From 3fb1023667e1ce4affce4a9177fe11800d838115 Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Mon, 2 Jun 2025 16:37:36 +0530 Subject: [PATCH] editor: Fix columnar selection incorrectly uses cursor to start selection instead of mouse position (#31888) Closes #13905 This PR fixes columnar selection to originate from mouse position instead of current cursor position. Now columnar selection behaves as same as Sublime Text. 1. Columnar selection from click-and-drag on text (New): https://github.com/user-attachments/assets/f2e721f4-109f-4d81-a25b-8534065bfb37 2. Columnar selection from click-and-drag on empty space (New): https://github.com/user-attachments/assets/c2bb02e9-c006-4193-8d76-097233a47a3c 3. Multi cursors at end of line when no interecting text found (New): https://github.com/user-attachments/assets/e47d5ab3-0b5f-4e55-81b3-dfe450f149b5 4. Converting normal selection to columnar selection (Existing): https://github.com/user-attachments/assets/e5715679-ebae-4f5a-ad17-d29864e14e1e Release Notes: - Fixed the issue where the columnar selection (`opt+shift`) incorrectly used the cursor to start the selection instead of the mouse position. --- crates/editor/src/editor.rs | 27 ++++++++++++++++++++++++--- crates/editor/src/element.rs | 2 +- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 594586f1152e7ab4c51665fbb0e75102ce6258e9..463e3c5d54023b41ca942fe9c56b36d3e891b151 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -932,6 +932,7 @@ pub struct Editor { /// typing enters text into each of them, even the ones that aren't focused. pub(crate) show_cursor_when_unfocused: bool, columnar_selection_tail: Option, + columnar_display_point: Option, add_selections_state: Option, select_next_state: Option, select_prev_state: Option, @@ -1797,6 +1798,7 @@ impl Editor { selections, scroll_manager: ScrollManager::new(cx), columnar_selection_tail: None, + columnar_display_point: None, add_selections_state: None, select_next_state: None, select_prev_state: None, @@ -3319,12 +3321,18 @@ impl Editor { SelectMode::Character, ); }); + if position.column() != goal_column { + self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column)); + } else { + self.columnar_display_point = None; + } } let tail = self.selections.newest::(cx).tail(); self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail)); if !reset { + self.columnar_display_point = None; self.select_columns( tail.to_display_point(&display_map), position, @@ -3347,7 +3355,9 @@ impl Editor { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); if let Some(tail) = self.columnar_selection_tail.as_ref() { - let tail = tail.to_display_point(&display_map); + let tail = self + .columnar_display_point + .unwrap_or_else(|| tail.to_display_point(&display_map)); self.select_columns(tail, position, goal_column, &display_map, window, cx); } else if let Some(mut pending) = self.selections.pending_anchor() { let buffer = self.buffer.read(cx).snapshot(cx); @@ -3463,7 +3473,7 @@ impl Editor { let selection_ranges = (start_row.0..=end_row.0) .map(DisplayRow) .filter_map(|row| { - if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) { + if !display_map.is_block_line(row) { let start = display_map .clip_point(DisplayPoint::new(row, start_column), Bias::Left) .to_point(display_map); @@ -3481,8 +3491,19 @@ impl Editor { }) .collect::>(); + let mut non_empty_ranges = selection_ranges + .iter() + .filter(|selection_range| selection_range.start != selection_range.end) + .peekable(); + + let ranges = if non_empty_ranges.peek().is_some() { + non_empty_ranges.cloned().collect() + } else { + selection_ranges + }; + self.change_selections(None, window, cx, |s| { - s.select_ranges(selection_ranges); + s.select_ranges(ranges); }); cx.notify(); } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index b6996b9a91fbbf4afab32aebbb0a02c74cd26fa4..53f72ac929a7467d579ac175ed8e37889396e138 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -682,7 +682,7 @@ impl EditorElement { editor.select( SelectPhase::BeginColumnar { position, - reset: false, + reset: true, goal_column: point_for_position.exact_unclipped.column(), }, window,