editor: Fix select when click on existing selection (#32365)

Follow-up for https://github.com/zed-industries/zed/pull/30671

Now, when clicking on an existing selection, the cursor will change on
`mouse_up` when `drag_and_drop_selection` is `true`. When
`drag_and_drop_selection` is `false`, it will change on `mouse_down`
(previous default).

Release Notes:

- N/A
This commit is contained in:
Smit Barmase 2025-06-09 11:58:06 +05:30 committed by GitHub
parent ebea734515
commit c57a6263aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 76 additions and 49 deletions

View file

@ -910,7 +910,10 @@ enum SelectionDragState {
/// State when no drag related activity is detected. /// State when no drag related activity is detected.
None, None,
/// State when the mouse is down on a selection that is about to be dragged. /// State when the mouse is down on a selection that is about to be dragged.
ReadyToDrag { selection: Selection<Anchor> }, ReadyToDrag {
selection: Selection<Anchor>,
click_position: gpui::Point<Pixels>,
},
/// State when the mouse is dragging the selection in the editor. /// State when the mouse is dragging the selection in the editor.
Dragging { Dragging {
selection: Selection<Anchor>, selection: Selection<Anchor>,
@ -10601,26 +10604,19 @@ impl Editor {
}); });
} }
pub fn drop_selection( pub fn move_selection_on_drop(
&mut self, &mut self,
point_for_position: Option<PointForPosition>, selection: &Selection<Anchor>,
target: DisplayPoint,
is_cut: bool, is_cut: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> bool { ) {
if let Some(point_for_position) = point_for_position {
match self.selection_drag_state {
SelectionDragState::Dragging { ref selection, .. } => {
let snapshot = self.snapshot(window, cx);
let selection_display =
selection.map(|anchor| anchor.to_display_point(&snapshot));
if !point_for_position.intersects_selection(&selection_display) {
let point = point_for_position.previous_valid;
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot; let buffer = &display_map.buffer_snapshot;
let mut edits = Vec::new(); let mut edits = Vec::new();
let insert_point = display_map let insert_point = display_map
.clip_point(point, Bias::Left) .clip_point(target, Bias::Left)
.to_point(&display_map); .to_point(&display_map);
let text = buffer let text = buffer
.text_for_range(selection.start..selection.end) .text_for_range(selection.start..selection.end)
@ -10640,15 +10636,10 @@ impl Editor {
s.select_anchor_ranges([last_edit_start..last_edit_end]); s.select_anchor_ranges([last_edit_start..last_edit_end]);
}); });
}); });
}
pub fn clear_selection_drag_state(&mut self) {
self.selection_drag_state = SelectionDragState::None; self.selection_drag_state = SelectionDragState::None;
return true;
}
}
_ => {}
}
}
self.selection_drag_state = SelectionDragState::None;
false
} }
pub fn duplicate( pub fn duplicate(

View file

@ -641,6 +641,7 @@ impl EditorElement {
if point_for_position.intersects_selection(&selection) { if point_for_position.intersects_selection(&selection) {
editor.selection_drag_state = SelectionDragState::ReadyToDrag { editor.selection_drag_state = SelectionDragState::ReadyToDrag {
selection: newest_anchor.clone(), selection: newest_anchor.clone(),
click_position: event.position,
}; };
cx.stop_propagation(); cx.stop_propagation();
return; return;
@ -832,10 +833,45 @@ impl EditorElement {
let pending_nonempty_selections = editor.has_pending_nonempty_selection(); let pending_nonempty_selections = editor.has_pending_nonempty_selection();
let point_for_position = position_map.point_for_position(event.position); let point_for_position = position_map.point_for_position(event.position);
let is_cut = !event.modifiers.control; match editor.selection_drag_state {
if editor.drop_selection(Some(point_for_position), is_cut, window, cx) { SelectionDragState::ReadyToDrag {
selection: _,
ref click_position,
} => {
if event.position == *click_position {
editor.select(
SelectPhase::Begin {
position: point_for_position.previous_valid,
add: false,
click_count: 1, // ready to drag state only occurs on click count 1
},
window,
cx,
);
editor.selection_drag_state = SelectionDragState::None;
cx.stop_propagation();
return; return;
} }
}
SelectionDragState::Dragging { ref selection, .. } => {
let snapshot = editor.snapshot(window, cx);
let selection_display = selection.map(|anchor| anchor.to_display_point(&snapshot));
if !point_for_position.intersects_selection(&selection_display) {
let is_cut = !event.modifiers.control;
editor.move_selection_on_drop(
&selection.clone(),
point_for_position.previous_valid,
is_cut,
window,
cx,
);
editor.selection_drag_state = SelectionDragState::None;
cx.stop_propagation();
return;
}
}
_ => {}
}
if end_selection { if end_selection {
editor.select(SelectPhase::End, window, cx); editor.select(SelectPhase::End, window, cx);
@ -951,7 +987,7 @@ impl EditorElement {
drop_cursor.start = drop_anchor; drop_cursor.start = drop_anchor;
drop_cursor.end = drop_anchor; drop_cursor.end = drop_anchor;
} }
SelectionDragState::ReadyToDrag { ref selection } => { SelectionDragState::ReadyToDrag { ref selection, .. } => {
let drop_cursor = Selection { let drop_cursor = Selection {
id: post_inc(&mut editor.selections.next_selection_id), id: post_inc(&mut editor.selections.next_selection_id),
start: drop_anchor, start: drop_anchor,

View file

@ -915,8 +915,8 @@ impl Vim {
if mode == Mode::Normal || mode != last_mode { if mode == Mode::Normal || mode != last_mode {
self.current_tx.take(); self.current_tx.take();
self.current_anchor.take(); self.current_anchor.take();
self.update_editor(window, cx, |_, editor, window, cx| { self.update_editor(window, cx, |_, editor, _, _| {
editor.drop_selection(None, false, window, cx); editor.clear_selection_drag_state();
}); });
} }
Vim::take_forced_motion(cx); Vim::take_forced_motion(cx);