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.
|
/// 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,54 +10604,42 @@ 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 {
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
match self.selection_drag_state {
|
let buffer = &display_map.buffer_snapshot;
|
||||||
SelectionDragState::Dragging { ref selection, .. } => {
|
let mut edits = Vec::new();
|
||||||
let snapshot = self.snapshot(window, cx);
|
let insert_point = display_map
|
||||||
let selection_display =
|
.clip_point(target, Bias::Left)
|
||||||
selection.map(|anchor| anchor.to_display_point(&snapshot));
|
.to_point(&display_map);
|
||||||
if !point_for_position.intersects_selection(&selection_display) {
|
let text = buffer
|
||||||
let point = point_for_position.previous_valid;
|
.text_for_range(selection.start..selection.end)
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
.collect::<String>();
|
||||||
let buffer = &display_map.buffer_snapshot;
|
if is_cut {
|
||||||
let mut edits = Vec::new();
|
edits.push(((selection.start..selection.end), String::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 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;
|
self.selection_drag_state = SelectionDragState::None;
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn duplicate(
|
pub fn duplicate(
|
||||||
|
|
|
@ -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,9 +833,44 @@ 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 {
|
||||||
return;
|
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 {
|
if end_selection {
|
||||||
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue