Vi redo
diff --git a/src/keymap.rs b/src/keymap.rs
index ed7cab3..c0299de 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -24,6 +24,7 @@
ForwardChar(RepeatCount),
ForwardSearchHistory,
ForwardWord(RepeatCount, At, Word), // Forward until start/end of word
+ Insert(RepeatCount, String),
Interrupt,
Kill(Movement),
NextHistory,
@@ -45,6 +46,43 @@
YankPop,
}
+impl Cmd {
+ fn is_repeatable_change(&self) -> bool {
+ match *self {
+ Cmd::Insert(_, _) => true,
+ Cmd::Kill(_) => true,
+ Cmd::Replace(_, _) => true,
+ Cmd::SelfInsert(_, _) => true,
+ Cmd::TransposeChars => false, // TODO Validate
+ Cmd::ViYankTo(_) => true,
+ Cmd::Yank(_, _) => true,
+ _ => false,
+ }
+ }
+
+ fn redo(&self, new: Option<RepeatCount>) -> Cmd {
+ match *self {
+ Cmd::Insert(previous, ref text) => {
+ Cmd::Insert(repeat_count(previous, new), text.clone())
+ }
+ Cmd::Kill(ref mvt) => Cmd::Kill(mvt.redo(new)),
+ Cmd::Replace(previous, c) => Cmd::Replace(repeat_count(previous, new), c),
+ Cmd::SelfInsert(previous, c) => Cmd::SelfInsert(repeat_count(previous, new), c),
+ //Cmd::TransposeChars => Cmd::TransposeChars,
+ Cmd::ViYankTo(ref mvt) => Cmd::ViYankTo(mvt.redo(new)),
+ Cmd::Yank(previous, anchor) => Cmd::Yank(repeat_count(previous, new), anchor),
+ _ => unreachable!(),
+ }
+ }
+}
+
+fn repeat_count(previous: RepeatCount, new: Option<RepeatCount>) -> RepeatCount {
+ match new {
+ Some(n) => n,
+ None => previous,
+ }
+}
+
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Word {
// non-blanks characters
@@ -89,14 +127,6 @@
}
}
-pub struct EditState {
- mode: EditMode,
- // Vi Command/Alternate, Insert/Input mode
- insert: bool, // vi only ?
- // numeric arguments: http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC7
- num_args: i16,
- last_char_search: Option<CharSearch>, // vi only
-}
#[derive(Debug, Clone, PartialEq)]
pub enum Movement {
@@ -110,12 +140,44 @@
ForwardChar(RepeatCount),
}
+impl Movement {
+ fn redo(&self, new: Option<RepeatCount>) -> Movement {
+ match *self {
+ Movement::WholeLine => Movement::WholeLine,
+ Movement::BeginningOfLine => Movement::BeginningOfLine,
+ Movement::EndOfLine => Movement::EndOfLine,
+ Movement::BackwardWord(previous, word) => {
+ Movement::BackwardWord(repeat_count(previous, new), word)
+ }
+ Movement::ForwardWord(previous, at, word) => {
+ Movement::ForwardWord(repeat_count(previous, new), at, word)
+ }
+ Movement::ViCharSearch(previous, ref char_search) => {
+ Movement::ViCharSearch(repeat_count(previous, new), char_search.clone())
+ }
+ Movement::BackwardChar(previous) => Movement::BackwardChar(repeat_count(previous, new)),
+ Movement::ForwardChar(previous) => Movement::ForwardChar(repeat_count(previous, new)),
+ }
+ }
+}
+
+pub struct EditState {
+ mode: EditMode,
+ // Vi Command/Alternate, Insert/Input mode
+ insert: bool, // vi only ?
+ // numeric arguments: http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC7
+ num_args: i16,
+ last_cmd: Cmd, // vi only
+ last_char_search: Option<CharSearch>, // vi only
+}
+
impl EditState {
pub fn new(config: &Config) -> EditState {
EditState {
mode: config.edit_mode(),
insert: true,
num_args: 0,
+ last_cmd: Cmd::Noop,
last_char_search: None,
}
}
@@ -276,11 +338,18 @@
if let KeyPress::Char(digit @ '1'...'9') = key {
key = try!(self.vi_arg_digit(rdr, digit));
}
+ let no_num_args = self.num_args == 0;
let n = self.vi_num_args(); // consume them in all cases
let cmd = match key {
KeyPress::Char('$') |
KeyPress::End => Cmd::EndOfLine,
- // TODO KeyPress::Char('.') => ..., // vi-redo
+ KeyPress::Char('.') => { // vi-redo
+ if no_num_args {
+ self.last_cmd.redo(None)
+ } else {
+ self.last_cmd.redo(Some(n))
+ }
+ },
// TODO KeyPress::Char('%') => Cmd::???, Move to the corresponding opening/closing bracket
KeyPress::Char('0') => Cmd::BeginningOfLine,
KeyPress::Char('^') => Cmd::ViFirstPrint,
@@ -407,6 +476,9 @@
_ => self.common(key, n, true),
};
debug!(target: "rustyline", "Vi command: {:?}", cmd);
+ if cmd.is_repeatable_change() {
+ self.update_last_cmd(cmd.clone());
+ }
Ok(cmd)
}
@@ -425,6 +497,9 @@
_ => self.common(key, 1, true),
};
debug!(target: "rustyline", "Vi insert: {:?}", cmd);
+ if cmd.is_repeatable_change() {
+ self.update_last_cmd(cmd.clone());
+ }
Ok(cmd)
}
@@ -608,4 +683,24 @@
num_args.abs() as RepeatCount
}
}
+
+ fn update_last_cmd(&mut self, new: Cmd) {
+ // consecutive char inserts are repeatable not only the last one...
+ if let Cmd::SelfInsert(_, c) = new {
+ match self.last_cmd {
+ Cmd::SelfInsert(_, pc) => {
+ let mut text = String::new();
+ text.push(pc);
+ text.push(c);
+ self.last_cmd = Cmd::Insert(1, text);
+ }
+ Cmd::Insert(_, ref mut text) => {
+ text.push(c);
+ }
+ _ => self.last_cmd = new,
+ }
+ } else {
+ self.last_cmd = new;
+ }
+ }
}
diff --git a/src/lib.rs b/src/lib.rs
index 8fa4bca..3e7050f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -871,6 +871,10 @@
editor.kill_ring.reset();
try!(edit_insert(&mut s, c, n));
continue;
+ } else if let Cmd::Insert(n, text) = cmd {
+ editor.kill_ring.reset();
+ try!(edit_yank(&mut s, &text, Anchor::Before, n));
+ continue;
}
if cmd == Cmd::ReverseSearchHistory {