Add a VisualBlock mode
Instead of trying to extend the Mode::Visual special case, just split out into three different modes.
This commit is contained in:
parent
404b1aa65a
commit
1cc0798aea
16 changed files with 94 additions and 90 deletions
|
@ -86,8 +86,9 @@ impl View for ModeIndicator {
|
|||
let text = match mode {
|
||||
Mode::Normal => "-- NORMAL --",
|
||||
Mode::Insert => "-- INSERT --",
|
||||
Mode::Visual { line: false } => "-- VISUAL --",
|
||||
Mode::Visual { line: true } => "VISUAL LINE",
|
||||
Mode::Visual => "-- VISUAL --",
|
||||
Mode::VisualLine => "VISUAL LINE",
|
||||
Mode::VisualBlock => "VISUAL BLOCK",
|
||||
};
|
||||
Label::new(text, theme.vim_mode_indicator.text.clone())
|
||||
.contained()
|
||||
|
|
|
@ -149,7 +149,7 @@ pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) {
|
|||
let operator = Vim::read(cx).active_operator();
|
||||
match Vim::read(cx).state.mode {
|
||||
Mode::Normal => normal_motion(motion, operator, times, cx),
|
||||
Mode::Visual { .. } => visual_motion(motion, times, cx),
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_motion(motion, times, cx),
|
||||
Mode::Insert => {
|
||||
// Shouldn't execute a motion in insert mode. Ignoring
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ pub fn change_case(_: &mut Workspace, _: &ChangeCase, cx: &mut ViewContext<Works
|
|||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
for selection in editor.selections.all::<Point>(cx) {
|
||||
match vim.state.mode {
|
||||
Mode::Visual { line: true } => {
|
||||
Mode::VisualLine => {
|
||||
let start = Point::new(selection.start.row, 0);
|
||||
let end =
|
||||
Point::new(selection.end.row, snapshot.line_len(selection.end.row));
|
||||
ranges.push(start..end);
|
||||
cursor_positions.push(start..start);
|
||||
}
|
||||
Mode::Visual { line: false } => {
|
||||
Mode::Visual | Mode::VisualBlock => {
|
||||
ranges.push(selection.start..selection.end);
|
||||
cursor_positions.push(selection.start..selection.start);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use language::Point;
|
|||
use crate::{motion::Motion, utils::copy_selections_content, Mode, Vim};
|
||||
|
||||
pub fn substitute(vim: &mut Vim, count: Option<usize>, cx: &mut WindowContext) {
|
||||
let line_mode = vim.state.mode == Mode::Visual { line: true };
|
||||
let line_mode = vim.state.mode == Mode::VisualLine;
|
||||
vim.switch_mode(Mode::Insert, true, cx);
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.transact(cx, |editor, cx| {
|
||||
|
@ -52,7 +52,7 @@ mod test {
|
|||
cx.assert_editor_state("xˇbc\n");
|
||||
|
||||
// supports a selection
|
||||
cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual { line: false });
|
||||
cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual);
|
||||
cx.assert_editor_state("a«bcˇ»\n");
|
||||
cx.simulate_keystrokes(["s", "x"]);
|
||||
cx.assert_editor_state("axˇ\n");
|
||||
|
|
|
@ -64,7 +64,7 @@ pub fn init(cx: &mut AppContext) {
|
|||
fn object(object: Object, cx: &mut WindowContext) {
|
||||
match Vim::read(cx).state.mode {
|
||||
Mode::Normal => normal_object(object, cx),
|
||||
Mode::Visual { .. } => visual_object(object, cx),
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_object(object, cx),
|
||||
Mode::Insert => {
|
||||
// Shouldn't execute a text object in insert mode. Ignoring
|
||||
}
|
||||
|
|
|
@ -9,14 +9,16 @@ use crate::motion::Motion;
|
|||
pub enum Mode {
|
||||
Normal,
|
||||
Insert,
|
||||
Visual { line: bool },
|
||||
Visual,
|
||||
VisualLine,
|
||||
VisualBlock,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
pub fn is_visual(&self) -> bool {
|
||||
match self {
|
||||
Mode::Normal | Mode::Insert => false,
|
||||
Mode::Visual { .. } => true,
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +76,7 @@ impl VimState {
|
|||
CursorShape::Underscore
|
||||
}
|
||||
}
|
||||
Mode::Visual { .. } => CursorShape::Block,
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => CursorShape::Block,
|
||||
Mode::Insert => CursorShape::Bar,
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +91,7 @@ impl VimState {
|
|||
|
||||
pub fn clip_at_line_ends(&self) -> bool {
|
||||
match self.mode {
|
||||
Mode::Insert | Mode::Visual { .. } => false,
|
||||
Mode::Insert | Mode::Visual | Mode::VisualLine | Mode::VisualBlock => false,
|
||||
Mode::Normal => true,
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +103,7 @@ impl VimState {
|
|||
"vim_mode",
|
||||
match self.mode {
|
||||
Mode::Normal => "normal",
|
||||
Mode::Visual { .. } => "visual",
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => "visual",
|
||||
Mode::Insert => "insert",
|
||||
},
|
||||
);
|
||||
|
|
|
@ -241,7 +241,7 @@ async fn test_status_indicator(
|
|||
deterministic.run_until_parked();
|
||||
assert_eq!(
|
||||
cx.workspace(|_, cx| mode_indicator.read(cx).mode),
|
||||
Some(Mode::Visual { line: false })
|
||||
Some(Mode::Visual)
|
||||
);
|
||||
|
||||
// hides if vim mode is disabled
|
||||
|
|
|
@ -116,7 +116,7 @@ impl<'a> NeovimBackedTestContext<'a> {
|
|||
|
||||
pub async fn set_shared_state(&mut self, marked_text: &str) -> ContextHandle {
|
||||
let mode = if marked_text.contains("»") {
|
||||
Mode::Visual { line: false }
|
||||
Mode::Visual
|
||||
} else {
|
||||
Mode::Normal
|
||||
};
|
||||
|
|
|
@ -261,8 +261,9 @@ impl NeovimConnection {
|
|||
let mode = match nvim_mode_text.as_ref() {
|
||||
"i" => Some(Mode::Insert),
|
||||
"n" => Some(Mode::Normal),
|
||||
"v" => Some(Mode::Visual { line: false }),
|
||||
"V" => Some(Mode::Visual { line: true }),
|
||||
"v" => Some(Mode::Visual),
|
||||
"V" => Some(Mode::VisualLine),
|
||||
"CTRL-V" => Some(Mode::VisualBlock),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
@ -270,7 +271,7 @@ impl NeovimConnection {
|
|||
// Zed uses the index of the positions between the characters, so we need
|
||||
// to add one to the end in visual mode.
|
||||
match mode {
|
||||
Some(Mode::Visual { .. }) => {
|
||||
Some(Mode::Visual) | Some(Mode::VisualLine) | Some(Mode::VisualBlock) => {
|
||||
if selection_col > cursor_col {
|
||||
let selection_line_length =
|
||||
self.read_position("echo strlen(getline(line('v')))").await;
|
||||
|
|
|
@ -164,7 +164,7 @@ impl Vim {
|
|||
let newest_selection_empty = editor.selections.newest::<usize>(cx).is_empty();
|
||||
|
||||
if editor_mode == EditorMode::Full && !newest_selection_empty {
|
||||
self.switch_mode(Mode::Visual { line: false }, true, cx);
|
||||
self.switch_mode(Mode::Visual, true, cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,7 @@ impl Vim {
|
|||
}
|
||||
Some(Operator::Replace) => match Vim::read(cx).state.mode {
|
||||
Mode::Normal => normal_replace(text, cx),
|
||||
Mode::Visual { .. } => visual_replace(text, cx),
|
||||
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_replace(text, cx),
|
||||
_ => Vim::update(cx, |vim, cx| vim.clear_operator(cx)),
|
||||
},
|
||||
_ => {}
|
||||
|
@ -317,7 +317,7 @@ impl Vim {
|
|||
editor.set_clip_at_line_ends(state.clip_at_line_ends(), cx);
|
||||
editor.set_collapse_matches(true);
|
||||
editor.set_input_enabled(!state.vim_controlled());
|
||||
editor.selections.line_mode = matches!(state.mode, Mode::Visual { line: true });
|
||||
editor.selections.line_mode = matches!(state.mode, Mode::VisualLine);
|
||||
let context_layer = state.keymap_context_layer();
|
||||
editor.set_keymap_context_layer::<Self>(context_layer, cx);
|
||||
} else {
|
||||
|
@ -368,7 +368,7 @@ impl Setting for VimModeSetting {
|
|||
fn local_selections_changed(newest_empty: bool, cx: &mut WindowContext) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
if vim.enabled && vim.state.mode == Mode::Normal && !newest_empty {
|
||||
vim.switch_mode(Mode::Visual { line: false }, false, cx)
|
||||
vim.switch_mode(Mode::Visual, false, cx)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -138,10 +138,10 @@ pub fn visual_object(object: Object, cx: &mut WindowContext) {
|
|||
|
||||
pub fn toggle_visual(_: &mut Workspace, _: &ToggleVisual, cx: &mut ViewContext<Workspace>) {
|
||||
Vim::update(cx, |vim, cx| match vim.state.mode {
|
||||
Mode::Normal | Mode::Insert | Mode::Visual { line: true } => {
|
||||
vim.switch_mode(Mode::Visual { line: false }, false, cx);
|
||||
Mode::Normal | Mode::Insert | Mode::VisualLine | Mode::VisualBlock => {
|
||||
vim.switch_mode(Mode::Visual, false, cx);
|
||||
}
|
||||
Mode::Visual { line: false } => {
|
||||
Mode::Visual => {
|
||||
vim.switch_mode(Mode::Normal, false, cx);
|
||||
}
|
||||
})
|
||||
|
@ -153,10 +153,10 @@ pub fn toggle_visual_line(
|
|||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
Vim::update(cx, |vim, cx| match vim.state.mode {
|
||||
Mode::Normal | Mode::Insert | Mode::Visual { line: false } => {
|
||||
vim.switch_mode(Mode::Visual { line: true }, false, cx);
|
||||
Mode::Normal | Mode::Insert | Mode::Visual | Mode::VisualBlock => {
|
||||
vim.switch_mode(Mode::VisualLine, false, cx);
|
||||
}
|
||||
Mode::Visual { line: true } => {
|
||||
Mode::VisualLine => {
|
||||
vim.switch_mode(Mode::Normal, false, cx);
|
||||
}
|
||||
})
|
||||
|
@ -701,7 +701,7 @@ mod test {
|
|||
The quick brown
|
||||
fox «jumpsˇ» over
|
||||
the lazy dog"},
|
||||
Mode::Visual { line: false },
|
||||
Mode::Visual,
|
||||
);
|
||||
cx.simulate_keystroke("y");
|
||||
cx.set_state(
|
||||
|
@ -725,7 +725,7 @@ mod test {
|
|||
The quick brown
|
||||
fox ju«mˇ»ps over
|
||||
the lazy dog"},
|
||||
Mode::Visual { line: true },
|
||||
Mode::VisualLine,
|
||||
);
|
||||
cx.simulate_keystroke("d");
|
||||
cx.assert_state(
|
||||
|
@ -738,7 +738,7 @@ mod test {
|
|||
indoc! {"
|
||||
The quick brown
|
||||
the «lazyˇ» dog"},
|
||||
Mode::Visual { line: false },
|
||||
Mode::Visual,
|
||||
);
|
||||
cx.simulate_keystroke("p");
|
||||
cx.assert_state(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue