Skip to content

Commit 5dd7e0e

Browse files
authored
Implemented VI mode change inside and delete inside functionality (#844)
* Implemented change in and delete in functionality * only allow certain chars for change in * added < * added clippy feedback * added > mapping for < * make change inside work with left or right brackets * Don't switch to insert mode on an invalid ChangeInside character * Fixed delete case, I was comparing right side twice
1 parent 4d8b8ce commit 5dd7e0e

File tree

2 files changed

+93
-4
lines changed

2 files changed

+93
-4
lines changed

src/edit_mode/vi/command.rs

+85-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,19 @@ where
99
match input.peek() {
1010
Some('d') => {
1111
let _ = input.next();
12-
Some(Command::Delete)
12+
if let Some('i') = input.peek() {
13+
let _ = input.next();
14+
match input.next() {
15+
Some(c)
16+
if is_valid_change_inside_left(c) || is_valid_change_inside_right(c) =>
17+
{
18+
Some(Command::DeleteInside(*c))
19+
}
20+
_ => None,
21+
}
22+
} else {
23+
Some(Command::Delete)
24+
}
1325
}
1426
Some('p') => {
1527
let _ = input.next();
@@ -33,7 +45,19 @@ where
3345
}
3446
Some('c') => {
3547
let _ = input.next();
36-
Some(Command::Change)
48+
if let Some('i') = input.peek() {
49+
let _ = input.next();
50+
match input.next() {
51+
Some(c)
52+
if is_valid_change_inside_left(c) || is_valid_change_inside_right(c) =>
53+
{
54+
Some(Command::ChangeInside(*c))
55+
}
56+
_ => None,
57+
}
58+
} else {
59+
Some(Command::Change)
60+
}
3761
}
3862
Some('x') => {
3963
let _ = input.next();
@@ -107,6 +131,8 @@ pub enum Command {
107131
HistorySearch,
108132
Switchcase,
109133
RepeatLastAction,
134+
ChangeInside(char),
135+
DeleteInside(char),
110136
}
111137

112138
impl Command {
@@ -150,10 +176,44 @@ impl Command {
150176
// Whenever a motion is required to finish the command we must be in visual mode
151177
Self::Delete | Self::Change => vec![ReedlineOption::Edit(EditCommand::CutSelection)],
152178
Self::Incomplete => vec![ReedlineOption::Incomplete],
153-
Command::RepeatLastAction => match &vi_state.previous {
179+
Self::RepeatLastAction => match &vi_state.previous {
154180
Some(event) => vec![ReedlineOption::Event(event.clone())],
155181
None => vec![],
156182
},
183+
Self::ChangeInside(left) if is_valid_change_inside_left(left) => {
184+
let right = bracket_for(left);
185+
vec![
186+
ReedlineOption::Edit(EditCommand::CutLeftBefore(*left)),
187+
ReedlineOption::Edit(EditCommand::CutRightBefore(right)),
188+
]
189+
}
190+
Self::ChangeInside(right) if is_valid_change_inside_right(right) => {
191+
let left = bracket_for(right);
192+
vec![
193+
ReedlineOption::Edit(EditCommand::CutLeftBefore(left)),
194+
ReedlineOption::Edit(EditCommand::CutRightBefore(*right)),
195+
]
196+
}
197+
Self::ChangeInside(_) => {
198+
vec![]
199+
}
200+
Self::DeleteInside(left) if is_valid_change_inside_left(left) => {
201+
let right = bracket_for(left);
202+
vec![
203+
ReedlineOption::Edit(EditCommand::CutLeftBefore(*left)),
204+
ReedlineOption::Edit(EditCommand::CutRightBefore(right)),
205+
]
206+
}
207+
Self::DeleteInside(right) if is_valid_change_inside_right(right) => {
208+
let left = bracket_for(right);
209+
vec![
210+
ReedlineOption::Edit(EditCommand::CutLeftBefore(left)),
211+
ReedlineOption::Edit(EditCommand::CutRightBefore(*right)),
212+
]
213+
}
214+
Self::DeleteInside(_) => {
215+
vec![]
216+
}
157217
}
158218
}
159219

@@ -276,3 +336,25 @@ impl Command {
276336
}
277337
}
278338
}
339+
340+
fn bracket_for(c: &char) -> char {
341+
match *c {
342+
'(' => ')',
343+
'[' => ']',
344+
'{' => '}',
345+
'<' => '>',
346+
')' => '(',
347+
']' => '[',
348+
'}' => '{',
349+
'>' => '<',
350+
_ => *c,
351+
}
352+
}
353+
354+
pub(crate) fn is_valid_change_inside_left(c: &char) -> bool {
355+
matches!(c, '(' | '[' | '{' | '"' | '\'' | '`' | '<')
356+
}
357+
358+
pub(crate) fn is_valid_change_inside_right(c: &char) -> bool {
359+
matches!(c, ')' | ']' | '}' | '"' | '\'' | '`' | '>')
360+
}

src/edit_mode/vi/parser.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::command::{parse_command, Command};
1+
use super::command::{
2+
is_valid_change_inside_left, is_valid_change_inside_right, parse_command, Command,
3+
};
24
use super::motion::{parse_motion, Motion};
35
use crate::{edit_mode::vi::ViMode, EditCommand, ReedlineEvent, Vi};
46
use std::iter::Peekable;
@@ -107,6 +109,11 @@ impl ParsedViSequence {
107109
| (Some(Command::SubstituteCharWithInsert), ParseResult::Incomplete)
108110
| (Some(Command::HistorySearch), ParseResult::Incomplete)
109111
| (Some(Command::Change), ParseResult::Valid(_)) => Some(ViMode::Insert),
112+
(Some(Command::ChangeInside(char)), ParseResult::Incomplete)
113+
if is_valid_change_inside_left(char) || is_valid_change_inside_right(char) =>
114+
{
115+
Some(ViMode::Insert)
116+
}
110117
(Some(Command::Delete), ParseResult::Incomplete) => Some(ViMode::Normal),
111118
_ => None,
112119
}

0 commit comments

Comments
 (0)