diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index af463ac438..8f03d660c4 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -912,6 +912,7 @@ enum SelectionDragState { ReadyToDrag { selection: Selection, click_position: gpui::Point, + mouse_down_time: Instant, }, /// State when the mouse is dragging the selection in the editor. Dragging { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 1f820162d4..fae6654af5 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -75,7 +75,7 @@ use std::{ ops::{Deref, Range}, rc::Rc, sync::Arc, - time::Duration, + time::{Duration, Instant}, }; use sum_tree::Bias; use text::{BufferId, SelectionGoal}; @@ -87,6 +87,7 @@ use util::{RangeExt, ResultExt, debug_panic}; use workspace::{CollaboratorId, Workspace, item::Item, notifications::NotifyTaskExt}; const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.; +const SELECTION_DRAG_DELAY: Duration = Duration::from_millis(300); /// Determines what kinds of highlights should be applied to a lines background. #[derive(Clone, Copy, Default)] @@ -642,6 +643,7 @@ impl EditorElement { editor.selection_drag_state = SelectionDragState::ReadyToDrag { selection: newest_anchor.clone(), click_position: event.position, + mouse_down_time: Instant::now(), }; cx.stop_propagation(); return; @@ -837,6 +839,7 @@ impl EditorElement { SelectionDragState::ReadyToDrag { selection: _, ref click_position, + mouse_down_time: _, } => { if event.position == *click_position { editor.select( @@ -851,6 +854,8 @@ impl EditorElement { editor.selection_drag_state = SelectionDragState::None; cx.stop_propagation(); return; + } else { + debug_panic!("drag state can never be in ready state after drag") } } SelectionDragState::Dragging { ref selection, .. } => { @@ -993,25 +998,54 @@ impl EditorElement { drop_cursor.start = drop_anchor; drop_cursor.end = drop_anchor; *hide_drop_cursor = !text_hitbox.is_hovered(window); + editor.apply_scroll_delta(scroll_delta, window, cx); + cx.notify(); } - SelectionDragState::ReadyToDrag { ref selection, .. } => { - let drop_cursor = Selection { - id: post_inc(&mut editor.selections.next_selection_id), - start: drop_anchor, - end: drop_anchor, - reversed: false, - goal: SelectionGoal::None, - }; - editor.selection_drag_state = SelectionDragState::Dragging { - selection: selection.clone(), - drop_cursor, - hide_drop_cursor: false, - }; + SelectionDragState::ReadyToDrag { + ref selection, + ref click_position, + ref mouse_down_time, + } => { + if mouse_down_time.elapsed() >= SELECTION_DRAG_DELAY { + let drop_cursor = Selection { + id: post_inc(&mut editor.selections.next_selection_id), + start: drop_anchor, + end: drop_anchor, + reversed: false, + goal: SelectionGoal::None, + }; + editor.selection_drag_state = SelectionDragState::Dragging { + selection: selection.clone(), + drop_cursor, + hide_drop_cursor: false, + }; + editor.apply_scroll_delta(scroll_delta, window, cx); + cx.notify(); + } else { + let click_point = position_map.point_for_position(*click_position); + editor.selection_drag_state = SelectionDragState::None; + editor.select( + SelectPhase::Begin { + position: click_point.previous_valid, + add: false, + click_count: 1, + }, + window, + cx, + ); + editor.select( + SelectPhase::Update { + position: point_for_position.previous_valid, + goal_column: point_for_position.exact_unclipped.column(), + scroll_delta, + }, + window, + cx, + ); + } } _ => {} } - editor.apply_scroll_delta(scroll_delta, window, cx); - cx.notify(); } else { editor.select( SelectPhase::Update { @@ -5577,6 +5611,12 @@ impl EditorElement { let editor = self.editor.read(cx); if editor.mouse_cursor_hidden { window.set_window_cursor_style(CursorStyle::None); + } else if matches!( + editor.selection_drag_state, + SelectionDragState::Dragging { .. } + ) { + window + .set_cursor_style(CursorStyle::DragCopy, &layout.position_map.text_hitbox); } else if editor .hovered_link_state .as_ref()