From 0da97b0c8bcbdfec92205cb66cede3a77257de64 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sat, 7 Jun 2025 16:21:13 -0400 Subject: [PATCH] editor: Respect `multi_cursor_modifier` setting when making columnar selections using mouse (#32273) Closes https://github.com/zed-industries/zed/issues/31181 Release Notes: - Added the `multi_cursor_modifier` setting to be respected when making columnar selections using the mouse drag. --------- Co-authored-by: Smit Barmase --- assets/settings/default.json | 9 ++++-- crates/editor/src/editor.rs | 41 +++++++++++++++++++------- crates/editor/src/editor_settings.rs | 2 +- crates/editor/src/element.rs | 43 ++++++++++++---------------- crates/editor/src/hover_links.rs | 8 ++---- docs/src/configuring-zed.md | 24 ++++++++++++++++ 6 files changed, 82 insertions(+), 45 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 2759262b51..0fff7110a8 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -101,9 +101,12 @@ // The second option is decimal. "unit": "binary" }, - // The key to use for adding multiple cursors - // Currently "alt" or "cmd_or_ctrl" (also aliased as - // "cmd" and "ctrl") are supported. + // Determines the modifier to be used to add multiple cursors with the mouse. The open hover link mouse gestures will adapt such that it do not conflict with the multicursor modifier. + // + // 1. Maps to `Alt` on Linux and Windows and to `Option` on MacOS: + // "alt" + // 2. Maps `Control` on Linux and Windows and to `Command` on MacOS: + // "cmd_or_ctrl" (alias: "cmd", "ctrl") "multi_cursor_modifier": "alt", // Whether to enable vim modes and key bindings. "vim_mode": false, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 51af7656d2..e211496343 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -213,11 +213,14 @@ use workspace::{ searchable::SearchEvent, }; -use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState}; use crate::{ code_context_menus::CompletionsMenuSource, hover_links::{find_url, find_url_from_range}, }; +use crate::{ + editor_settings::MultiCursorModifier, + signature_help::{SignatureHelpHiddenBy, SignatureHelpState}, +}; pub const FILE_HEADER_HEIGHT: u32 = 2; pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1; @@ -253,14 +256,6 @@ pub type RenderDiffHunkControlsFn = Arc< ) -> AnyElement, >; -const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers { - alt: true, - shift: true, - control: false, - platform: false, - function: false, -}; - struct InlineValueCache { enabled: bool, inlays: Vec, @@ -7091,6 +7086,29 @@ impl Editor { ) } + fn multi_cursor_modifier( + cursor_event: bool, + modifiers: &Modifiers, + cx: &mut Context, + ) -> bool { + let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier; + if cursor_event { + match multi_cursor_setting { + MultiCursorModifier::Alt => modifiers.alt, + MultiCursorModifier::CmdOrCtrl => modifiers.secondary(), + } + } else { + match multi_cursor_setting { + MultiCursorModifier::Alt => modifiers.secondary(), + MultiCursorModifier::CmdOrCtrl => modifiers.alt, + } + } + } + + fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool { + modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2 + } + fn update_selection_mode( &mut self, modifiers: &Modifiers, @@ -7098,7 +7116,10 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() { + let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx); + if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers) + || self.selections.pending.is_none() + { return; } diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 57459dfc94..0d14064ef8 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -422,7 +422,7 @@ pub struct EditorSettingsContent { /// Default: always pub seed_search_query_from_cursor: Option, pub use_smartcase_search: Option, - /// The key to use for adding multiple cursors + /// Determines the modifier to be used to add multiple cursors with the mouse. The open hover link mouse gestures will adapt such that it do not conflict with the multicursor modifier. /// /// Default: alt pub multi_cursor_modifier: Option, diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index fadabaf035..d596646517 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1,15 +1,15 @@ use crate::{ - ActiveDiagnostic, BlockId, COLUMNAR_SELECTION_MODIFIERS, CURSORS_VISIBLE_FOR, - ChunkRendererContext, ChunkReplacement, CodeActionSource, ConflictsOurs, ConflictsOursMarker, - ConflictsOuter, ConflictsTheirs, ConflictsTheirsMarker, ContextMenuPlacement, CursorShape, - CustomBlockId, DisplayDiffHunk, DisplayPoint, DisplayRow, DocumentHighlightRead, - DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode, EditorSettings, EditorSnapshot, - EditorStyle, FILE_HEADER_HEIGHT, FocusedBlock, GutterDimensions, HalfPageDown, HalfPageUp, - HandleInput, HoveredCursor, InlayHintRefreshReason, InlineCompletion, JumpData, LineDown, - LineHighlight, LineUp, MAX_LINE_LEN, MIN_LINE_NUMBER_DIGITS, MINIMAP_FONT_SIZE, - MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, OpenExcerpts, PageDown, PageUp, PhantomBreakpointIndicator, - Point, RowExt, RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap, - StickyHeaderExcerpt, ToPoint, ToggleFold, + ActiveDiagnostic, BlockId, CURSORS_VISIBLE_FOR, ChunkRendererContext, ChunkReplacement, + CodeActionSource, ConflictsOurs, ConflictsOursMarker, ConflictsOuter, ConflictsTheirs, + ConflictsTheirsMarker, ContextMenuPlacement, CursorShape, CustomBlockId, DisplayDiffHunk, + DisplayPoint, DisplayRow, DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, + Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, FILE_HEADER_HEIGHT, + FocusedBlock, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, + InlayHintRefreshReason, InlineCompletion, JumpData, LineDown, LineHighlight, LineUp, + MAX_LINE_LEN, MIN_LINE_NUMBER_DIGITS, MINIMAP_FONT_SIZE, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, + OpenExcerpts, PageDown, PageUp, PhantomBreakpointIndicator, Point, RowExt, RowRangeExt, + SelectPhase, SelectedTextHighlight, Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, + ToggleFold, code_context_menus::{CodeActionsMenu, MENU_ASIDE_MAX_WIDTH, MENU_ASIDE_MIN_WIDTH, MENU_GAP}, display_map::{ Block, BlockContext, BlockStyle, DisplaySnapshot, EditorMargins, FoldId, HighlightedChunk, @@ -17,8 +17,7 @@ use crate::{ }, editor_settings::{ CurrentLineHighlight, DoubleClickInMultibuffer, MinimapThumb, MinimapThumbBorder, - MultiCursorModifier, ScrollBeyondLastLine, ScrollbarAxes, ScrollbarDiagnostics, - ShowMinimap, ShowScrollbar, + ScrollBeyondLastLine, ScrollbarAxes, ScrollbarDiagnostics, ShowMinimap, ShowScrollbar, }, git::blame::{BlameRenderer, GitBlame, GlobalBlameRenderer}, hover_popover::{ @@ -678,7 +677,10 @@ impl EditorElement { let point_for_position = position_map.point_for_position(event.position); let position = point_for_position.previous_valid; - if modifiers == COLUMNAR_SELECTION_MODIFIERS { + + let multi_cursor_modifier = Editor::multi_cursor_modifier(true, &modifiers, cx); + + if Editor::columnar_selection_modifiers(multi_cursor_modifier, &modifiers) { editor.select( SelectPhase::BeginColumnar { position, @@ -699,11 +701,6 @@ impl EditorElement { cx, ); } else { - let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier; - let multi_cursor_modifier = match multi_cursor_setting { - MultiCursorModifier::Alt => modifiers.alt, - MultiCursorModifier::CmdOrCtrl => modifiers.secondary(), - }; editor.select( SelectPhase::Begin { position, @@ -867,13 +864,9 @@ impl EditorElement { let text_hitbox = &position_map.text_hitbox; let pending_nonempty_selections = editor.has_pending_nonempty_selection(); - let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier; - let multi_cursor_modifier = match multi_cursor_setting { - MultiCursorModifier::Alt => event.modifiers().secondary(), - MultiCursorModifier::CmdOrCtrl => event.modifiers().alt, - }; + let hovered_link_modifier = Editor::multi_cursor_modifier(false, &event.modifiers(), cx); - if !pending_nonempty_selections && multi_cursor_modifier && text_hitbox.is_hovered(window) { + if !pending_nonempty_selections && hovered_link_modifier && text_hitbox.is_hovered(window) { let point = position_map.point_for_position(event.up.position); editor.handle_click_hovered_link(point, event.modifiers(), window, cx); diff --git a/crates/editor/src/hover_links.rs b/crates/editor/src/hover_links.rs index 927981e6e6..a716b2e031 100644 --- a/crates/editor/src/hover_links.rs +++ b/crates/editor/src/hover_links.rs @@ -1,7 +1,7 @@ use crate::{ Anchor, Editor, EditorSettings, EditorSnapshot, FindAllReferences, GoToDefinition, GoToTypeDefinition, GotoDefinitionKind, InlayId, Navigated, PointForPosition, SelectPhase, - editor_settings::{GoToDefinitionFallback, MultiCursorModifier}, + editor_settings::GoToDefinitionFallback, hover_popover::{self, InlayHover}, scroll::ScrollAmount, }; @@ -120,11 +120,7 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier; - let hovered_link_modifier = match multi_cursor_setting { - MultiCursorModifier::Alt => modifiers.secondary(), - MultiCursorModifier::CmdOrCtrl => modifiers.alt, - }; + let hovered_link_modifier = Editor::multi_cursor_modifier(false, &modifiers, cx); if !hovered_link_modifier || self.has_pending_selection() { self.hide_hovered_link(cx); return; diff --git a/docs/src/configuring-zed.md b/docs/src/configuring-zed.md index 3c7167f980..b31be7cf85 100644 --- a/docs/src/configuring-zed.md +++ b/docs/src/configuring-zed.md @@ -1924,6 +1924,30 @@ Example: `boolean` values +## Multi Cursor Modifier + +- Description: Determines the modifier to be used to add multiple cursors with the mouse. The open hover link mouse gestures will adapt such that it do not conflict with the multicursor modifier. +- Setting: `multi_cursor_modifier` +- Default: `alt` + +**Options** + +1. Maps to `Alt` on Linux and Windows and to `Option` on MacOS: + +```jsonc +{ + "multi_cursor_modifier": "alt", +} +``` + +2. Maps `Control` on Linux and Windows and to `Command` on MacOS: + +```jsonc +{ + "multi_cursor_modifier": "cmd_or_ctrl", // alias: "cmd", "ctrl" +} +``` + ## Hover Popover Enabled - Description: Whether or not to show the informational hover box when moving the mouse over symbols in the editor.