diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index ae6bc8391e30e1bc61622e23e9f3aad773f4f1a7..f8d04257790baedc625e5e722420e03c16c62861 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -580,18 +580,18 @@ // "q": "vim::AnyQuotes", "q": "vim::MiniQuotes", "|": "vim::VerticalBars", - "(": "vim::Parentheses", + "(": ["vim::Parentheses", { "opening": true }], ")": "vim::Parentheses", "b": "vim::Parentheses", // "b": "vim::AnyBrackets", // "b": "vim::MiniBrackets", - "[": "vim::SquareBrackets", + "[": ["vim::SquareBrackets", { "opening": true }], "]": "vim::SquareBrackets", "r": "vim::SquareBrackets", - "{": "vim::CurlyBrackets", + "{": ["vim::CurlyBrackets", { "opening": true }], "}": "vim::CurlyBrackets", "shift-b": "vim::CurlyBrackets", - "<": "vim::AngleBrackets", + "<": ["vim::AngleBrackets", { "opening": true }], ">": "vim::AngleBrackets", "a": "vim::Argument", "i": "vim::IndentObj", diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index 829e8bf1117fea3dc5d6c98b9c59effbf9c3f4c1..e52ec62eaa9c9aefef4b48ca672d2cc7e43f5a4b 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -302,7 +302,7 @@ struct MiddleOfLine { display_lines: bool, } -/// Finds the next unmatched bracket or delimiter. +/// Finds the next unmatch #[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)] #[action(namespace = vim)] #[serde(deny_unknown_fields)] diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index a65b9d827f180aefbebc209feebaed5362fa149e..0804095c1bb73c1bf918ed39617cbfe420a049e0 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -450,6 +450,7 @@ impl Vim { &mut self, object: Object, times: Option, + is_opening: bool, window: &mut Window, cx: &mut Context, ) { @@ -524,6 +525,7 @@ impl Vim { if self.check_and_move_to_valid_bracket_pair(object, window, cx) { waiting_operator = Some(Operator::ChangeSurrounds { target: Some(object), + is_opening, }); } } diff --git a/crates/vim/src/object.rs b/crates/vim/src/object.rs index 8ae163b17266bf77716d6643495c1b55657f8c5f..73bc67610aa0eb84972e73ad83aa6b060d30b22e 100644 --- a/crates/vim/src/object.rs +++ b/crates/vim/src/object.rs @@ -85,6 +85,41 @@ pub struct CandidateWithRanges { close_range: Range, } +/// Selects text at the same indentation level. +#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)] +#[action(namespace = vim)] +#[serde(deny_unknown_fields)] +struct Parentheses { + #[serde(default)] + opening: bool, +} + +/// Selects text at the same indentation level. +#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)] +#[action(namespace = vim)] +#[serde(deny_unknown_fields)] +struct SquareBrackets { + #[serde(default)] + opening: bool, +} + +/// Selects text at the same indentation level. +#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)] +#[action(namespace = vim)] +#[serde(deny_unknown_fields)] +struct AngleBrackets { + #[serde(default)] + opening: bool, +} +/// Selects text at the same indentation level. +#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)] +#[action(namespace = vim)] +#[serde(deny_unknown_fields)] +struct CurlyBrackets { + #[serde(default)] + opening: bool, +} + fn cover_or_next, Range)>>( candidates: Option, caret: DisplayPoint, @@ -275,18 +310,10 @@ actions!( DoubleQuotes, /// Selects text within vertical bars (pipes). VerticalBars, - /// Selects text within parentheses. - Parentheses, /// Selects text within the nearest brackets. MiniBrackets, /// Selects text within any type of brackets. AnyBrackets, - /// Selects text within square brackets. - SquareBrackets, - /// Selects text within curly brackets. - CurlyBrackets, - /// Selects text within angle brackets. - AngleBrackets, /// Selects a function argument. Argument, /// Selects an HTML/XML tag. @@ -350,17 +377,17 @@ pub fn register(editor: &mut Editor, cx: &mut Context) { Vim::action(editor, cx, |vim, _: &DoubleQuotes, window, cx| { vim.object(Object::DoubleQuotes, window, cx) }); - Vim::action(editor, cx, |vim, _: &Parentheses, window, cx| { - vim.object(Object::Parentheses, window, cx) + Vim::action(editor, cx, |vim, action: &Parentheses, window, cx| { + vim.object_impl(Object::Parentheses, action.is_opening, window, cx) }); - Vim::action(editor, cx, |vim, _: &SquareBrackets, window, cx| { - vim.object(Object::SquareBrackets, window, cx) + Vim::action(editor, cx, |vim, action: &SquareBrackets, window, cx| { + vim.object_impl(Object::SquareBrackets, action.is_opening, window, cx) }); - Vim::action(editor, cx, |vim, _: &CurlyBrackets, window, cx| { - vim.object(Object::CurlyBrackets, window, cx) + Vim::action(editor, cx, |vim, action: &CurlyBrackets, window, cx| { + vim.object_impl(Object::CurlyBrackets, action.is_opening, window, cx) }); - Vim::action(editor, cx, |vim, _: &AngleBrackets, window, cx| { - vim.object(Object::AngleBrackets, window, cx) + Vim::action(editor, cx, |vim, action: &AngleBrackets, window, cx| { + vim.object_impl(Object::AngleBrackets, action.is_opening, window, cx) }); Vim::action(editor, cx, |vim, _: &VerticalBars, window, cx| { vim.object(Object::VerticalBars, window, cx) @@ -394,10 +421,22 @@ pub fn register(editor: &mut Editor, cx: &mut Context) { impl Vim { fn object(&mut self, object: Object, window: &mut Window, cx: &mut Context) { + self.object_impl(object, window, false, cx); + } + + fn object_impl( + &mut self, + object: Object, + window: &mut Window, + is_opening: bool, + cx: &mut Context, + ) { let count = Self::take_count(cx); match self.mode { - Mode::Normal | Mode::HelixNormal => self.normal_object(object, count, window, cx), + Mode::Normal | Mode::HelixNormal => { + self.normal_object(object, count, is_opening, window, cx) + } Mode::Visual | Mode::VisualLine | Mode::VisualBlock | Mode::HelixSelect => { self.visual_object(object, count, window, cx) } diff --git a/crates/vim/src/state.rs b/crates/vim/src/state.rs index 3458a92442a3ec76ebce581bf798fc57509f7d53..c9c0532ee687df06531269a55969c5509ca5d700 100644 --- a/crates/vim/src/state.rs +++ b/crates/vim/src/state.rs @@ -109,6 +109,7 @@ pub enum Operator { }, ChangeSurrounds { target: Option, + is_opening: bool, }, DeleteSurrounds, Mark,