implemented quote/delimiter text objects

This commit is contained in:
2025-06-09 02:29:34 -04:00
parent 2c14e4c202
commit ff0207a27f
5 changed files with 871 additions and 221 deletions

View File

@@ -6,7 +6,7 @@ use unicode_segmentation::UnicodeSegmentation;
use super::keys::{KeyCode as K, KeyEvent as E, ModKeys as M};
use super::linebuf::CharClass;
use super::vicmd::{Anchor, Bound, Dest, Direction, Motion, MotionCmd, RegisterName, TextObj, To, Verb, VerbCmd, ViCmd, Word};
use super::vicmd::{Anchor, Bound, CmdFlags, Dest, Direction, Motion, MotionCmd, RegisterName, TextObj, To, Verb, VerbCmd, ViCmd, Word};
use crate::prelude::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -82,7 +82,8 @@ impl ViInsert {
self
}
pub fn register_and_return(&mut self) -> Option<ViCmd> {
let cmd = self.take_cmd();
let mut cmd = self.take_cmd();
cmd.normalize_counts();
self.register_cmd(&cmd);
Some(cmd)
}
@@ -188,19 +189,11 @@ impl ViReplace {
self
}
pub fn register_and_return(&mut self) -> Option<ViCmd> {
let cmd = self.take_cmd();
let mut cmd = self.take_cmd();
cmd.normalize_counts();
self.register_cmd(&cmd);
Some(cmd)
}
pub fn ctrl_w_is_undo(&self) -> bool {
let insert_count = self.cmds.iter().filter(|cmd| {
matches!(cmd.verb(),Some(VerbCmd(1, Verb::ReplaceChar(_))))
}).count();
let backspace_count = self.cmds.iter().filter(|cmd| {
matches!(cmd.verb(),Some(VerbCmd(1, Verb::Delete)))
}).count();
insert_count > backspace_count
}
pub fn register_cmd(&mut self, cmd: &ViCmd) {
self.cmds.push(cmd.clone())
}
@@ -218,14 +211,9 @@ impl ViMode for ViReplace {
self.register_and_return()
}
E(K::Char('W'), M::CTRL) => {
if self.ctrl_w_is_undo() {
self.pending_cmd.set_verb(VerbCmd(1,Verb::Undo));
self.cmds.clear();
Some(self.take_cmd())
} else {
self.pending_cmd.set_motion(MotionCmd(1, Motion::WordMotion(To::Start, Word::Normal, Direction::Backward)));
self.register_and_return()
}
self.pending_cmd.set_verb(VerbCmd(1, Verb::Delete));
self.pending_cmd.set_motion(MotionCmd(1, Motion::WordMotion(To::Start, Word::Normal, Direction::Backward)));
self.register_and_return()
}
E(K::Char('H'), M::CTRL) |
E(K::Backspace, M::NONE) => {
@@ -280,6 +268,7 @@ impl ViMode for ViReplace {
#[derive(Default,Debug)]
pub struct ViNormal {
pending_seq: String,
pending_flags: CmdFlags,
}
impl ViNormal {
@@ -292,6 +281,9 @@ impl ViNormal {
pub fn take_cmd(&mut self) -> String {
std::mem::take(&mut self.pending_seq)
}
pub fn flags(&self) -> CmdFlags {
self.pending_flags
}
#[allow(clippy::unnecessary_unwrap)]
fn validate_combination(&self, verb: Option<&Verb>, motion: Option<&Motion>) -> CmdState {
if verb.is_none() {
@@ -337,6 +329,12 @@ impl ViNormal {
self.pending_seq.push(ch);
let mut chars = self.pending_seq.chars().peekable();
/*
* Parse the register
*
* Registers can be any letter a-z or A-Z.
* While uncommon, it is possible to give a count to a register name.
*/
let register = 'reg_parse: {
let mut chars_clone = chars.clone();
let count = self.parse_count(&mut chars_clone);
@@ -345,7 +343,7 @@ impl ViNormal {
break 'reg_parse RegisterName::default()
};
let Some(reg_name) = chars_clone.next() else {
let Some(reg_name) = chars_clone.next() else {
return None // Pending register name
};
match reg_name {
@@ -358,6 +356,17 @@ impl ViNormal {
RegisterName::new(Some(reg_name), count)
};
/*
* We will now parse the verb
* If we hit an invalid sequence, we will call 'return self.quit_parse()'
* self.quit_parse() will clear the pending command and return None
*
* If we hit an incomplete sequence, we will simply return None.
* returning None leaves the pending sequence where it is
*
* Note that we do use a label here for the block and 'return' values from this scope
* using "break 'verb_parse <value>"
*/
let verb = 'verb_parse: {
let mut chars_clone = chars.clone();
let count = self.parse_count(&mut chars_clone).unwrap_or(1);
@@ -375,7 +384,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(1, Verb::VisualModeSelectLast)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags(),
}
)
}
@@ -412,6 +422,7 @@ impl ViNormal {
verb: Some(VerbCmd(count, Verb::RepeatLast)),
motion: None,
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -421,7 +432,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Delete)),
motion: Some(MotionCmd(1, Motion::ForwardChar)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -431,7 +443,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Delete)),
motion: Some(MotionCmd(1, Motion::BackwardChar)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -441,8 +454,9 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Change)),
motion: Some(MotionCmd(1, Motion::ForwardChar)),
raw_seq: self.take_cmd()
}
raw_seq: self.take_cmd(),
flags: self.flags()
},
)
}
'S' => {
@@ -451,7 +465,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Change)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -476,9 +491,10 @@ impl ViNormal {
return Some(
ViCmd {
register,
verb: Some(VerbCmd(count, Verb::ReplaceChar(ch))),
verb: Some(VerbCmd(1, Verb::ReplaceCharInplace(ch,count as u16))),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -488,7 +504,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::ReplaceMode)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -496,9 +513,10 @@ impl ViNormal {
return Some(
ViCmd {
register,
verb: Some(VerbCmd(count, Verb::ToggleCaseSingle)),
verb: Some(VerbCmd(1, Verb::ToggleCaseInplace(count as u16))),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -508,7 +526,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Undo)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -518,7 +537,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::VisualMode)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -528,7 +548,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::VisualModeLine)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -538,7 +559,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::InsertModeLineBreak(Anchor::After))),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -548,7 +570,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::InsertModeLineBreak(Anchor::Before))),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -558,7 +581,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::InsertMode)),
motion: Some(MotionCmd(1, Motion::ForwardChar)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -568,7 +592,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::InsertMode)),
motion: Some(MotionCmd(1, Motion::EndOfLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -578,7 +603,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::InsertMode)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -588,7 +614,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::InsertMode)),
motion: Some(MotionCmd(1, Motion::BeginningOfFirstWord)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -598,7 +625,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::JoinLines)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -620,7 +648,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Yank)),
motion: Some(MotionCmd(1, Motion::EndOfLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -630,7 +659,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Delete)),
motion: Some(MotionCmd(1, Motion::EndOfLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -640,7 +670,8 @@ impl ViNormal {
register,
verb: Some(VerbCmd(count, Verb::Change)),
motion: Some(MotionCmd(1, Motion::EndOfLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -672,15 +703,6 @@ impl ViNormal {
('~', Some(VerbCmd(_,Verb::ToggleCaseRange))) |
('>', Some(VerbCmd(_,Verb::Indent))) |
('<', Some(VerbCmd(_,Verb::Dedent))) => break 'motion_parse Some(MotionCmd(count, Motion::WholeLine)),
// Exception cases
('w', Some(VerbCmd(_, Verb::Change))) => {
// 'w' usually means 'to the start of the next word'
// e.g. 'dw' deleted to the start of the next word
// however, 'cw' only changes to the end of the current word
// 'caw' is used to change to the start of the next word
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Normal, Direction::Forward)));
}
('W', Some(VerbCmd(_, Verb::Change))) => {
// Same with 'W'
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Big, Direction::Forward)));
@@ -689,47 +711,69 @@ impl ViNormal {
}
match ch {
'g' => {
if let Some(ch) = chars_clone.peek() {
match ch {
'g' => {
chars_clone.next();
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::BeginningOfBuffer))
}
'e' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Normal, Direction::Backward)));
}
'E' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Big, Direction::Backward)));
}
'k' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::ScreenLineUp));
}
'j' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::ScreenLineDown));
}
'_' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::EndOfLastWord));
}
'0' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::BeginningOfScreenLine));
}
'^' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::FirstGraphicalOnScreenLine));
}
_ => return self.quit_parse()
}
} else {
let Some(ch) = chars_clone.peek() else {
break 'motion_parse None
};
match ch {
'g' => {
chars_clone.next();
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::BeginningOfBuffer))
}
'e' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Normal, Direction::Backward)));
}
'E' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Big, Direction::Backward)));
}
'k' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::ScreenLineUp));
}
'j' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::ScreenLineDown));
}
'_' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::EndOfLastWord));
}
'0' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::BeginningOfScreenLine));
}
'^' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::FirstGraphicalOnScreenLine));
}
_ => return self.quit_parse()
}
}
'v' => {
// We got 'v' after a verb
// Instead of normal operations, we will calculate the span based on how visual mode would see it
if self.flags().intersects(CmdFlags::VISUAL | CmdFlags::VISUAL_LINE | CmdFlags::VISUAL_BLOCK) {
// We can't have more than one of these
return self.quit_parse();
}
self.pending_flags |= CmdFlags::VISUAL;
break 'motion_parse None
}
'V' => {
// We got 'V' after a verb
// Instead of normal operations, we will calculate the span based on how visual line mode would see it
if self.flags().intersects(CmdFlags::VISUAL | CmdFlags::VISUAL_LINE | CmdFlags::VISUAL_BLOCK) {
// We can't have more than one of these
// I know vim can technically do this, but it doesn't really make sense to allow it
// since even in vim only the first one given is used
return self.quit_parse();
}
self.pending_flags |= CmdFlags::VISUAL;
break 'motion_parse None
}
// TODO: figure out how to include 'Ctrl+V' here, might need a refactor
'G' => {
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::EndOfBuffer));
@@ -840,6 +884,7 @@ impl ViNormal {
'W' => TextObj::Word(Word::Big),
'"' => TextObj::DoubleQuote,
'\'' => TextObj::SingleQuote,
'`' => TextObj::BacktickQuote,
'(' | ')' | 'b' => TextObj::Paren,
'{' | '}' | 'B' => TextObj::Brace,
'[' | ']' => TextObj::Bracket,
@@ -868,7 +913,8 @@ impl ViNormal {
register,
verb,
motion,
raw_seq: std::mem::take(&mut self.pending_seq)
raw_seq: std::mem::take(&mut self.pending_seq),
flags: self.flags()
}
)
}
@@ -885,7 +931,7 @@ impl ViNormal {
impl ViMode for ViNormal {
fn handle_key(&mut self, key: E) -> Option<ViCmd> {
match key {
let mut cmd = match key {
E(K::Char(ch), M::NONE) => self.try_parse(ch),
E(K::Backspace, M::NONE) => {
Some(ViCmd {
@@ -893,6 +939,7 @@ impl ViMode for ViNormal {
verb: None,
motion: Some(MotionCmd(1, Motion::BackwardChar)),
raw_seq: "".into(),
flags: self.flags()
})
}
E(K::Char('R'), M::CTRL) => {
@@ -903,7 +950,8 @@ impl ViMode for ViNormal {
register: RegisterName::default(),
verb: Some(VerbCmd(count,Verb::Redo)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: self.flags()
}
)
}
@@ -919,7 +967,12 @@ impl ViMode for ViNormal {
None
}
}
}
};
if let Some(cmd) = cmd.as_mut() {
cmd.normalize_counts();
};
cmd
}
fn is_repeatable(&self) -> bool {
@@ -1051,7 +1104,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(1, Verb::VisualModeSelectLast)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1061,7 +1115,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(1, Verb::Rot13)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1078,6 +1133,7 @@ impl ViVisual {
verb: Some(VerbCmd(count, Verb::RepeatLast)),
motion: None,
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1092,6 +1148,7 @@ impl ViVisual {
verb: Some(VerbCmd(1, Verb::Delete)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1101,7 +1158,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(1, Verb::Yank)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1111,7 +1169,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(1, Verb::Delete)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1123,6 +1182,7 @@ impl ViVisual {
verb: Some(VerbCmd(1, Verb::Change)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1133,6 +1193,7 @@ impl ViVisual {
verb: Some(VerbCmd(1, Verb::Indent)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1143,6 +1204,7 @@ impl ViVisual {
verb: Some(VerbCmd(1, Verb::Dedent)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1153,6 +1215,7 @@ impl ViVisual {
verb: Some(VerbCmd(1, Verb::Equalize)),
motion: Some(MotionCmd(1, Motion::WholeLine)),
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1168,7 +1231,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(1, Verb::ReplaceChar(ch))),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1178,7 +1242,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(1, Verb::ToggleCaseRange)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1188,7 +1253,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(count, Verb::ToLower)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1198,7 +1264,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(count, Verb::ToUpper)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1209,7 +1276,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(count, Verb::SwapVisualAnchor)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1219,7 +1287,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(count, Verb::InsertMode)),
motion: Some(MotionCmd(1, Motion::ForwardChar)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1229,7 +1298,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(count, Verb::InsertMode)),
motion: Some(MotionCmd(1, Motion::BeginningOfLine)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1239,7 +1309,8 @@ impl ViVisual {
register,
verb: Some(VerbCmd(count, Verb::JoinLines)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1264,7 +1335,8 @@ impl ViVisual {
register,
verb: Some(verb),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
})
}
@@ -1294,18 +1366,22 @@ impl ViVisual {
break 'motion_parse Some(MotionCmd(count, Motion::BeginningOfBuffer))
}
'e' => {
chars_clone.next();
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Normal, Direction::Backward)));
}
'E' => {
chars_clone.next();
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::WordMotion(To::End, Word::Big, Direction::Backward)));
}
'k' => {
chars_clone.next();
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::ScreenLineUp));
}
'j' => {
chars_clone.next();
chars = chars_clone;
break 'motion_parse Some(MotionCmd(count, Motion::ScreenLineDown));
}
@@ -1417,6 +1493,7 @@ impl ViVisual {
'W' => TextObj::Word(Word::Big),
'"' => TextObj::DoubleQuote,
'\'' => TextObj::SingleQuote,
'`' => TextObj::BacktickQuote,
'(' | ')' | 'b' => TextObj::Paren,
'{' | '}' | 'B' => TextObj::Brace,
'[' | ']' => TextObj::Bracket,
@@ -1445,7 +1522,8 @@ impl ViVisual {
register,
verb,
motion,
raw_seq: std::mem::take(&mut self.pending_seq)
raw_seq: std::mem::take(&mut self.pending_seq),
flags: CmdFlags::empty()
}
)
}
@@ -1462,7 +1540,7 @@ impl ViVisual {
impl ViMode for ViVisual {
fn handle_key(&mut self, key: E) -> Option<ViCmd> {
match key {
let mut cmd = match key {
E(K::Char(ch), M::NONE) => self.try_parse(ch),
E(K::Backspace, M::NONE) => {
Some(ViCmd {
@@ -1470,6 +1548,7 @@ impl ViMode for ViVisual {
verb: None,
motion: Some(MotionCmd(1, Motion::BackwardChar)),
raw_seq: "".into(),
flags: CmdFlags::empty()
})
}
E(K::Char('R'), M::CTRL) => {
@@ -1480,7 +1559,8 @@ impl ViMode for ViVisual {
register: RegisterName::default(),
verb: Some(VerbCmd(count,Verb::Redo)),
motion: None,
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
}
)
}
@@ -1490,7 +1570,8 @@ impl ViMode for ViVisual {
register: Default::default(),
verb: Some(VerbCmd(1, Verb::NormalMode)),
motion: Some(MotionCmd(1, Motion::Null)),
raw_seq: self.take_cmd()
raw_seq: self.take_cmd(),
flags: CmdFlags::empty()
})
}
_ => {
@@ -1501,7 +1582,12 @@ impl ViMode for ViVisual {
None
}
}
}
};
if let Some(cmd) = cmd.as_mut() {
cmd.normalize_counts();
};
cmd
}
fn is_repeatable(&self) -> bool {