diff --git a/.github/workflows/upload_asset.sh b/.github/workflows/upload_asset.sh index 9e1f40e5684..15c2c5001e6 100755 --- a/.github/workflows/upload_asset.sh +++ b/.github/workflows/upload_asset.sh @@ -6,7 +6,7 @@ if [ $# -lt 2 ]; then exit 1 fi -repo="alacritty/alacritty" +repo="sigurdo/alacritty-smart-copy" file_path=$1 bearer=$2 diff --git a/README.md b/README.md index d9bfde9b19d..a6cc1f10c04 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,40 @@ src="https://raw.githubusercontent.com/alacritty/alacritty/master/extra/promo/alacritty-readme.png">

+## About this fork + +This fork of Alacritty lets you copy and paste with `ctrl+c` and `ctrl+v`, like in most modern Windows and Linux software. If no text is selected, `ctrl+c` sends `SIGINT` like usual. The selection is cleared when you copy with `ctrl+c`. In this way, pressing `ctrl+c` twice will always send minimum one `SIGINT`. Copying without clearing the selection can still be achieved with `ctrl+shift+c`. + +Precompiled binaries are available from the [GitHub releases page](https://github.com/sigurdo/alacritty-smart-copy/releases). + +On the technical side, a `CopyDynamic` action is added. It copies the selected text and clears the selection. When no text is selected, the keystroke is passed through, thus causing a `SIGINT`. + +"Smart copy" was first propsed and rejected already [back in 2018](https://github.com/alacritty/alacritty/issues/1919) for reasons I do not agree with. In 2020, dtheodor provided a [fantastic explanation](https://github.com/alacritty/alacritty/issues/1919#issuecomment-588188924) of why smart copy is such a brilliant solution. A [pull request implementing this feature](https://github.com/alacritty/alacritty/pull/3873) was proposed by ambiso later in 2020, which was also rejected. [Their fork](https://github.com/ambiso/alacritty/tree/master) is sadly outdated now. Therefore, I created this updated fork with the same approach. I plan to keep the fork up to date for as long as I use Alacritty as my daily driver terminal emulator. + +The following key bindings are provided by default for Windows, Linux and BSD: + +```toml +[[keyboard.bindings]] +key = "V" +mods = "Control" +mode = "~Vi" +action = "Paste" + +[[keyboard.bindings]] +key = "C" +mods = "Control" +mode = "~Vi" +action = "CopyDynamic" +``` + +and in YAML (for Alacritty v0.12 or older), + +```yaml +key_bindings: + - { key: V, mods: Control, mode: ~Vi, action: Paste } + - { key: C, mods: Control, mode: ~Vi, action: CopyDynamic } +``` + ## About Alacritty is a modern terminal emulator that comes with sensible defaults, but diff --git a/alacritty/src/config/bindings.rs b/alacritty/src/config/bindings.rs index 931b0583ba2..aba1ddfd5fa 100644 --- a/alacritty/src/config/bindings.rs +++ b/alacritty/src/config/bindings.rs @@ -121,6 +121,9 @@ pub enum Action { /// Store current selection into clipboard. Copy, + /// Copy selection and clear it, or forward the keybinding to the program if there is no selection. + CopyDynamic, + /// Store current selection into selection buffer. CopySelection, @@ -536,11 +539,13 @@ fn common_keybindings() -> Vec { KeyBinding; "v", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::VI; Action::Paste; "v", ModifiersState::CONTROL | ModifiersState::SHIFT, +BindingMode::VI, +BindingMode::SEARCH; Action::Paste; + "v", ModifiersState::CONTROL, ~BindingMode::VI; Action::Paste; "f", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Action::SearchForward; "b", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Action::SearchBackward; Insert, ModifiersState::SHIFT, ~BindingMode::VI; Action::PasteSelection; "c", ModifiersState::CONTROL | ModifiersState::SHIFT; Action::Copy; "c", ModifiersState::CONTROL | ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; + "c", ModifiersState::CONTROL, ~BindingMode::VI; Action::CopyDynamic; "0", ModifiersState::CONTROL; Action::ResetFontSize; "=", ModifiersState::CONTROL; Action::IncreaseFontSize; "+", ModifiersState::CONTROL; Action::IncreaseFontSize; diff --git a/alacritty/src/input/keyboard.rs b/alacritty/src/input/keyboard.rs index af9bfbb2507..d1ade96e2d2 100644 --- a/alacritty/src/input/keyboard.rs +++ b/alacritty/src/input/keyboard.rs @@ -196,6 +196,11 @@ impl> Processor { // Pass through the key if any of the bindings has the `ReceiveChar` action. *suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar; + // Pass through the key if any of the bindings has the `CopyDynamic` action and the selection is empty. + if binding.action == Action::CopyDynamic && self.ctx.selection_is_empty() { + suppress_chars = Some(false); + } + // Binding was triggered; run the action. binding.action.clone().execute(&mut self.ctx); } diff --git a/alacritty/src/input/mod.rs b/alacritty/src/input/mod.rs index 3f85512f2f7..f5928e8e001 100644 --- a/alacritty/src/input/mod.rs +++ b/alacritty/src/input/mod.rs @@ -304,6 +304,12 @@ impl Execute for Action { Action::Copy => ctx.copy_selection(ClipboardType::Clipboard), #[cfg(not(any(target_os = "macos", windows)))] Action::CopySelection => ctx.copy_selection(ClipboardType::Selection), + Action::CopyDynamic => { + if !ctx.selection_is_empty() { + ctx.copy_selection(ClipboardType::Clipboard); + ctx.clear_selection(); + } + }, Action::ClearSelection => ctx.clear_selection(), Action::Paste => { let text = ctx.clipboard_mut().load(ClipboardType::Clipboard);