From b453b6e1c0f6a236612cd84dd96ba23236110248 Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Tue, 17 Mar 2026 18:05:50 +0530 Subject: [PATCH] editor: Fix selection direction reversal in `SelectLargeSyntaxNode` with multiple cursors (#51752) Closes https://github.com/zed-industries/zed/issues/47737 Regressed by https://github.com/zed-industries/zed/pull/27295 Release Notes: - Fixed an issue where using the `SelectLargeSyntaxNode` action with multiple cursors could reverse the selection direction for the last cursor. --- crates/editor/src/editor.rs | 12 ++++++------ crates/editor/src/editor_tests.rs | 31 ++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 386e51340fd7288cbafbc831bc64751393f5cf37..bff3275ae4d550a519aa0eb7c935cfb00201dd81 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -16509,12 +16509,12 @@ impl Editor { .zip(new_selections.last().cloned()) .expect("old_selections isn't empty"); - // revert selection - let is_selection_reversed = { - let should_newest_selection_be_reversed = last_old.start != last_new.start; - new_selections.last_mut().expect("checked above").reversed = - should_newest_selection_be_reversed; - should_newest_selection_be_reversed + let is_selection_reversed = if new_selections.len() == 1 { + let should_be_reversed = last_old.start != last_new.start; + new_selections.last_mut().expect("checked above").reversed = should_be_reversed; + should_be_reversed + } else { + last_new.reversed }; if selected_larger_node { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 04d3babf20f5c866dd3f3447f0909f11becf724d..f752bb9d21caf6c488c37f3f65ceb7db88471875 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -10057,7 +10057,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut TestAppContext) { use mod1::mod2::{mod3, «mod4ˇ»}; fn fn_1«ˇ(param1: bool, param2: &str)» { - let var1 = "«ˇtext»"; + let var1 = "«textˇ»"; } "#}, cx, @@ -10129,7 +10129,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut TestAppContext) { use mod1::mod2::{mod3, «mod4ˇ»}; fn fn_1«ˇ(param1: bool, param2: &str)» { - let var1 = "«ˇtext»"; + let var1 = "«textˇ»"; } "#}, cx, @@ -10198,7 +10198,32 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut TestAppContext) { use mod1::mod2::«{mod3, mod4}ˇ»; fn fn_1«ˇ(param1: bool, param2: &str)» { - let var1 = "«ˇtext»"; + let var1 = "«textˇ»"; + } + "#}, + cx, + ); + }); + + // Ensure multiple cursors have consistent direction after expanding + editor.update_in(cx, |editor, window, cx| { + editor.unfold_all(&UnfoldAll, window, cx); + editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { + s.select_display_ranges([ + DisplayPoint::new(DisplayRow(0), 25)..DisplayPoint::new(DisplayRow(0), 25), + DisplayPoint::new(DisplayRow(3), 18)..DisplayPoint::new(DisplayRow(3), 18), + ]); + }); + editor.select_larger_syntax_node(&SelectLargerSyntaxNode, window, cx); + }); + editor.update(cx, |editor, cx| { + assert_text_with_selections( + editor, + indoc! {r#" + use mod1::mod2::{mod3, «mod4ˇ»}; + + fn fn_1(param1: bool, param2: &str) { + let var1 = "«textˇ»"; } "#}, cx,