diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index dcacb20e49..82695f319e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -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 }, + ReadyToDrag { + selection: Selection, + click_position: gpui::Point, + }, /// State when the mouse is dragging the selection in the editor. Dragging { selection: Selection, @@ -10601,54 +10604,42 @@ impl Editor { }); } - pub fn drop_selection( + pub fn move_selection_on_drop( &mut self, - point_for_position: Option, + selection: &Selection, + target: DisplayPoint, is_cut: bool, window: &mut Window, cx: &mut Context, - ) -> 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::(); - 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::(); + 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( diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 2436112909..8dc7c30e22 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -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, diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 72be41566a..7198cee36e 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -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);