Skip to content

Commit

Permalink
Re-implement smart copy from alacritty#3873
Browse files Browse the repository at this point in the history
  • Loading branch information
sigurdo committed May 3, 2024
1 parent bb8ea18 commit d18995e
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/upload_asset.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ if [ $# -lt 2 ]; then
exit 1
fi

repo="alacritty/alacritty"
repo="sigurdo/alacritty-smart-copy"
file_path=$1
bearer=$2

Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,40 @@
src="extra/promo/alacritty-readme.png">
</p>

## 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
Expand Down
5 changes: 5 additions & 0 deletions alacritty/src/config/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,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,

Expand Down Expand Up @@ -535,11 +538,13 @@ fn common_keybindings() -> Vec<KeyBinding> {
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;
Expand Down
5 changes: 5 additions & 0 deletions alacritty/src/input/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> {
// 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);
}
Expand Down
6 changes: 6 additions & 0 deletions alacritty/src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,12 @@ impl<T: EventListener> Execute<T> 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);
Expand Down

0 comments on commit d18995e

Please sign in to comment.