Move selection helpers to SelectionCollection, add update_anchor_selections, add a number of invariant preserving mutation functions to the MutableSelectionCollection
This commit is contained in:
parent
61b4a4202f
commit
c9dcfff607
22 changed files with 1891 additions and 1467 deletions
|
@ -13,9 +13,11 @@ pub fn init(cx: &mut MutableAppContext) {
|
|||
fn normal_before(_: &mut Workspace, _: &NormalBefore, cx: &mut ViewContext<Workspace>) {
|
||||
Vim::update(cx, |state, cx| {
|
||||
state.update_active_editor(cx, |editor, cx| {
|
||||
editor.move_cursors(cx, |map, mut cursor, _| {
|
||||
*cursor.column_mut() = cursor.column().saturating_sub(1);
|
||||
(map.clip_point(cursor, Bias::Left), SelectionGoal::None)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, mut cursor, _| {
|
||||
*cursor.column_mut() = cursor.column().saturating_sub(1);
|
||||
(map.clip_point(cursor, Bias::Left), SelectionGoal::None)
|
||||
});
|
||||
});
|
||||
});
|
||||
state.switch_mode(Mode::Normal, cx);
|
||||
|
|
|
@ -76,7 +76,9 @@ pub fn normal_motion(motion: Motion, cx: &mut MutableAppContext) {
|
|||
|
||||
fn move_cursor(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.move_cursors(cx, |map, cursor, goal| motion.move_point(map, cursor, goal))
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, cursor, goal| motion.move_point(map, cursor, goal))
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -84,8 +86,10 @@ fn insert_after(_: &mut Workspace, _: &InsertAfter, cx: &mut ViewContext<Workspa
|
|||
Vim::update(cx, |vim, cx| {
|
||||
vim.switch_mode(Mode::Insert, cx);
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.move_cursors(cx, |map, cursor, goal| {
|
||||
Motion::Right.move_point(map, cursor, goal)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, cursor, goal| {
|
||||
Motion::Right.move_point(map, cursor, goal)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -99,8 +103,10 @@ fn insert_first_non_whitespace(
|
|||
Vim::update(cx, |vim, cx| {
|
||||
vim.switch_mode(Mode::Insert, cx);
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.move_cursors(cx, |map, cursor, goal| {
|
||||
Motion::FirstNonWhitespace.move_point(map, cursor, goal)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, cursor, goal| {
|
||||
Motion::FirstNonWhitespace.move_point(map, cursor, goal)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -110,8 +116,10 @@ fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewConte
|
|||
Vim::update(cx, |vim, cx| {
|
||||
vim.switch_mode(Mode::Insert, cx);
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.move_cursors(cx, |map, cursor, goal| {
|
||||
Motion::EndOfLine.move_point(map, cursor, goal)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, cursor, goal| {
|
||||
Motion::EndOfLine.move_point(map, cursor, goal)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -137,10 +145,12 @@ fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContex
|
|||
(start_of_line..start_of_line, new_text)
|
||||
});
|
||||
editor.edit_with_autoindent(edits, cx);
|
||||
editor.move_cursors(cx, |map, mut cursor, _| {
|
||||
*cursor.row_mut() -= 1;
|
||||
*cursor.column_mut() = map.line_len(cursor.row());
|
||||
(map.clip_point(cursor, Bias::Left), SelectionGoal::None)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, mut cursor, _| {
|
||||
*cursor.row_mut() -= 1;
|
||||
*cursor.column_mut() = map.line_len(cursor.row());
|
||||
(map.clip_point(cursor, Bias::Left), SelectionGoal::None)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -166,8 +176,10 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex
|
|||
new_text.push_str(&" ".repeat(indent as usize));
|
||||
(end_of_line..end_of_line, new_text)
|
||||
});
|
||||
editor.move_cursors(cx, |map, cursor, goal| {
|
||||
Motion::EndOfLine.move_point(map, cursor, goal)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_cursors_with(|map, cursor, goal| {
|
||||
Motion::EndOfLine.move_point(map, cursor, goal)
|
||||
});
|
||||
});
|
||||
editor.edit_with_autoindent(edits, cx);
|
||||
});
|
||||
|
|
|
@ -22,8 +22,10 @@ pub fn change_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
|||
editor.transact(cx, |editor, cx| {
|
||||
// We are swapping to insert mode anyway. Just set the line end clipping behavior now
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
motion.expand_selection(map, selection, false);
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
motion.expand_selection(map, selection, false);
|
||||
});
|
||||
});
|
||||
editor.insert(&"", cx);
|
||||
});
|
||||
|
@ -46,16 +48,21 @@ fn change_word(
|
|||
editor.transact(cx, |editor, cx| {
|
||||
// We are swapping to insert mode anyway. Just set the line end clipping behavior now
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
if selection.end.column() == map.line_len(selection.end.row()) {
|
||||
return;
|
||||
}
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
if selection.end.column() == map.line_len(selection.end.row()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selection.end = movement::find_boundary(map, selection.end, |left, right| {
|
||||
let left_kind = char_kind(left).coerce_punctuation(ignore_punctuation);
|
||||
let right_kind = char_kind(right).coerce_punctuation(ignore_punctuation);
|
||||
selection.end =
|
||||
movement::find_boundary(map, selection.end, |left, right| {
|
||||
let left_kind =
|
||||
char_kind(left).coerce_punctuation(ignore_punctuation);
|
||||
let right_kind =
|
||||
char_kind(right).coerce_punctuation(ignore_punctuation);
|
||||
|
||||
left_kind != right_kind || left == '\n' || right == '\n'
|
||||
left_kind != right_kind || left == '\n' || right == '\n'
|
||||
});
|
||||
});
|
||||
});
|
||||
editor.insert(&"", cx);
|
||||
|
|
|
@ -8,24 +8,28 @@ pub fn delete_over(vim: &mut Vim, motion: Motion, cx: &mut MutableAppContext) {
|
|||
editor.transact(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
let mut original_columns: HashMap<_, _> = Default::default();
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
let original_head = selection.head();
|
||||
motion.expand_selection(map, selection, true);
|
||||
original_columns.insert(selection.id, original_head.column());
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let original_head = selection.head();
|
||||
motion.expand_selection(map, selection, true);
|
||||
original_columns.insert(selection.id, original_head.column());
|
||||
});
|
||||
});
|
||||
editor.insert(&"", cx);
|
||||
|
||||
// Fixup cursor position after the deletion
|
||||
editor.set_clip_at_line_ends(true, cx);
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
let mut cursor = selection.head();
|
||||
if motion.linewise() {
|
||||
if let Some(column) = original_columns.get(&selection.id) {
|
||||
*cursor.column_mut() = *column
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let mut cursor = selection.head();
|
||||
if motion.linewise() {
|
||||
if let Some(column) = original_columns.get(&selection.id) {
|
||||
*cursor.column_mut() = *column
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor = map.clip_point(cursor, Bias::Left);
|
||||
selection.collapse_to(cursor, selection.goal)
|
||||
cursor = map.clip_point(cursor, Bias::Left);
|
||||
selection.collapse_to(cursor, selection.goal)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -128,7 +128,9 @@ impl<'a> VimTestContext<'a> {
|
|||
let (unmarked_text, markers) = marked_text(&text);
|
||||
editor.set_text(unmarked_text, cx);
|
||||
let cursor_offset = markers[0];
|
||||
editor.replace_selections_with(cx, |map| cursor_offset.to_display_point(map));
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.replace_cursors_with(|map| vec![cursor_offset.to_display_point(map)])
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -197,7 +199,8 @@ impl<'a> VimTestContext<'a> {
|
|||
let (empty_selections, reverse_selections, forward_selections) =
|
||||
self.editor.read_with(self.cx, |editor, cx| {
|
||||
let (empty_selections, non_empty_selections): (Vec<_>, Vec<_>) = editor
|
||||
.local_selections::<usize>(cx)
|
||||
.selections
|
||||
.interleaved::<usize>(&editor.buffer().read(cx).read(cx))
|
||||
.into_iter()
|
||||
.partition_map(|selection| {
|
||||
if selection.is_empty() {
|
||||
|
|
|
@ -14,23 +14,25 @@ pub fn init(cx: &mut MutableAppContext) {
|
|||
pub fn visual_motion(motion: Motion, cx: &mut MutableAppContext) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
let (new_head, goal) = motion.move_point(map, selection.head(), selection.goal);
|
||||
let new_head = map.clip_at_line_end(new_head);
|
||||
let was_reversed = selection.reversed;
|
||||
selection.set_head(new_head, goal);
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let (new_head, goal) = motion.move_point(map, selection.head(), selection.goal);
|
||||
let new_head = map.clip_at_line_end(new_head);
|
||||
let was_reversed = selection.reversed;
|
||||
selection.set_head(new_head, goal);
|
||||
|
||||
if was_reversed && !selection.reversed {
|
||||
// Head was at the start of the selection, and now is at the end. We need to move the start
|
||||
// back by one if possible in order to compensate for this change.
|
||||
*selection.start.column_mut() = selection.start.column().saturating_sub(1);
|
||||
selection.start = map.clip_point(selection.start, Bias::Left);
|
||||
} else if !was_reversed && selection.reversed {
|
||||
// Head was at the end of the selection, and now is at the start. We need to move the end
|
||||
// forward by one if possible in order to compensate for this change.
|
||||
*selection.end.column_mut() = selection.end.column() + 1;
|
||||
selection.end = map.clip_point(selection.end, Bias::Left);
|
||||
}
|
||||
if was_reversed && !selection.reversed {
|
||||
// Head was at the start of the selection, and now is at the end. We need to move the start
|
||||
// back by one if possible in order to compensate for this change.
|
||||
*selection.start.column_mut() = selection.start.column().saturating_sub(1);
|
||||
selection.start = map.clip_point(selection.start, Bias::Left);
|
||||
} else if !was_reversed && selection.reversed {
|
||||
// Head was at the end of the selection, and now is at the start. We need to move the end
|
||||
// forward by one if possible in order to compensate for this change.
|
||||
*selection.end.column_mut() = selection.end.column() + 1;
|
||||
selection.end = map.clip_point(selection.end, Bias::Left);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -40,13 +42,15 @@ pub fn change(_: &mut Workspace, _: &VisualChange, cx: &mut ViewContext<Workspac
|
|||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
if !selection.reversed {
|
||||
// Head was at the end of the selection, and now is at the start. We need to move the end
|
||||
// forward by one if possible in order to compensate for this change.
|
||||
*selection.end.column_mut() = selection.end.column() + 1;
|
||||
selection.end = map.clip_point(selection.end, Bias::Left);
|
||||
}
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
if !selection.reversed {
|
||||
// Head was at the end of the selection, and now is at the start. We need to move the end
|
||||
// forward by one if possible in order to compensate for this change.
|
||||
*selection.end.column_mut() = selection.end.column() + 1;
|
||||
selection.end = map.clip_point(selection.end, Bias::Left);
|
||||
}
|
||||
});
|
||||
});
|
||||
editor.insert("", cx);
|
||||
});
|
||||
|
@ -59,22 +63,26 @@ pub fn delete(_: &mut Workspace, _: &VisualDelete, cx: &mut ViewContext<Workspac
|
|||
vim.switch_mode(Mode::Normal, cx);
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
if !selection.reversed {
|
||||
// Head was at the end of the selection, and now is at the start. We need to move the end
|
||||
// forward by one if possible in order to compensate for this change.
|
||||
*selection.end.column_mut() = selection.end.column() + 1;
|
||||
selection.end = map.clip_point(selection.end, Bias::Left);
|
||||
}
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
if !selection.reversed {
|
||||
// Head was at the end of the selection, and now is at the start. We need to move the end
|
||||
// forward by one if possible in order to compensate for this change.
|
||||
*selection.end.column_mut() = selection.end.column() + 1;
|
||||
selection.end = map.clip_point(selection.end, Bias::Left);
|
||||
}
|
||||
});
|
||||
});
|
||||
editor.insert("", cx);
|
||||
|
||||
// Fixup cursor position after the deletion
|
||||
editor.set_clip_at_line_ends(true, cx);
|
||||
editor.move_selections(cx, |map, selection| {
|
||||
let mut cursor = selection.head();
|
||||
cursor = map.clip_point(cursor, Bias::Left);
|
||||
selection.collapse_to(cursor, selection.goal)
|
||||
editor.change_selections(true, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let mut cursor = selection.head();
|
||||
cursor = map.clip_point(cursor, Bias::Left);
|
||||
selection.collapse_to(cursor, selection.goal)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue