vim: Add some forced motion support (#27991)
Closes https://github.com/zed-industries/zed/issues/20971 Added `v` input to yank and delete to override default motion. The global vim state tracking if the forced motion flag was passed handled the same way that the count is. [The main chunk of code maps the motion kind from the default to the overridden kind](https://github.com/zed-industries/zed/pull/27991/files#diff-2dca6b7d1673c912d14e4edc74e415abbe3a4e6d6b37e0e2006d30828bf4bb9cR1249-R1254). To handle the case of deleting a single character (dv0) at the start of a row I had to modify the control flow [here](https://github.com/zed-industries/zed/pull/27991/files#diff-2dca6b7d1673c912d14e4edc74e415abbe3a4e6d6b37e0e2006d30828bf4bb9cR1240-R1244). Then to handle an exclusive delete till the end of the row (dv$) I [saturated the endpoint with a left bias](https://github.com/zed-industries/zed/pull/27991/files#diff-2dca6b7d1673c912d14e4edc74e415abbe3a4e6d6b37e0e2006d30828bf4bb9cR1281-R1286). Test case: dv0 https://github.com/user-attachments/assets/613cf9fb-9732-425c-9179-025f3e107584 Test case: yvjp https://github.com/user-attachments/assets/550b7c77-1eb8-41c3-894b-117eb50b7a5d Release Notes: - Added some forced motion support for delete and yank
This commit is contained in:
parent
1df01eabfe
commit
08ce230bae
30 changed files with 485 additions and 58 deletions
|
@ -18,6 +18,7 @@ impl Vim {
|
|||
&mut self,
|
||||
motion: Motion,
|
||||
times: Option<usize>,
|
||||
forced_motion: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
|
@ -59,6 +60,7 @@ impl Vim {
|
|||
selection,
|
||||
times,
|
||||
&text_layout_details,
|
||||
forced_motion,
|
||||
);
|
||||
if let Motion::CurrentLine = motion {
|
||||
let mut start_offset =
|
||||
|
@ -181,7 +183,7 @@ fn expand_changed_word_selection(
|
|||
} else {
|
||||
Motion::NextWordStart { ignore_punctuation }
|
||||
};
|
||||
motion.expand_selection(map, selection, times, text_layout_details)
|
||||
motion.expand_selection(map, selection, times, text_layout_details, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ impl Vim {
|
|||
&mut self,
|
||||
motion: Motion,
|
||||
times: Option<usize>,
|
||||
forced_motion: bool,
|
||||
mode: ConvertTarget,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
|
@ -39,7 +40,13 @@ impl Vim {
|
|||
s.move_with(|map, selection| {
|
||||
let anchor = map.display_point_to_anchor(selection.head(), Bias::Left);
|
||||
selection_starts.insert(selection.id, anchor);
|
||||
motion.expand_selection(map, selection, times, &text_layout_details);
|
||||
motion.expand_selection(
|
||||
map,
|
||||
selection,
|
||||
times,
|
||||
&text_layout_details,
|
||||
forced_motion,
|
||||
);
|
||||
});
|
||||
});
|
||||
match mode {
|
||||
|
@ -185,6 +192,7 @@ impl Vim {
|
|||
self.record_current_action(cx);
|
||||
self.store_visual_marks(window, cx);
|
||||
let count = Vim::take_count(cx).unwrap_or(1) as u32;
|
||||
Vim::take_forced_motion(cx);
|
||||
|
||||
self.update_editor(window, cx, |vim, editor, window, cx| {
|
||||
let mut ranges = Vec::new();
|
||||
|
|
|
@ -18,6 +18,7 @@ impl Vim {
|
|||
&mut self,
|
||||
motion: Motion,
|
||||
times: Option<usize>,
|
||||
forced_motion: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
|
@ -33,9 +34,13 @@ impl Vim {
|
|||
s.move_with(|map, selection| {
|
||||
let original_head = selection.head();
|
||||
original_columns.insert(selection.id, original_head.column());
|
||||
let kind =
|
||||
motion.expand_selection(map, selection, times, &text_layout_details);
|
||||
|
||||
let kind = motion.expand_selection(
|
||||
map,
|
||||
selection,
|
||||
times,
|
||||
&text_layout_details,
|
||||
forced_motion,
|
||||
);
|
||||
ranges_to_copy
|
||||
.push(selection.start.to_point(map)..selection.end.to_point(map));
|
||||
|
||||
|
|
|
@ -29,12 +29,14 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
Vim::action(editor, cx, |vim, action: &Increment, window, cx| {
|
||||
vim.record_current_action(cx);
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
let step = if action.step { count as i32 } else { 0 };
|
||||
vim.increment(count as i64, step, window, cx)
|
||||
});
|
||||
Vim::action(editor, cx, |vim, action: &Decrement, window, cx| {
|
||||
vim.record_current_action(cx);
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
let step = if action.step { -1 * (count as i32) } else { 0 };
|
||||
vim.increment(-(count as i64), step, window, cx)
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@ impl Vim {
|
|||
self.record_current_action(cx);
|
||||
self.store_visual_marks(window, cx);
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
|
||||
self.update_editor(window, cx, |vim, editor, window, cx| {
|
||||
let text_layout_details = editor.text_layout_details(window);
|
||||
|
@ -247,6 +248,7 @@ impl Vim {
|
|||
&mut self,
|
||||
motion: Motion,
|
||||
times: Option<usize>,
|
||||
forced_motion: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
|
@ -258,7 +260,13 @@ impl Vim {
|
|||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.change_selections(None, window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
motion.expand_selection(map, selection, times, &text_layout_details);
|
||||
motion.expand_selection(
|
||||
map,
|
||||
selection,
|
||||
times,
|
||||
&text_layout_details,
|
||||
forced_motion,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -170,6 +170,7 @@ impl Vim {
|
|||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let mut count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
self.clear_operator(window, cx);
|
||||
|
||||
let globals = Vim::globals(cx);
|
||||
|
@ -201,6 +202,7 @@ impl Vim {
|
|||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let count = Vim::take_count(cx);
|
||||
Vim::take_forced_motion(cx);
|
||||
|
||||
let Some((mut actions, selection, mode)) = Vim::update_globals(cx, |globals, _| {
|
||||
let actions = globals.recorded_actions.clone();
|
||||
|
|
|
@ -55,6 +55,7 @@ impl Vim {
|
|||
by: fn(c: Option<f32>) -> ScrollAmount,
|
||||
) {
|
||||
let amount = by(Vim::take_count(cx).map(|c| c as f32));
|
||||
Vim::take_forced_motion(cx);
|
||||
self.update_editor(window, cx, |_, editor, window, cx| {
|
||||
scroll_editor(editor, move_cursor, &amount, window, cx)
|
||||
});
|
||||
|
|
|
@ -138,6 +138,7 @@ impl Vim {
|
|||
Direction::Next
|
||||
};
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
let prior_selections = self.editor_selections(window, cx);
|
||||
pane.update(cx, |pane, cx| {
|
||||
if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() {
|
||||
|
@ -261,6 +262,7 @@ impl Vim {
|
|||
return;
|
||||
};
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
let prior_selections = self.editor_selections(window, cx);
|
||||
|
||||
let success = pane.update(cx, |pane, cx| {
|
||||
|
@ -303,6 +305,7 @@ impl Vim {
|
|||
return;
|
||||
};
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
Vim::take_forced_motion(cx);
|
||||
let prior_selections = self.editor_selections(window, cx);
|
||||
let cursor_word = self.editor_cursor_word(window, cx);
|
||||
let vim = cx.entity().clone();
|
||||
|
|
|
@ -13,6 +13,7 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
Vim::action(editor, cx, |vim, _: &Substitute, window, cx| {
|
||||
vim.start_recording(cx);
|
||||
let count = Vim::take_count(cx);
|
||||
Vim::take_forced_motion(cx);
|
||||
vim.substitute(count, vim.mode == Mode::VisualLine, window, cx);
|
||||
});
|
||||
|
||||
|
@ -22,6 +23,7 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
|||
vim.switch_mode(Mode::VisualLine, false, window, cx)
|
||||
}
|
||||
let count = Vim::take_count(cx);
|
||||
Vim::take_forced_motion(cx);
|
||||
vim.substitute(count, true, window, cx)
|
||||
});
|
||||
}
|
||||
|
@ -47,6 +49,7 @@ impl Vim {
|
|||
selection,
|
||||
count,
|
||||
&text_layout_details,
|
||||
false,
|
||||
);
|
||||
}
|
||||
if line_mode {
|
||||
|
@ -60,6 +63,7 @@ impl Vim {
|
|||
selection,
|
||||
None,
|
||||
&text_layout_details,
|
||||
false,
|
||||
);
|
||||
if let Some((point, _)) = (Motion::FirstNonWhitespace {
|
||||
display_lines: false,
|
||||
|
|
|
@ -9,6 +9,7 @@ impl Vim {
|
|||
&mut self,
|
||||
motion: Motion,
|
||||
times: Option<usize>,
|
||||
forced_motion: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
|
@ -21,7 +22,13 @@ impl Vim {
|
|||
s.move_with(|map, selection| {
|
||||
let anchor = map.display_point_to_anchor(selection.head(), Bias::Right);
|
||||
selection_starts.insert(selection.id, anchor);
|
||||
motion.expand_selection(map, selection, times, &text_layout_details);
|
||||
motion.expand_selection(
|
||||
map,
|
||||
selection,
|
||||
times,
|
||||
&text_layout_details,
|
||||
forced_motion,
|
||||
);
|
||||
});
|
||||
});
|
||||
editor.toggle_comments(&Default::default(), window, cx);
|
||||
|
|
|
@ -21,6 +21,7 @@ impl Vim {
|
|||
&mut self,
|
||||
motion: Motion,
|
||||
times: Option<usize>,
|
||||
forced_motion: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
|
@ -33,8 +34,19 @@ impl Vim {
|
|||
editor.change_selections(None, window, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
let original_position = (selection.head(), selection.goal);
|
||||
original_positions.insert(selection.id, original_position);
|
||||
kind = motion.expand_selection(map, selection, times, &text_layout_details);
|
||||
kind = motion.expand_selection(
|
||||
map,
|
||||
selection,
|
||||
times,
|
||||
&text_layout_details,
|
||||
forced_motion,
|
||||
);
|
||||
if kind == Some(MotionKind::Exclusive) {
|
||||
original_positions
|
||||
.insert(selection.id, (selection.start, selection.goal));
|
||||
} else {
|
||||
original_positions.insert(selection.id, original_position);
|
||||
}
|
||||
})
|
||||
});
|
||||
let Some(kind) = kind else { return };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue