Simplify handling of shift-click to extend selections
This commit is contained in:
parent
d969f38850
commit
9e651ee127
2 changed files with 79 additions and 79 deletions
|
@ -1,5 +1,3 @@
|
||||||
use crate::BeginSelectionMode;
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll,
|
DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll,
|
||||||
Select, SelectPhase, Snapshot, MAX_LINE_LEN,
|
Select, SelectPhase, Snapshot, MAX_LINE_LEN,
|
||||||
|
@ -59,40 +57,34 @@ impl EditorElement {
|
||||||
position: Vector2F,
|
position: Vector2F,
|
||||||
shift: bool,
|
shift: bool,
|
||||||
cmd: bool,
|
cmd: bool,
|
||||||
click_count: usize,
|
mut click_count: usize,
|
||||||
layout: &mut LayoutState,
|
layout: &mut LayoutState,
|
||||||
paint: &mut PaintState,
|
paint: &mut PaintState,
|
||||||
cx: &mut EventContext,
|
cx: &mut EventContext,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mode = if cmd {
|
if paint.gutter_bounds.contains_point(position) {
|
||||||
BeginSelectionMode::Add
|
click_count = 3; // Simulate triple-click when clicking the gutter to select lines
|
||||||
} else if shift {
|
} else if !paint.text_bounds.contains_point(position) {
|
||||||
BeginSelectionMode::Extend
|
return false;
|
||||||
} else {
|
}
|
||||||
BeginSelectionMode::Update
|
|
||||||
};
|
|
||||||
|
|
||||||
if paint.text_bounds.contains_point(position) {
|
let snapshot = self.snapshot(cx.app);
|
||||||
let snapshot = self.snapshot(cx.app);
|
let position = paint.point_for_position(&snapshot, layout, position);
|
||||||
let position = paint.point_for_position(&snapshot, layout, position);
|
|
||||||
cx.dispatch_action(Select(SelectPhase::Begin {
|
if shift {
|
||||||
|
cx.dispatch_action(Select(SelectPhase::Extend {
|
||||||
position,
|
position,
|
||||||
mode,
|
|
||||||
click_count,
|
click_count,
|
||||||
}));
|
}));
|
||||||
true
|
} else {
|
||||||
} else if paint.gutter_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 {
|
cx.dispatch_action(Select(SelectPhase::Begin {
|
||||||
position,
|
position,
|
||||||
mode,
|
add: cmd,
|
||||||
click_count: 3,
|
click_count,
|
||||||
}));
|
}));
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool {
|
fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool {
|
||||||
|
|
|
@ -273,7 +273,11 @@ struct SpannedRows {
|
||||||
pub enum SelectPhase {
|
pub enum SelectPhase {
|
||||||
Begin {
|
Begin {
|
||||||
position: DisplayPoint,
|
position: DisplayPoint,
|
||||||
mode: BeginSelectionMode,
|
add: bool,
|
||||||
|
click_count: usize,
|
||||||
|
},
|
||||||
|
Extend {
|
||||||
|
position: DisplayPoint,
|
||||||
click_count: usize,
|
click_count: usize,
|
||||||
},
|
},
|
||||||
Update {
|
Update {
|
||||||
|
@ -283,15 +287,8 @@ pub enum SelectPhase {
|
||||||
End,
|
End,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum BeginSelectionMode {
|
|
||||||
Update,
|
|
||||||
Extend,
|
|
||||||
Add,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum ExtendSelectionMode {
|
enum SelectMode {
|
||||||
Character,
|
Character,
|
||||||
Word(Range<Anchor>),
|
Word(Range<Anchor>),
|
||||||
Line(Range<Anchor>),
|
Line(Range<Anchor>),
|
||||||
|
@ -345,7 +342,7 @@ pub struct Snapshot {
|
||||||
|
|
||||||
struct PendingSelection {
|
struct PendingSelection {
|
||||||
selection: Selection<Anchor>,
|
selection: Selection<Anchor>,
|
||||||
mode: ExtendSelectionMode,
|
mode: SelectMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AddSelectionsState {
|
struct AddSelectionsState {
|
||||||
|
@ -650,9 +647,13 @@ impl Editor {
|
||||||
match phase {
|
match phase {
|
||||||
SelectPhase::Begin {
|
SelectPhase::Begin {
|
||||||
position,
|
position,
|
||||||
mode,
|
add,
|
||||||
click_count,
|
click_count,
|
||||||
} => self.begin_selection(*position, *mode, *click_count, cx),
|
} => self.begin_selection(*position, *add, *click_count, cx),
|
||||||
|
SelectPhase::Extend {
|
||||||
|
position,
|
||||||
|
click_count,
|
||||||
|
} => self.extend_selection(*position, *click_count, cx),
|
||||||
SelectPhase::Update {
|
SelectPhase::Update {
|
||||||
position,
|
position,
|
||||||
scroll_position,
|
scroll_position,
|
||||||
|
@ -661,10 +662,41 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extend_selection(
|
||||||
|
&mut self,
|
||||||
|
position: DisplayPoint,
|
||||||
|
click_count: usize,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
let tail = self.newest_selection::<usize>(cx).tail();
|
||||||
|
|
||||||
|
self.begin_selection(position, false, click_count, cx);
|
||||||
|
|
||||||
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
|
let buffer = self.buffer.read(cx);
|
||||||
|
let position = position.to_offset(&display_map, Bias::Left);
|
||||||
|
let tail_anchor = buffer.anchor_before(tail);
|
||||||
|
let pending = self.pending_selection.as_mut().unwrap();
|
||||||
|
|
||||||
|
if position >= tail {
|
||||||
|
pending.selection.start = tail_anchor.clone();
|
||||||
|
} else {
|
||||||
|
pending.selection.end = tail_anchor.clone();
|
||||||
|
pending.selection.reversed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &mut pending.mode {
|
||||||
|
SelectMode::Word(range) | SelectMode::Line(range) => {
|
||||||
|
*range = tail_anchor.clone()..tail_anchor
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn begin_selection(
|
fn begin_selection(
|
||||||
&mut self,
|
&mut self,
|
||||||
position: DisplayPoint,
|
position: DisplayPoint,
|
||||||
begin_mode: BeginSelectionMode,
|
add: bool,
|
||||||
click_count: usize,
|
click_count: usize,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -677,18 +709,18 @@ impl Editor {
|
||||||
let buffer = self.buffer.read(cx);
|
let buffer = self.buffer.read(cx);
|
||||||
let start;
|
let start;
|
||||||
let end;
|
let end;
|
||||||
let mut extend_mode;
|
let mode;
|
||||||
match click_count {
|
match click_count {
|
||||||
1 => {
|
1 => {
|
||||||
start = buffer.anchor_before(position.to_point(&display_map));
|
start = buffer.anchor_before(position.to_point(&display_map));
|
||||||
end = start.clone();
|
end = start.clone();
|
||||||
extend_mode = ExtendSelectionMode::Character;
|
mode = SelectMode::Character;
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
let range = movement::surrounding_word(&display_map, position);
|
let range = movement::surrounding_word(&display_map, position);
|
||||||
start = buffer.anchor_before(range.start.to_point(&display_map));
|
start = buffer.anchor_before(range.start.to_point(&display_map));
|
||||||
end = buffer.anchor_before(range.end.to_point(&display_map));
|
end = buffer.anchor_before(range.end.to_point(&display_map));
|
||||||
extend_mode = ExtendSelectionMode::Word(start.clone()..end.clone());
|
mode = SelectMode::Word(start.clone()..end.clone());
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
let position = display_map.clip_point(position, Bias::Left);
|
let position = display_map.clip_point(position, Bias::Left);
|
||||||
|
@ -700,16 +732,16 @@ impl Editor {
|
||||||
|
|
||||||
start = buffer.anchor_before(line_start.to_point(&display_map));
|
start = buffer.anchor_before(line_start.to_point(&display_map));
|
||||||
end = buffer.anchor_before(next_line_start.to_point(&display_map));
|
end = buffer.anchor_before(next_line_start.to_point(&display_map));
|
||||||
extend_mode = ExtendSelectionMode::Line(start.clone()..end.clone());
|
mode = SelectMode::Line(start.clone()..end.clone());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
start = buffer.anchor_before(0);
|
start = buffer.anchor_before(0);
|
||||||
end = buffer.anchor_before(buffer.len());
|
end = buffer.anchor_before(buffer.len());
|
||||||
extend_mode = ExtendSelectionMode::All;
|
mode = SelectMode::All;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut selection = Selection {
|
let selection = Selection {
|
||||||
id: post_inc(&mut self.next_selection_id),
|
id: post_inc(&mut self.next_selection_id),
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
|
@ -717,35 +749,11 @@ impl Editor {
|
||||||
goal: SelectionGoal::None,
|
goal: SelectionGoal::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
match begin_mode {
|
if !add {
|
||||||
BeginSelectionMode::Update => {
|
self.update_selections::<usize>(Vec::new(), false, cx);
|
||||||
self.update_selections::<usize>(Vec::new(), false, cx);
|
|
||||||
}
|
|
||||||
BeginSelectionMode::Extend => {
|
|
||||||
let position = position.to_offset(&display_map, Bias::Left);
|
|
||||||
let tail = self.newest_selection::<usize>(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::<usize>(Vec::new(), false, cx);
|
|
||||||
}
|
|
||||||
BeginSelectionMode::Add => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pending_selection = Some(PendingSelection {
|
self.pending_selection = Some(PendingSelection { selection, mode });
|
||||||
selection,
|
|
||||||
mode: extend_mode,
|
|
||||||
});
|
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
@ -762,11 +770,11 @@ impl Editor {
|
||||||
let head;
|
let head;
|
||||||
let tail;
|
let tail;
|
||||||
match mode {
|
match mode {
|
||||||
ExtendSelectionMode::Character => {
|
SelectMode::Character => {
|
||||||
head = position.to_point(&display_map);
|
head = position.to_point(&display_map);
|
||||||
tail = selection.tail().to_point(buffer);
|
tail = selection.tail().to_point(buffer);
|
||||||
}
|
}
|
||||||
ExtendSelectionMode::Word(original_range) => {
|
SelectMode::Word(original_range) => {
|
||||||
let original_display_range = original_range.start.to_display_point(&display_map)
|
let original_display_range = original_range.start.to_display_point(&display_map)
|
||||||
..original_range.end.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)
|
let original_buffer_range = original_display_range.start.to_point(&display_map)
|
||||||
|
@ -790,7 +798,7 @@ impl Editor {
|
||||||
tail = original_buffer_range.start;
|
tail = original_buffer_range.start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExtendSelectionMode::Line(original_range) => {
|
SelectMode::Line(original_range) => {
|
||||||
let original_display_range = original_range.start.to_display_point(&display_map)
|
let original_display_range = original_range.start.to_display_point(&display_map)
|
||||||
..original_range.end.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)
|
let original_buffer_range = original_display_range.start.to_point(&display_map)
|
||||||
|
@ -813,7 +821,7 @@ impl Editor {
|
||||||
tail = original_buffer_range.start;
|
tail = original_buffer_range.start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExtendSelectionMode::All => {
|
SelectMode::All => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3287,7 +3295,7 @@ mod tests {
|
||||||
cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
||||||
|
|
||||||
editor.update(cx, |view, cx| {
|
editor.update(cx, |view, cx| {
|
||||||
view.begin_selection(DisplayPoint::new(2, 2), BeginSelectionMode::Update, 1, cx);
|
view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -3324,7 +3332,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
editor.update(cx, |view, cx| {
|
editor.update(cx, |view, cx| {
|
||||||
view.begin_selection(DisplayPoint::new(3, 3), BeginSelectionMode::Add, 1, cx);
|
view.begin_selection(DisplayPoint::new(3, 3), true, 1, cx);
|
||||||
view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx);
|
view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3353,7 +3361,7 @@ mod tests {
|
||||||
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
||||||
|
|
||||||
view.update(cx, |view, cx| {
|
view.update(cx, |view, cx| {
|
||||||
view.begin_selection(DisplayPoint::new(2, 2), BeginSelectionMode::Update, 1, cx);
|
view.begin_selection(DisplayPoint::new(2, 2), false, 1, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
view.selection_ranges(cx),
|
view.selection_ranges(cx),
|
||||||
[DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
|
[DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
|
||||||
|
@ -3385,11 +3393,11 @@ mod tests {
|
||||||
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx));
|
||||||
|
|
||||||
view.update(cx, |view, cx| {
|
view.update(cx, |view, cx| {
|
||||||
view.begin_selection(DisplayPoint::new(3, 4), BeginSelectionMode::Update, 1, cx);
|
view.begin_selection(DisplayPoint::new(3, 4), false, 1, cx);
|
||||||
view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
|
view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), cx);
|
||||||
view.end_selection(cx);
|
view.end_selection(cx);
|
||||||
|
|
||||||
view.begin_selection(DisplayPoint::new(0, 1), BeginSelectionMode::Add, 1, cx);
|
view.begin_selection(DisplayPoint::new(0, 1), true, 1, cx);
|
||||||
view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx);
|
view.update_selection(DisplayPoint::new(0, 3), Vector2F::zero(), cx);
|
||||||
view.end_selection(cx);
|
view.end_selection(cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue