Only clear selections when right click was performed outside of selection (#13701)

Stanislav Alekseev created

Release Notes:

- Fixed selections being cleared when right-click was performed outside
of a selection
([#4267](https://github.com/zed-industries/zed/pull/13701)).

<img width="1136" alt="Screenshot 2024-07-01 at 16 53 58"
src="https://github.com/zed-industries/zed/assets/43210583/082bfb0a-c679-4e87-a4e8-7dd751d8f4a2">

Change summary

crates/editor/src/mouse_context_menu.rs | 39 +++++++++++++++++++++-----
1 file changed, 31 insertions(+), 8 deletions(-)

Detailed changes

crates/editor/src/mouse_context_menu.rs 🔗

@@ -1,7 +1,10 @@
+use std::ops::Range;
+
 use crate::{
-    Copy, CopyPermalinkToLine, Cut, DisplayPoint, Editor, EditorMode, FindAllReferences,
-    GoToDefinition, GoToImplementation, GoToTypeDefinition, Paste, Rename, RevealInFinder,
-    SelectMode, ToggleCodeActions,
+    selections_collection::SelectionsCollection, Copy, CopyPermalinkToLine, Cut, DisplayPoint,
+    DisplaySnapshot, Editor, EditorMode, FindAllReferences, GoToDefinition, GoToImplementation,
+    GoToTypeDefinition, Paste, Rename, RevealInFinder, SelectMode, ToDisplayPoint,
+    ToggleCodeActions,
 };
 use gpui::{DismissEvent, Pixels, Point, Subscription, View, ViewContext};
 use workspace::OpenInTerminal;
@@ -37,6 +40,23 @@ impl MouseContextMenu {
     }
 }
 
+fn display_ranges<'a>(
+    display_map: &'a DisplaySnapshot,
+    selections: &'a SelectionsCollection,
+) -> impl Iterator<Item = Range<DisplayPoint>> + 'a {
+    let pending = selections
+        .pending
+        .as_ref()
+        .map(|pending| &pending.selection);
+    selections.disjoint.iter().chain(pending).map(move |s| {
+        if s.reversed {
+            s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
+        } else {
+            s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map)
+        }
+    })
+}
+
 pub fn deploy_context_menu(
     editor: &mut Editor,
     position: Point<Pixels>,
@@ -65,11 +85,14 @@ pub fn deploy_context_menu(
             return;
         }
 
-        // Move the cursor to the clicked location so that dispatched actions make sense
-        editor.change_selections(None, cx, |s| {
-            s.clear_disjoint();
-            s.set_pending_display_range(point..point, SelectMode::Character);
-        });
+        let display_map = editor.selections.display_map(cx);
+        if !display_ranges(&display_map, &editor.selections).any(|r| r.contains(&point)) {
+            // Move the cursor to the clicked location so that dispatched actions make sense
+            editor.change_selections(None, cx, |s| {
+                s.clear_disjoint();
+                s.set_pending_display_range(point..point, SelectMode::Character);
+            });
+        }
 
         let focus = cx.focused();
         ui::ContextMenu::build(cx, |menu, _cx| {