terminal: Expose `selection` in context and add `keep_selection_on_copy` setting (#33491)

chico ferreira created

Closes #21262

Introduces a new setting `keep_selection_on_copy`, which controls
whether the current text selection is preserved after copying in the
terminal. The default behavior remains the same (`true`), but setting it
to `false` will clear the selection after the copy operation, matching
VSCode's behavior.

Additionally, the terminal context now exposes a `selection` flag
whenever text is selected.

This allows users to match VSCode and other terminal's smart copy
behavior.

Release Notes:

- Expose `selection` to terminal context when there is text selected in
the terminal
- Add `keep_selection_on_copy` terminal setting. Can be set to false to
clear the text selection when copying text.

**VSCode Behavior Example:**

**settings.json:**
```json
  "terminal": {
    "keep_selection_on_copy": false
  },
```
**keymap.json:**
```json
  {
    "context": "Terminal && selection",
    "bindings": {
      "ctrl-c": "terminal::Copy"
    }
  }
```

Change summary

assets/settings/default.json              |  2 ++
crates/terminal/src/terminal.rs           |  8 +++++++-
crates/terminal/src/terminal_settings.rs  |  5 +++++
crates/terminal_view/src/terminal_view.rs |  5 +++++
docs/src/configuring-zed.md               | 21 +++++++++++++++++++++
5 files changed, 40 insertions(+), 1 deletion(-)

Detailed changes

assets/settings/default.json 🔗

@@ -1292,6 +1292,8 @@
     // Whether or not selecting text in the terminal will automatically
     // copy to the system clipboard.
     "copy_on_select": false,
+    // Whether to keep the text selection after copying it to the clipboard
+    "keep_selection_on_copy": false,
     // Whether to show the terminal button in the status bar
     "button": true,
     // Any key-value pairs added to this list will be added to the terminal's

crates/terminal/src/terminal.rs 🔗

@@ -898,7 +898,13 @@ impl Terminal {
 
             InternalEvent::Copy => {
                 if let Some(txt) = term.selection_to_string() {
-                    cx.write_to_clipboard(ClipboardItem::new_string(txt))
+                    cx.write_to_clipboard(ClipboardItem::new_string(txt));
+
+                    let settings = TerminalSettings::get_global(cx);
+
+                    if !settings.keep_selection_on_copy {
+                        self.events.push_back(InternalEvent::SetSelection(None));
+                    }
                 }
             }
             InternalEvent::ScrollToAlacPoint(point) => {

crates/terminal/src/terminal_settings.rs 🔗

@@ -40,6 +40,7 @@ pub struct TerminalSettings {
     pub alternate_scroll: AlternateScroll,
     pub option_as_meta: bool,
     pub copy_on_select: bool,
+    pub keep_selection_on_copy: bool,
     pub button: bool,
     pub dock: TerminalDockPosition,
     pub default_width: Pixels,
@@ -193,6 +194,10 @@ pub struct TerminalSettingsContent {
     ///
     /// Default: false
     pub copy_on_select: Option<bool>,
+    /// Whether to keep the text selection after copying it to the clipboard.
+    ///
+    /// Default: false
+    pub keep_selection_on_copy: Option<bool>,
     /// Whether to show the terminal button in the status bar.
     ///
     /// Default: true

crates/terminal_view/src/terminal_view.rs 🔗

@@ -823,6 +823,11 @@ impl TerminalView {
             };
             dispatch_context.set("mouse_format", format);
         };
+
+        if self.terminal.read(cx).last_content.selection.is_some() {
+            dispatch_context.add("selection");
+        }
+
         dispatch_context
     }
 

docs/src/configuring-zed.md 🔗

@@ -2564,6 +2564,7 @@ List of `integer` column numbers
     "alternate_scroll": "off",
     "blinking": "terminal_controlled",
     "copy_on_select": false,
+    "keep_selection_on_copy": false,
     "dock": "bottom",
     "default_width": 640,
     "default_height": 320,
@@ -2688,6 +2689,26 @@ List of `integer` column numbers
 }
 ```
 
+### Terminal: Keep Selection On Copy
+
+- Description: Whether or not to keep the selection in the terminal after copying text.
+- Setting: `keep_selection_on_copy`
+- Default: `false`
+
+**Options**
+
+`boolean` values
+
+**Example**
+
+```json
+{
+  "terminal": {
+    "keep_selection_on_copy": true
+  }
+}
+```
+
 ### Terminal: Env
 
 - Description: Any key-value pairs added to this object will be added to the terminal's environment. Keys must be unique, use `:` to separate multiple values in a single variable