From d969f38850ba623612349fe1d289b558969b9eaa Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 23 Nov 2021 15:42:21 -0700 Subject: [PATCH] Implement shift-click to extend the newest selection --- crates/editor/src/element.rs | 18 +++++- crates/editor/src/lib.rs | 81 +++++++++++++++++++-------- crates/gpui/src/app.rs | 1 + crates/gpui/src/platform/event.rs | 1 + crates/gpui/src/platform/mac/event.rs | 6 +- 5 files changed, 77 insertions(+), 30 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 0eef242bd7..77def82c51 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1,3 +1,5 @@ +use crate::BeginSelectionMode; + use super::{ DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll, Select, SelectPhase, Snapshot, MAX_LINE_LEN, @@ -55,18 +57,27 @@ impl EditorElement { fn mouse_down( &self, position: Vector2F, + shift: bool, cmd: bool, click_count: usize, layout: &mut LayoutState, paint: &mut PaintState, cx: &mut EventContext, ) -> bool { + let mode = if cmd { + BeginSelectionMode::Add + } else if shift { + BeginSelectionMode::Extend + } else { + BeginSelectionMode::Update + }; + if paint.text_bounds.contains_point(position) { let snapshot = self.snapshot(cx.app); let position = paint.point_for_position(&snapshot, layout, position); cx.dispatch_action(Select(SelectPhase::Begin { position, - add: cmd, + mode, click_count, })); true @@ -75,7 +86,7 @@ impl EditorElement { let position = paint.point_for_position(&snapshot, layout, position); cx.dispatch_action(Select(SelectPhase::Begin { position, - add: cmd, + mode, click_count: 3, })); true @@ -858,9 +869,10 @@ impl Element for EditorElement { match event { Event::LeftMouseDown { position, + shift, cmd, click_count, - } => self.mouse_down(*position, *cmd, *click_count, layout, paint, cx), + } => self.mouse_down(*position, *shift, *cmd, *click_count, layout, paint, cx), Event::LeftMouseUp { position } => self.mouse_up(*position, cx), Event::LeftMouseDragged { position } => { self.mouse_dragged(*position, layout, paint, cx) diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 159ac76be2..1252234b05 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -273,7 +273,7 @@ struct SpannedRows { pub enum SelectPhase { Begin { position: DisplayPoint, - add: bool, + mode: BeginSelectionMode, click_count: usize, }, Update { @@ -283,8 +283,15 @@ pub enum SelectPhase { End, } +#[derive(Clone, Copy, Debug)] +pub enum BeginSelectionMode { + Update, + Extend, + Add, +} + #[derive(Clone, Debug)] -enum SelectMode { +enum ExtendSelectionMode { Character, Word(Range), Line(Range), @@ -338,7 +345,7 @@ pub struct Snapshot { struct PendingSelection { selection: Selection, - mode: SelectMode, + mode: ExtendSelectionMode, } struct AddSelectionsState { @@ -643,9 +650,9 @@ impl Editor { match phase { SelectPhase::Begin { position, - add, + mode, click_count, - } => self.begin_selection(*position, *add, *click_count, cx), + } => self.begin_selection(*position, *mode, *click_count, cx), SelectPhase::Update { position, scroll_position, @@ -657,7 +664,7 @@ impl Editor { fn begin_selection( &mut self, position: DisplayPoint, - add: bool, + begin_mode: BeginSelectionMode, click_count: usize, cx: &mut ViewContext, ) { @@ -670,18 +677,18 @@ impl Editor { let buffer = self.buffer.read(cx); let start; let end; - let mode; + let mut extend_mode; match click_count { 1 => { start = buffer.anchor_before(position.to_point(&display_map)); end = start.clone(); - mode = SelectMode::Character; + extend_mode = ExtendSelectionMode::Character; } 2 => { let range = movement::surrounding_word(&display_map, position); start = buffer.anchor_before(range.start.to_point(&display_map)); end = buffer.anchor_before(range.end.to_point(&display_map)); - mode = SelectMode::Word(start.clone()..end.clone()); + extend_mode = ExtendSelectionMode::Word(start.clone()..end.clone()); } 3 => { let position = display_map.clip_point(position, Bias::Left); @@ -693,15 +700,16 @@ impl Editor { start = buffer.anchor_before(line_start.to_point(&display_map)); end = buffer.anchor_before(next_line_start.to_point(&display_map)); - mode = SelectMode::Line(start.clone()..end.clone()); + extend_mode = ExtendSelectionMode::Line(start.clone()..end.clone()); } _ => { start = buffer.anchor_before(0); end = buffer.anchor_before(buffer.len()); - mode = SelectMode::All; + extend_mode = ExtendSelectionMode::All; } } - let selection = Selection { + + let mut selection = Selection { id: post_inc(&mut self.next_selection_id), start, end, @@ -709,10 +717,35 @@ impl Editor { goal: SelectionGoal::None, }; - if !add { - self.update_selections::(Vec::new(), false, cx); + match begin_mode { + BeginSelectionMode::Update => { + self.update_selections::(Vec::new(), false, cx); + } + BeginSelectionMode::Extend => { + let position = position.to_offset(&display_map, Bias::Left); + let tail = self.newest_selection::(cx).tail(); + let tail_anchor = buffer.anchor_before(tail); + if position >= tail { + selection.start = tail_anchor.clone(); + } else { + selection.end = tail_anchor.clone(); + selection.reversed = true; + } + match &mut extend_mode { + ExtendSelectionMode::Word(range) | ExtendSelectionMode::Line(range) => { + *range = tail_anchor.clone()..tail_anchor + } + _ => {} + } + self.update_selections::(Vec::new(), false, cx); + } + BeginSelectionMode::Add => {} } - self.pending_selection = Some(PendingSelection { selection, mode }); + + self.pending_selection = Some(PendingSelection { + selection, + mode: extend_mode, + }); cx.notify(); } @@ -729,11 +762,11 @@ impl Editor { let head; let tail; match mode { - SelectMode::Character => { + ExtendSelectionMode::Character => { head = position.to_point(&display_map); tail = selection.tail().to_point(buffer); } - SelectMode::Word(original_range) => { + ExtendSelectionMode::Word(original_range) => { let original_display_range = original_range.start.to_display_point(&display_map) ..original_range.end.to_display_point(&display_map); let original_buffer_range = original_display_range.start.to_point(&display_map) @@ -757,7 +790,7 @@ impl Editor { tail = original_buffer_range.start; } } - SelectMode::Line(original_range) => { + ExtendSelectionMode::Line(original_range) => { let original_display_range = original_range.start.to_display_point(&display_map) ..original_range.end.to_display_point(&display_map); let original_buffer_range = original_display_range.start.to_point(&display_map) @@ -780,7 +813,7 @@ impl Editor { tail = original_buffer_range.start; } } - SelectMode::All => { + ExtendSelectionMode::All => { return; } }; @@ -3254,7 +3287,7 @@ mod tests { cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); + view.begin_selection(DisplayPoint::new(2, 2), BeginSelectionMode::Update, 1, cx); }); assert_eq!( @@ -3291,7 +3324,7 @@ mod tests { ); editor.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(3, 3), true, 1, cx); + view.begin_selection(DisplayPoint::new(3, 3), BeginSelectionMode::Add, 1, cx); view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx); }); @@ -3320,7 +3353,7 @@ mod tests { let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx); + view.begin_selection(DisplayPoint::new(2, 2), BeginSelectionMode::Update, 1, cx); assert_eq!( view.selection_ranges(cx), [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)] @@ -3352,11 +3385,11 @@ mod tests { let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { - view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx); + view.begin_selection(DisplayPoint::new(3, 4), BeginSelectionMode::Update, 1, cx); view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx); view.end_selection(cx); - view.begin_selection(DisplayPoint::new(0, 1), true, 1, cx); + view.begin_selection(DisplayPoint::new(0, 1), BeginSelectionMode::Add, 1, cx); view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx); view.end_selection(cx); assert_eq!( diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index b05934fdcb..e34ed6877d 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3650,6 +3650,7 @@ mod tests { presenter.borrow_mut().dispatch_event( Event::LeftMouseDown { position: Default::default(), + shift: false, cmd: false, click_count: 1, }, diff --git a/crates/gpui/src/platform/event.rs b/crates/gpui/src/platform/event.rs index 1da8fc151f..08f84765bc 100644 --- a/crates/gpui/src/platform/event.rs +++ b/crates/gpui/src/platform/event.rs @@ -15,6 +15,7 @@ pub enum Event { LeftMouseDown { position: Vector2F, cmd: bool, + shift: bool, click_count: usize, }, LeftMouseUp { diff --git a/crates/gpui/src/platform/mac/event.rs b/crates/gpui/src/platform/mac/event.rs index fcac34111d..4e25dd7de7 100644 --- a/crates/gpui/src/platform/mac/event.rs +++ b/crates/gpui/src/platform/mac/event.rs @@ -86,14 +86,14 @@ impl Event { }) } NSEventType::NSLeftMouseDown => { + let modifiers = native_event.modifierFlags(); window_height.map(|window_height| Self::LeftMouseDown { position: vec2f( native_event.locationInWindow().x as f32, window_height - native_event.locationInWindow().y as f32, ), - cmd: native_event - .modifierFlags() - .contains(NSEventModifierFlags::NSCommandKeyMask), + shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask), + cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask), click_count: native_event.clickCount() as usize, }) }