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:
parent
ebea734515
commit
c57a6263aa
3 changed files with 76 additions and 49 deletions
|
@ -910,7 +910,10 @@ enum SelectionDragState {
|
|||
/// State when no drag related activity is detected.
|
||||
None,
|
||||
/// 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.
|
||||
Dragging {
|
||||
selection: Selection<Anchor>,
|
||||
|
@ -10601,54 +10604,42 @@ impl Editor {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn drop_selection(
|
||||
pub fn move_selection_on_drop(
|
||||
&mut self,
|
||||
point_for_position: Option<PointForPosition>,
|
||||
selection: &Selection<Anchor>,
|
||||
target: DisplayPoint,
|
||||
is_cut: bool,
|
||||
window: &mut Window,
|
||||
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 buffer = &display_map.buffer_snapshot;
|
||||
let mut edits = Vec::new();
|
||||
let insert_point = display_map
|
||||
.clip_point(point, Bias::Left)
|
||||
.to_point(&display_map);
|
||||
let text = buffer
|
||||
.text_for_range(selection.start..selection.end)
|
||||
.collect::<String>();
|
||||
if is_cut {
|
||||
edits.push(((selection.start..selection.end), String::new()));
|
||||
}
|
||||
let insert_anchor = buffer.anchor_before(insert_point);
|
||||
edits.push(((insert_anchor..insert_anchor), text));
|
||||
let last_edit_start = insert_anchor.bias_left(buffer);
|
||||
let last_edit_end = insert_anchor.bias_right(buffer);
|
||||
self.transact(window, cx, |this, window, cx| {
|
||||
this.buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit(edits, None, cx);
|
||||
});
|
||||
this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
|
||||
s.select_anchor_ranges([last_edit_start..last_edit_end]);
|
||||
});
|
||||
});
|
||||
self.selection_drag_state = SelectionDragState::None;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
) {
|
||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let buffer = &display_map.buffer_snapshot;
|
||||
let mut edits = Vec::new();
|
||||
let insert_point = display_map
|
||||
.clip_point(target, Bias::Left)
|
||||
.to_point(&display_map);
|
||||
let text = buffer
|
||||
.text_for_range(selection.start..selection.end)
|
||||
.collect::<String>();
|
||||
if is_cut {
|
||||
edits.push(((selection.start..selection.end), String::new()));
|
||||
}
|
||||
let insert_anchor = buffer.anchor_before(insert_point);
|
||||
edits.push(((insert_anchor..insert_anchor), text));
|
||||
let last_edit_start = insert_anchor.bias_left(buffer);
|
||||
let last_edit_end = insert_anchor.bias_right(buffer);
|
||||
self.transact(window, cx, |this, window, cx| {
|
||||
this.buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit(edits, None, cx);
|
||||
});
|
||||
this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
|
||||
s.select_anchor_ranges([last_edit_start..last_edit_end]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn clear_selection_drag_state(&mut self) {
|
||||
self.selection_drag_state = SelectionDragState::None;
|
||||
false
|
||||
}
|
||||
|
||||
pub fn duplicate(
|
||||
|
|
|
@ -641,6 +641,7 @@ impl EditorElement {
|
|||
if point_for_position.intersects_selection(&selection) {
|
||||
editor.selection_drag_state = SelectionDragState::ReadyToDrag {
|
||||
selection: newest_anchor.clone(),
|
||||
click_position: event.position,
|
||||
};
|
||||
cx.stop_propagation();
|
||||
return;
|
||||
|
@ -832,9 +833,44 @@ impl EditorElement {
|
|||
let pending_nonempty_selections = editor.has_pending_nonempty_selection();
|
||||
let point_for_position = position_map.point_for_position(event.position);
|
||||
|
||||
let is_cut = !event.modifiers.control;
|
||||
if editor.drop_selection(Some(point_for_position), is_cut, window, cx) {
|
||||
return;
|
||||
match editor.selection_drag_state {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
@ -951,7 +987,7 @@ impl EditorElement {
|
|||
drop_cursor.start = drop_anchor;
|
||||
drop_cursor.end = drop_anchor;
|
||||
}
|
||||
SelectionDragState::ReadyToDrag { ref selection } => {
|
||||
SelectionDragState::ReadyToDrag { ref selection, .. } => {
|
||||
let drop_cursor = Selection {
|
||||
id: post_inc(&mut editor.selections.next_selection_id),
|
||||
start: drop_anchor,
|
||||
|
|
|
@ -915,8 +915,8 @@ impl Vim {
|
|||
if mode == Mode::Normal || mode != last_mode {
|
||||
self.current_tx.take();
|
||||
self.current_anchor.take();
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
editor.drop_selection(None, false, window, cx);
|
||||
self.update_editor(window, cx, |_, editor, _, _| {
|
||||
editor.clear_selection_drag_state();
|
||||
});
|
||||
}
|
||||
Vim::take_forced_motion(cx);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue