From 7fbe3530156b4aa732b8927ab53da085c7715db5 Mon Sep 17 00:00:00 2001
From: gwenn <gtreguier@gmail.com>
Date: Sat, 25 Feb 2017 10:53:24 +0100
Subject: [PATCH] Vi repeat char search

---
 README.md     |  3 +++
 src/keymap.rs | 31 +++++++++++++++++++++++++++++--
 2 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 5787912e..1856588d 100644
--- a/README.md
+++ b/README.md
@@ -118,6 +118,9 @@ Meta-Y       | See Ctrl-Y
 Meta-BackSpace | Kill from the start of the current word, or, if between words, to the start of the previous word
 
 [Readline Emacs Editing Mode Cheat Sheet](http://www.catonmat.net/download/readline-emacs-editing-mode-cheat-sheet.pdf)
+
+[Readline VI Editing Mode Cheat Sheet](http://www.catonmat.net/download/bash-vi-editing-mode-cheat-sheet.pdf)
+
 [Terminal codes (ANSI/VT100)](http://wiki.bash-hackers.org/scripting/terminalcodes)
 
 ## ToDo
diff --git a/src/keymap.rs b/src/keymap.rs
index 6881988f..5f6b7488 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -77,6 +77,17 @@ pub enum CharSearch {
     BackwardAfter(char),
 }
 
+impl CharSearch {
+    fn opposite(&self) -> CharSearch {
+        match *self {
+            CharSearch::Forward(c) => CharSearch::Backward(c),
+            CharSearch::ForwardBefore(c) => CharSearch::BackwardAfter(c),
+            CharSearch::Backward(c) => CharSearch::Forward(c),
+            CharSearch::BackwardAfter(c) => CharSearch::ForwardBefore(c),
+        }
+    }
+}
+
 pub struct EditState {
     mode: EditMode,
     // Vi Command/Alternate, Insert/Input mode
@@ -84,6 +95,7 @@ pub struct EditState {
     // 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
 }
 
 #[derive(Debug, Clone, PartialEq)]
@@ -105,6 +117,7 @@ impl EditState {
             insert: true,
             num_args: 0,
             last_cmd: Cmd::Noop,
+            last_char_search: None,
         }
     }
 
@@ -331,6 +344,18 @@ impl EditState {
                     None => Cmd::Unknown,
                 }
             }
+            KeyPress::Char(';') => {
+                match self.last_char_search {
+                    Some(ref cs) => Cmd::ViCharSearch(n, cs.clone()),
+                    None => Cmd::Noop,
+                }
+            }
+            KeyPress::Char(',') => {
+                match self.last_char_search {
+                    Some(ref cs) => Cmd::ViCharSearch(n, cs.opposite()),
+                    None => Cmd::Noop,
+                }
+            }
             // TODO KeyPress::Char('G') => Cmd::???, Move to the history line n
             KeyPress::Char('p') => Cmd::Yank(n, Anchor::After), // vi-put
             KeyPress::Char('P') => Cmd::Yank(n, Anchor::Before), // vi-put
@@ -479,13 +504,15 @@ impl EditState {
         let ch = try!(rdr.next_key(config.keyseq_timeout()));
         Ok(match ch {
             KeyPress::Char(ch) => {
-                Some(match cmd {
+                let cs = match cmd {
                     'f' => CharSearch::Forward(ch),
                     't' => CharSearch::ForwardBefore(ch),
                     'F' => CharSearch::Backward(ch),
                     'T' => CharSearch::BackwardAfter(ch),
                     _ => unreachable!(),
-                })
+                };
+                self.last_char_search = Some(cs.clone());
+                Some(cs)
             }
             _ => None,
         })
-- 
GitLab