Open excerpt on double click in multibuffer by default. (#9196)

Kirill Bulatov created

Closes https://github.com/zed-industries/zed/issues/5275

Double click with `alt` modifier pressed will do the regular word
selection.

Adds a setting to disable this behavior and instead select a word, as in
the regular buffer.

```
// What to do when multibuffer is double clicked in some of its excerpts
// (parts of singleton buffers).
// May take 2 values:
//  1. Behave as a regular buffer and select the whole word.
//         "double_click_in_multibuffer": "select"
//  2. Open the excerpt clicked as a new buffer in the new tab (default).
//         "double_click_in_multibuffer": "open",
// For the case of "open", regular selection behavior can be achieved by holding `alt` when double clicking.
"double_click_in_multibuffer": "open",
```


Release Notes:

- Made multibuffer to open excerpts in new tabs on double click by
default (changing settings or keeping alt restores the word selection
behavior). ([5275](https://github.com/zed-industries/zed/issues/5275))

Change summary

assets/settings/default.json         |  9 +++++++++
crates/editor/src/editor_settings.rs | 20 ++++++++++++++++++++
crates/editor/src/element.rs         | 23 +++++++++++++++++++++--
3 files changed, 50 insertions(+), 2 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -140,6 +140,15 @@
     // Whether to show diagnostic indicators in the scrollbar.
     "diagnostics": true
   },
+  // What to do when multibuffer is double clicked in some of its excerpts
+  // (parts of singleton buffers).
+  // May take 2 values:
+  //  1. Behave as a regular buffer and select the whole word.
+  //         "double_click_in_multibuffer": "select"
+  //  2. Open the excerpt clicked as a new buffer in the new tab (default).
+  //         "double_click_in_multibuffer": "open",
+  // For the case of "open", regular selection behavior can be achieved by holding `alt` when double clicking.
+  "double_click_in_multibuffer": "open",
   "gutter": {
     // Whether to show line numbers in the gutter.
     "line_numbers": true,

crates/editor/src/editor_settings.rs 🔗

@@ -17,6 +17,8 @@ pub struct EditorSettings {
     pub relative_line_numbers: bool,
     pub seed_search_query_from_cursor: SeedQuerySetting,
     pub redact_private_values: bool,
+    #[serde(default)]
+    pub double_click_in_multibuffer: DoubleClickInMultibuffer,
 }
 
 /// When to populate a new search's query based on the text under the cursor.
@@ -31,6 +33,18 @@ pub enum SeedQuerySetting {
     Never,
 }
 
+/// What to do when multibuffer is double clicked in some of its excerpts (parts of singleton buffers).
+#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum DoubleClickInMultibuffer {
+    /// Behave as a regular buffer and select the whole word.
+    Select,
+    #[default]
+    /// Open the excerpt clicked as a new buffer in the new tab, if no `alt` modifier was pressed during double click.
+    /// Otherwise, behave as a regular buffer and select the whole word.
+    Open,
+}
+
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
 pub struct Toolbar {
     pub breadcrumbs: bool,
@@ -127,6 +141,12 @@ pub struct EditorSettingsContent {
     ///
     /// Default: false
     pub redact_private_values: Option<bool>,
+
+    /// What to do when multibuffer is double clicked in some of its excerpts
+    /// (parts of singleton buffers).
+    ///
+    /// Default: open
+    pub double_click_in_multibuffer: Option<DoubleClickInMultibuffer>,
 }
 
 // Toolbar related settings

crates/editor/src/element.rs 🔗

@@ -3,7 +3,7 @@ use crate::{
         BlockContext, BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint,
         TransformBlock,
     },
-    editor_settings::ShowScrollbar,
+    editor_settings::{DoubleClickInMultibuffer, ShowScrollbar},
     git::{diff_hunk_to_display, DisplayDiffHunk},
     hover_popover::{
         self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
@@ -392,7 +392,7 @@ impl EditorElement {
         }
 
         let mut click_count = event.click_count;
-        let modifiers = event.modifiers;
+        let mut modifiers = event.modifiers;
 
         if gutter_hitbox.is_hovered(cx) {
             click_count = 3; // Simulate triple-click when clicking the gutter to select lines
@@ -400,6 +400,25 @@ impl EditorElement {
             return;
         }
 
+        if click_count == 2 {
+            match EditorSettings::get_global(cx).double_click_in_multibuffer {
+                DoubleClickInMultibuffer::Select => {
+                    // do nothing special on double click, all selection logic is below
+                }
+                DoubleClickInMultibuffer::Open => {
+                    if modifiers.alt {
+                        // if double click is made with alt, pretend it's a regular double click without opening and alt,
+                        // and run the selection logic.
+                        modifiers.alt = false;
+                    } else {
+                        // if double click is made without alt, open the corresponding excerp
+                        editor.open_excerpts(&OpenExcerpts, cx);
+                        return;
+                    }
+                }
+            }
+        }
+
         let point_for_position =
             position_map.point_for_position(text_hitbox.bounds, event.position);
         let position = point_for_position.previous_valid;