From f575eac1dece4a0bdf46c5c58312c9b3f68e1b65 Mon Sep 17 00:00:00 2001
From: gwenn <gtreguier@gmail.com>
Date: Sun, 26 Mar 2017 20:23:23 +0200
Subject: [PATCH] Improve kill ring related code

---
 src/keymap.rs    | 10 ++++++++++
 src/kill_ring.rs |  6 +++---
 src/lib.rs       | 37 +++++--------------------------------
 3 files changed, 18 insertions(+), 35 deletions(-)

diff --git a/src/keymap.rs b/src/keymap.rs
index e39db68f..fca6cc7e 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -45,6 +45,16 @@ pub enum Cmd {
 }
 
 impl Cmd {
+    pub fn should_reset_kill_ring(&self) -> bool {
+        match *self {
+            Cmd::Kill(Movement::BackwardChar(_)) |
+            Cmd::Kill(Movement::ForwardChar(_)) => true,
+            Cmd::ClearScreen | Cmd::Kill(_) | Cmd::Noop | Cmd::Suspend | Cmd::Yank(_, _) |
+            Cmd::YankPop => false,
+            _ => true,
+        }
+    }
+
     fn is_repeatable_change(&self) -> bool {
         match *self {
             Cmd::Insert(_, _) => true,
diff --git a/src/kill_ring.rs b/src/kill_ring.rs
index cbbdbfbe..635cb4f5 100644
--- a/src/kill_ring.rs
+++ b/src/kill_ring.rs
@@ -15,7 +15,9 @@ pub enum Mode {
 
 pub struct KillRing {
     slots: Vec<String>,
+    // where we are in the kill ring
     index: usize,
+    // whether or not the last command was a kill or a yank
     last_action: Action,
 }
 
@@ -44,9 +46,7 @@ impl KillRing {
                 }
                 match dir {
                     Mode::Append => self.slots[self.index].push_str(text),
-                    Mode::Prepend => {
-                        self.slots[self.index] = String::from(text) + &self.slots[self.index]
-                    }
+                    Mode::Prepend => self.slots[self.index].insert_str(0, text),
                 };
             }
             _ => {
diff --git a/src/lib.rs b/src/lib.rs
index 53851a28..db0c4329 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -863,11 +863,14 @@ fn readline_edit<C: Completer>(prompt: &str,
         let rc = s.next_cmd(&mut rdr);
         let mut cmd = try!(rc);
 
+        if cmd.should_reset_kill_ring() {
+            editor.reset_kill_ring();
+        }
+
         // autocomplete
         if cmd == Cmd::Complete && completer.is_some() {
             let next = try!(complete_line(&mut rdr, &mut s, completer.unwrap(), &editor.config));
             if next.is_some() {
-                editor.kill_ring.reset();
                 cmd = next.unwrap();
             } else {
                 continue;
@@ -875,11 +878,9 @@ fn readline_edit<C: Completer>(prompt: &str,
         }
 
         if let Cmd::SelfInsert(n, c) = cmd {
-            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;
         }
@@ -896,31 +897,25 @@ fn readline_edit<C: Completer>(prompt: &str,
 
         match cmd {
             Cmd::Move(Movement::BeginningOfLine) => {
-                editor.kill_ring.reset();
                 // Move to the beginning of line.
                 try!(edit_move_home(&mut s))
             }
             Cmd::Move(Movement::ViFirstPrint) => {
-                editor.kill_ring.reset();
                 try!(edit_move_home(&mut s));
                 try!(edit_move_to_next_word(&mut s, At::Start, Word::Big, 1))
             }
             Cmd::Move(Movement::BackwardChar(n)) => {
-                editor.kill_ring.reset();
                 // Move back a character.
                 try!(edit_move_backward(&mut s, n))
             }
             Cmd::Kill(Movement::ForwardChar(n)) => {
-                editor.kill_ring.reset();
                 // Delete (forward) one character at point.
                 try!(edit_delete(&mut s, n))
             }
             Cmd::Replace(n, c) => {
-                editor.kill_ring.reset();
                 try!(edit_replace_char(&mut s, c, n));
             }
             Cmd::EndOfFile => {
-                editor.kill_ring.reset();
                 if !s.edit_state.is_emacs_mode() && !s.line.is_empty() {
                     try!(edit_move_end(&mut s));
                     break;
@@ -931,17 +926,14 @@ fn readline_edit<C: Completer>(prompt: &str,
                 }
             }
             Cmd::Move(Movement::EndOfLine) => {
-                editor.kill_ring.reset();
                 // Move to the end of line.
                 try!(edit_move_end(&mut s))
             }
             Cmd::Move(Movement::ForwardChar(n)) => {
-                editor.kill_ring.reset();
                 // Move forward a character.
                 try!(edit_move_forward(&mut s, n))
             }
             Cmd::Kill(Movement::BackwardChar(n)) => {
-                editor.kill_ring.reset();
                 // Delete one character backward.
                 try!(edit_backspace(&mut s, n))
             }
@@ -963,17 +955,14 @@ fn readline_edit<C: Completer>(prompt: &str,
                 try!(s.refresh_line())
             }
             Cmd::NextHistory => {
-                editor.kill_ring.reset();
                 // Fetch the next command from the history list.
                 try!(edit_history_next(&mut s, &editor.history, false))
             }
             Cmd::PreviousHistory => {
-                editor.kill_ring.reset();
                 // Fetch the previous command from the history list.
                 try!(edit_history_next(&mut s, &editor.history, true))
             }
             Cmd::TransposeChars => {
-                editor.kill_ring.reset();
                 // Exchange the char before cursor with the character at cursor.
                 try!(edit_transpose_chars(&mut s))
             }
@@ -986,7 +975,6 @@ fn readline_edit<C: Completer>(prompt: &str,
             #[cfg(unix)]
             Cmd::QuotedInsert => {
                 // Quoted insert
-                editor.kill_ring.reset();
                 let c = try!(rdr.next_char());
                 try!(edit_insert(&mut s, c, 1)) // FIXME
             }
@@ -997,7 +985,6 @@ fn readline_edit<C: Completer>(prompt: &str,
                 }
             }
             Cmd::ViYankTo(mvt) => {
-                editor.kill_ring.reset();
                 if let Some(text) = s.line.copy(mvt) {
                     editor.kill_ring.kill(&text, Mode::Append)
                 }
@@ -1005,7 +992,6 @@ fn readline_edit<C: Completer>(prompt: &str,
             // TODO CTRL-_ // undo
             Cmd::AcceptLine => {
                 // Accept the line regardless of where the cursor is.
-                editor.kill_ring.reset();
                 try!(edit_move_end(&mut s));
                 break;
             }
@@ -1017,22 +1003,18 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::BeginningOfHistory => {
                 // move to first entry in history
-                editor.kill_ring.reset();
                 try!(edit_history(&mut s, &editor.history, true))
             }
             Cmd::EndOfHistory => {
                 // move to last entry in history
-                editor.kill_ring.reset();
                 try!(edit_history(&mut s, &editor.history, false))
             }
             Cmd::Move(Movement::BackwardWord(n, word_def)) => {
                 // move backwards one word
-                editor.kill_ring.reset();
                 try!(edit_move_to_prev_word(&mut s, word_def, n))
             }
             Cmd::CapitalizeWord => {
                 // capitalize word after point
-                editor.kill_ring.reset();
                 try!(edit_word(&mut s, WordAction::CAPITALIZE))
             }
             Cmd::Kill(Movement::ForwardWord(n, at, word_def)) => {
@@ -1043,22 +1025,18 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Move(Movement::ForwardWord(n, at, word_def)) => {
                 // move forwards one word
-                editor.kill_ring.reset();
                 try!(edit_move_to_next_word(&mut s, at, word_def, n))
             }
             Cmd::DowncaseWord => {
                 // lowercase word after point
-                editor.kill_ring.reset();
                 try!(edit_word(&mut s, WordAction::LOWERCASE))
             }
             Cmd::TransposeWords(n) => {
                 // transpose words
-                editor.kill_ring.reset();
                 try!(edit_transpose_words(&mut s, n))
             }
             Cmd::UpcaseWord => {
                 // uppercase word after point
-                editor.kill_ring.reset();
                 try!(edit_word(&mut s, WordAction::UPPERCASE))
             }
             Cmd::YankPop => {
@@ -1067,17 +1045,13 @@ fn readline_edit<C: Completer>(prompt: &str,
                     try!(edit_yank_pop(&mut s, yank_size, text))
                 }
             }
-            Cmd::Move(Movement::ViCharSearch(n, cs)) => {
-                editor.kill_ring.reset();
-                try!(edit_move_to(&mut s, cs, n))
-            }
+            Cmd::Move(Movement::ViCharSearch(n, cs)) => try!(edit_move_to(&mut s, cs, n)),
             Cmd::Kill(Movement::ViCharSearch(n, cs)) => {
                 if let Some(text) = try!(edit_delete_to(&mut s, cs, n)) {
                     editor.kill_ring.kill(&text, Mode::Append)
                 }
             }
             Cmd::Interrupt => {
-                editor.kill_ring.reset();
                 return Err(error::ReadlineError::Interrupted);
             }
             #[cfg(unix)]
@@ -1090,7 +1064,6 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Noop => {}
             _ => {
-                editor.kill_ring.reset();
                 // Ignore the character typed.
             }
         }
-- 
GitLab