diff --git a/examples/example.rs b/examples/example.rs
index 25c6ad3ace9801cc5e5f9c5e5f99577d8f73d693..9f047c64d9e7fd86851017cda8519e96977383c7 100644
--- a/examples/example.rs
+++ b/examples/example.rs
@@ -70,7 +70,7 @@ impl log::Log for Logger {
 
 fn init_logger() -> Result<(), SetLoggerError> {
     log::set_logger(|max_log_level| {
-        max_log_level.set(LogLevelFilter::Info);
-        Box::new(Logger)
-    })
+                        max_log_level.set(LogLevelFilter::Info);
+                        Box::new(Logger)
+                    })
 }
diff --git a/src/history.rs b/src/history.rs
index c4c5e9a9d8b1fdbbea9ced3c0ab78c97e2e0f1ec..054d181ead2b8850467c70b130406b5ee3826669 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -56,7 +56,11 @@ impl History {
             return false;
         }
         if line.as_ref().is_empty() ||
-           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
+           (self.ignore_space &&
+            line.as_ref()
+                .chars()
+                .next()
+                .map_or(true, |c| c.is_whitespace())) {
             return false;
         }
         if self.ignore_dups {
@@ -160,7 +164,10 @@ impl History {
                 index.and_then(|index| Some(start - index))
             }
             Direction::Forward => {
-                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
+                let index = self.entries
+                    .iter()
+                    .skip(start)
+                    .position(|entry| entry.contains(term));
                 index.and_then(|index| Some(index + start))
             }
         }
@@ -260,9 +267,7 @@ mod tests {
 
     #[test]
     fn add() {
-        let config = Config::builder()
-            .history_ignore_space(true)
-            .build();
+        let config = Config::builder().history_ignore_space(true).build();
         let mut history = History::with_config(config);
         assert_eq!(config.max_history_size(), history.max_len);
         assert!(history.add("line1"));
@@ -277,7 +282,7 @@ mod tests {
         let mut history = init();
         history.set_max_len(1);
         assert_eq!(1, history.entries.len());
-        assert_eq!(Some(&"line3".to_string()), history.last());
+        assert_eq!(Some(&"line3".to_owned()), history.last());
     }
 
     #[test]
diff --git a/src/keymap.rs b/src/keymap.rs
index 3287f53552fb0b258adb0a21d8a18f854ac7cf85..a63be00e2f42ff72bc72f48e83150330f1af9384 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -119,6 +119,15 @@ pub enum CharSearch {
 }
 
 impl CharSearch {
+    pub fn is_backward(&self) -> bool {
+        match *self {
+            CharSearch::Forward(_) => false,
+            CharSearch::ForwardBefore(_) => false,
+            CharSearch::Backward(_) => true,
+            CharSearch::BackwardAfter(_) => true,
+        }
+    }
+
     fn opposite(&self) -> CharSearch {
         match *self {
             CharSearch::Forward(c) => CharSearch::Backward(c),
diff --git a/src/kill_ring.rs b/src/kill_ring.rs
index cbbdbfbe721341082ebf377c2e9455ba360f3d9b..cbe2aa12aa5eec5b692014919a9f6152c81ab1e5 100644
--- a/src/kill_ring.rs
+++ b/src/kill_ring.rs
@@ -187,9 +187,9 @@ mod tests {
         kill_ring.reset();
         kill_ring.kill("word2", Mode::Append);
 
-        assert_eq!(Some(&"word2".to_string()), kill_ring.yank());
+        assert_eq!(Some(&"word2".to_owned()), kill_ring.yank());
         assert_eq!(Action::Yank(5), kill_ring.last_action);
-        assert_eq!(Some(&"word2".to_string()), kill_ring.yank());
+        assert_eq!(Some(&"word2".to_owned()), kill_ring.yank());
         assert_eq!(Action::Yank(5), kill_ring.last_action);
     }
 
@@ -202,8 +202,8 @@ mod tests {
 
         assert_eq!(None, kill_ring.yank_pop());
         kill_ring.yank();
-        assert_eq!(Some((9, &"word1".to_string())), kill_ring.yank_pop());
-        assert_eq!(Some((5, &"longword2".to_string())), kill_ring.yank_pop());
-        assert_eq!(Some((9, &"word1".to_string())), kill_ring.yank_pop());
+        assert_eq!(Some((9, &"word1".to_owned())), kill_ring.yank_pop());
+        assert_eq!(Some((5, &"longword2".to_owned())), kill_ring.yank_pop());
+        assert_eq!(Some((9, &"word1".to_owned())), kill_ring.yank_pop());
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index c2946c8324ef39ccceabce23b04885d36c5cee12..0718d734d36da0cbd01f36f2ff97df6b519a673f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -43,11 +43,13 @@ mod undo;
 
 mod tty;
 
+use std::cell::RefCell;
 use std::fmt;
 use std::io::{self, Write};
 use std::mem;
 use std::path::Path;
 use std::result;
+use std::rc::Rc;
 use unicode_segmentation::UnicodeSegmentation;
 use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
 
@@ -55,7 +57,7 @@ use tty::{RawMode, RawReader, Terminal, Term};
 
 use completion::{Completer, longest_common_prefix};
 use history::{Direction, History};
-use line_buffer::{LineBuffer, MAX_LINE, WordAction};
+use line_buffer::{ChangeListener, LineBuffer, MAX_LINE, WordAction};
 use keymap::{Anchor, At, CharSearch, Cmd, EditState, Movement, RepeatCount, Word};
 use kill_ring::{Mode, KillRing};
 pub use config::{CompletionType, Config, EditMode, HistoryDuplicates};
@@ -78,7 +80,6 @@ struct State<'out, 'prompt> {
     term: Terminal, // terminal
     byte_buffer: [u8; 4],
     edit_state: EditState,
-    changes: Changeset,
 }
 
 #[derive(Copy, Clone, Debug, Default)]
@@ -110,7 +111,6 @@ impl<'out, 'prompt> State<'out, 'prompt> {
             term: term,
             byte_buffer: [0; 4],
             edit_state: EditState::new(config),
-            changes: Changeset::new(),
         }
     }
 
@@ -128,6 +128,7 @@ impl<'out, 'prompt> State<'out, 'prompt> {
 
     fn snapshot(&mut self) {
         mem::swap(&mut self.line, &mut self.snapshot);
+        // TODO swap ChangeListener ?
     }
 
     fn backup(&mut self) {
@@ -209,9 +210,9 @@ impl<'out, 'prompt> State<'out, 'prompt> {
         info.dwCursorPosition.Y -= self.cursor.row as i16;
         try!(self.term.set_console_cursor_position(info.dwCursorPosition));
         let mut _count = 0;
-        try!(self.term
-            .fill_console_output_character((info.dwSize.X * (self.old_rows as i16 + 1)) as u32,
-                                           info.dwCursorPosition));
+        try!(self.term.fill_console_output_character((info.dwSize.X * (self.old_rows as i16 + 1)) as
+                                                     u32,
+                                                     info.dwCursorPosition));
         let mut ab = String::new();
         // display the prompt
         ab.push_str(prompt); // TODO handle ansi escape code (SetConsoleTextAttribute)
@@ -419,7 +420,7 @@ fn edit_delete(s: &mut State, n: RepeatCount) -> Result<()> {
 
 /// Backspace implementation.
 fn edit_backspace(s: &mut State, n: RepeatCount) -> Result<()> {
-    if s.line.backspace(n).is_some() {
+    if s.line.backspace(n) {
         s.refresh_line()
     } else {
         Ok(())
@@ -427,22 +428,20 @@ fn edit_backspace(s: &mut State, n: RepeatCount) -> Result<()> {
 }
 
 /// Kill the text from point to the end of the line.
-fn edit_kill_line(s: &mut State) -> Result<Option<String>> {
-    if let Some(text) = s.line.kill_line() {
-        try!(s.refresh_line());
-        Ok(Some(text))
+fn edit_kill_line(s: &mut State) -> Result<()> {
+    if s.line.kill_line() {
+        s.refresh_line()
     } else {
-        Ok(None)
+        Ok(())
     }
 }
 
 /// Kill backward from point to the beginning of the line.
-fn edit_discard_line(s: &mut State) -> Result<Option<String>> {
-    if let Some(text) = s.line.discard_line() {
-        try!(s.refresh_line());
-        Ok(Some(text))
+fn edit_discard_line(s: &mut State) -> Result<()> {
+    if s.line.discard_line() {
+        s.refresh_line()
     } else {
-        Ok(None)
+        Ok(())
     }
 }
 
@@ -465,12 +464,11 @@ fn edit_move_to_prev_word(s: &mut State, word_def: Word, n: RepeatCount) -> Resu
 
 /// Delete the previous word, maintaining the cursor at the start of the
 /// current word.
-fn edit_delete_prev_word(s: &mut State, word_def: Word, n: RepeatCount) -> Result<Option<String>> {
-    if let Some(text) = s.line.delete_prev_word(word_def, n) {
-        try!(s.refresh_line());
-        Ok(Some(text))
+fn edit_delete_prev_word(s: &mut State, word_def: Word, n: RepeatCount) -> Result<()> {
+    if s.line.delete_prev_word(word_def, n) {
+        s.refresh_line()
     } else {
-        Ok(None)
+        Ok(())
     }
 }
 
@@ -491,25 +489,19 @@ fn edit_move_to(s: &mut State, cs: CharSearch, n: RepeatCount) -> Result<()> {
 }
 
 /// Kill from the cursor to the end of the current word, or, if between words, to the end of the next word.
-fn edit_delete_word(s: &mut State,
-                    at: At,
-                    word_def: Word,
-                    n: RepeatCount)
-                    -> Result<Option<String>> {
-    if let Some(text) = s.line.delete_word(at, word_def, n) {
-        try!(s.refresh_line());
-        Ok(Some(text))
+fn edit_delete_word(s: &mut State, at: At, word_def: Word, n: RepeatCount) -> Result<()> {
+    if s.line.delete_word(at, word_def, n) {
+        s.refresh_line()
     } else {
-        Ok(None)
+        Ok(())
     }
 }
 
-fn edit_delete_to(s: &mut State, cs: CharSearch, n: RepeatCount) -> Result<Option<String>> {
-    if let Some(text) = s.line.delete_to(cs, n) {
-        try!(s.refresh_line());
-        Ok(Some(text))
+fn edit_delete_to(s: &mut State, cs: CharSearch, n: RepeatCount) -> Result<()> {
+    if s.line.delete_to(cs, n) {
+        s.refresh_line()
     } else {
-        Ok(None)
+        Ok(())
     }
 }
 
@@ -849,12 +841,14 @@ fn readline_edit<C: Completer>(prompt: &str,
 
     let mut stdout = editor.term.create_writer();
 
-    editor.kill_ring.reset();
+    editor.reset_kill_ring();
+    editor.clear_changes();
     let mut s = State::new(&mut stdout,
                            editor.term.clone(),
                            &editor.config,
                            prompt,
                            editor.history.len());
+    s.line.bind(Some(editor.listener.clone()));
     try!(s.refresh_line());
 
     let mut rdr = try!(s.term.create_reader(&editor.config));
@@ -867,7 +861,7 @@ fn readline_edit<C: Completer>(prompt: &str,
         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();
+                editor.reset_kill_ring();
                 cmd = next.unwrap();
             } else {
                 continue;
@@ -875,11 +869,11 @@ fn readline_edit<C: Completer>(prompt: &str,
         }
 
         if let Cmd::SelfInsert(n, c) = cmd {
-            editor.kill_ring.reset();
+            editor.reset_kill_ring();
             try!(edit_insert(&mut s, c, n));
             continue;
         } else if let Cmd::Insert(n, text) = cmd {
-            editor.kill_ring.reset();
+            editor.reset_kill_ring();
             try!(edit_yank(&mut s, &text, Anchor::Before, n));
             continue;
         }
@@ -896,31 +890,31 @@ fn readline_edit<C: Completer>(prompt: &str,
 
         match cmd {
             Cmd::BeginningOfLine => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Move to the beginning of line.
                 try!(edit_move_home(&mut s))
             }
             Cmd::ViFirstPrint => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_move_home(&mut s));
                 try!(edit_move_to_next_word(&mut s, At::Start, Word::Big, 1))
             }
             Cmd::BackwardChar(n) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Move back a character.
                 try!(edit_move_backward(&mut s, n))
             }
             Cmd::Kill(Movement::ForwardChar(n)) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Delete (forward) one character at point.
                 try!(edit_delete(&mut s, n))
             }
             Cmd::Replace(n, c) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_replace_char(&mut s, c, n));
             }
             Cmd::EndOfFile => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 if !s.edit_state.is_emacs_mode() && !s.line.is_empty() {
                     try!(edit_move_end(&mut s));
                     break;
@@ -931,31 +925,29 @@ fn readline_edit<C: Completer>(prompt: &str,
                 }
             }
             Cmd::EndOfLine => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Move to the end of line.
                 try!(edit_move_end(&mut s))
             }
             Cmd::ForwardChar(n) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Move forward a character.
                 try!(edit_move_forward(&mut s, n))
             }
             Cmd::Kill(Movement::BackwardChar(n)) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Delete one character backward.
                 try!(edit_backspace(&mut s, n))
             }
             Cmd::Kill(Movement::EndOfLine) => {
                 // Kill the text from point to the end of the line.
-                if let Some(text) = try!(edit_kill_line(&mut s)) {
-                    editor.kill_ring.kill(&text, Mode::Append)
-                }
+                editor.set_kill_ring_mode(Mode::Append);
+                try!(edit_kill_line(&mut s))
             }
             Cmd::Kill(Movement::WholeLine) => {
                 try!(edit_move_home(&mut s));
-                if let Some(text) = try!(edit_kill_line(&mut s)) {
-                    editor.kill_ring.kill(&text, Mode::Append)
-                }
+                editor.set_kill_ring_mode(Mode::Append);
+                try!(edit_kill_line(&mut s))
             }
             Cmd::ClearScreen => {
                 // Clear the screen leaving the current line at the top of the screen.
@@ -963,126 +955,126 @@ fn readline_edit<C: Completer>(prompt: &str,
                 try!(s.refresh_line())
             }
             Cmd::NextHistory => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Fetch the next command from the history list.
                 try!(edit_history_next(&mut s, &editor.history, false))
             }
             Cmd::PreviousHistory => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Fetch the previous command from the history list.
                 try!(edit_history_next(&mut s, &editor.history, true))
             }
             Cmd::TransposeChars => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Exchange the char before cursor with the character at cursor.
                 try!(edit_transpose_chars(&mut s))
             }
             Cmd::Kill(Movement::BeginningOfLine) => {
                 // Kill backward from point to the beginning of the line.
-                if let Some(text) = try!(edit_discard_line(&mut s)) {
-                    editor.kill_ring.kill(&text, Mode::Prepend)
-                }
+                editor.set_kill_ring_mode(Mode::Prepend);
+                try!(edit_discard_line(&mut s))
             }
             #[cfg(unix)]
             Cmd::QuotedInsert => {
                 // Quoted insert
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 let c = try!(rdr.next_char());
                 try!(edit_insert(&mut s, c, 1)) // FIXME
             }
             Cmd::Yank(n, anchor) => {
                 // retrieve (yank) last item killed
-                if let Some(text) = editor.kill_ring.yank() {
+                if let Some(text) = editor.listener.borrow_mut().kill_ring.yank() {
                     try!(edit_yank(&mut s, text, anchor, n))
                 }
             }
             Cmd::ViYankTo(mvt) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 if let Some(text) = s.line.copy(mvt) {
-                    editor.kill_ring.kill(&text, Mode::Append)
+                    editor.kill(&text, Mode::Append)
                 }
             }
             // TODO CTRL-_ // undo
             Cmd::AcceptLine => {
                 // Accept the line regardless of where the cursor is.
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_move_end(&mut s));
                 break;
             }
             Cmd::Kill(Movement::BackwardWord(n, word_def)) => {
                 // kill one word backward (until start of word)
-                if let Some(text) = try!(edit_delete_prev_word(&mut s, word_def, n)) {
-                    editor.kill_ring.kill(&text, Mode::Prepend)
-                }
+                editor.set_kill_ring_mode(Mode::Prepend);
+                try!(edit_delete_prev_word(&mut s, word_def, n))
             }
             Cmd::BeginningOfHistory => {
                 // move to first entry in history
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_history(&mut s, &editor.history, true))
             }
             Cmd::EndOfHistory => {
                 // move to last entry in history
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_history(&mut s, &editor.history, false))
             }
             Cmd::BackwardWord(n, word_def) => {
                 // move backwards one word
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_move_to_prev_word(&mut s, word_def, n))
             }
             Cmd::CapitalizeWord => {
                 // capitalize word after point
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_word(&mut s, WordAction::CAPITALIZE))
             }
             Cmd::Kill(Movement::ForwardWord(n, at, word_def)) => {
                 // kill one word forward (until start/end of word)
-                if let Some(text) = try!(edit_delete_word(&mut s, at, word_def, n)) {
-                    editor.kill_ring.kill(&text, Mode::Append)
-                }
+                editor.set_kill_ring_mode(Mode::Append);
+                try!(edit_delete_word(&mut s, at, word_def, n))
             }
             Cmd::ForwardWord(n, at, word_def) => {
                 // move forwards one word
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_move_to_next_word(&mut s, at, word_def, n))
             }
             Cmd::DowncaseWord => {
                 // lowercase word after point
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_word(&mut s, WordAction::LOWERCASE))
             }
             Cmd::TransposeWords(n) => {
                 // transpose words
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_transpose_words(&mut s, n))
             }
             Cmd::UpcaseWord => {
                 // uppercase word after point
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 try!(edit_word(&mut s, WordAction::UPPERCASE))
             }
             Cmd::YankPop => {
                 // yank-pop
-                if let Some((yank_size, text)) = editor.kill_ring.yank_pop() {
+                if let Some((yank_size, text)) = editor.listener.borrow_mut().kill_ring.yank_pop() {
                     try!(edit_yank_pop(&mut s, yank_size, text))
                 }
             }
             Cmd::ViCharSearch(n, cs) => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 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)
+                if cs.is_backward() {
+                    editor.set_kill_ring_mode(Mode::Prepend);
+                } else {
+                    editor.set_kill_ring_mode(Mode::Append);
                 }
+                try!(edit_delete_to(&mut s, cs, n))
             }
             Cmd::Undo => {
-                if s.changes.undo(&mut s.line) {
+                if editor.undo(&mut s.line) {
                     try!(s.refresh_line());
                 }
             }
             Cmd::Interrupt => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 return Err(error::ReadlineError::Interrupted);
             }
             #[cfg(unix)]
@@ -1095,7 +1087,7 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Noop => {}
             _ => {
-                editor.kill_ring.reset();
+                editor.reset_kill_ring();
                 // Ignore the character typed.
             }
         }
@@ -1138,10 +1130,71 @@ pub struct Editor<C: Completer> {
     term: Terminal,
     history: History,
     completer: Option<C>,
-    kill_ring: KillRing,
+    listener: Rc<RefCell<Listener>>,
     config: Config,
 }
 
+struct Listener {
+    kill_ring: KillRing,
+    mode: Option<Mode>,
+    changes: Changeset, // FIXME useful only during one line edition (versus kill_ring)
+    undoing: bool,
+}
+
+impl Listener {
+    fn new() -> Rc<RefCell<Listener>> {
+        let l = Listener {
+            kill_ring: KillRing::new(60),
+            mode: None,
+            changes: Changeset::new(),
+            undoing: false,
+        };
+        Rc::new(RefCell::new(l))
+    }
+
+    fn reset_kill_ring(&mut self) {
+        self.kill_ring.reset();
+        self.mode = None;
+    }
+    fn set_kill_ring_mode(&mut self, mode: Mode) {
+        self.mode = Some(mode);
+    }
+
+    fn undo(&mut self, line: &mut LineBuffer) -> bool {
+        self.undoing = true;
+        let ok = self.changes.undo(line);
+        self.undoing = false;
+        ok
+    }
+    fn clear_changes(&mut self) {
+        self.changes.clear();
+    }
+}
+impl ChangeListener for Listener {
+    fn insert_char(&mut self, idx: usize, c: char) {
+        if self.undoing {
+            return;
+        }
+        self.changes.insert(idx, c);
+    }
+    fn insert_str(&mut self, idx: usize, string: &str) {
+        if self.undoing {
+            return;
+        }
+        self.changes.insert_str(idx, string);
+    }
+    fn delete(&mut self, idx: usize, string: &str) {
+        if self.mode.is_some() {
+            self.kill_ring.kill(string, self.mode.unwrap());
+            self.mode = None;
+        }
+        if self.undoing {
+            return;
+        }
+        self.changes.delete(idx, string);
+    }
+}
+
 impl<C: Completer> Editor<C> {
     pub fn new() -> Editor<C> {
         Self::with_config(Config::default())
@@ -1153,7 +1206,7 @@ impl<C: Completer> Editor<C> {
             term: term,
             history: History::with_config(config),
             completer: None,
-            kill_ring: KillRing::new(60),
+            listener: Listener::new(),
             config: config,
         }
     }
@@ -1222,6 +1275,23 @@ impl<C: Completer> Editor<C> {
             prompt: prompt,
         }
     }
+
+    fn reset_kill_ring(&self) {
+        self.listener.borrow_mut().reset_kill_ring();
+    }
+    fn set_kill_ring_mode(&self, mode: Mode) {
+        self.listener.borrow_mut().set_kill_ring_mode(mode);
+    }
+    fn kill(&self, text: &str, dir: Mode) {
+        self.listener.borrow_mut().kill_ring.kill(text, dir)
+    }
+
+    fn undo(&self, line: &mut LineBuffer) -> bool {
+        self.listener.borrow_mut().undo(line)
+    }
+    fn clear_changes(&self) {
+        self.listener.borrow_mut().clear_changes()
+    }
 }
 
 impl<C: Completer> fmt::Debug for Editor<C> {
@@ -1267,7 +1337,6 @@ mod test {
     use keymap::{Cmd, EditState};
     use super::{Editor, Position, Result, State};
     use tty::{Terminal, Term};
-    use undo::Changeset;
 
     fn init_state<'out>(out: &'out mut Write,
                         line: &str,
@@ -1280,7 +1349,7 @@ mod test {
             out: out,
             prompt: "",
             prompt_size: Position::default(),
-            line: LineBuffer::init(line, pos),
+            line: LineBuffer::init(line, pos, None),
             cursor: Position::default(),
             cols: cols,
             old_rows: 0,
@@ -1289,7 +1358,6 @@ mod test {
             term: term,
             byte_buffer: [0; 4],
             edit_state: EditState::new(&config),
-            changes: Changeset::new(),
         }
     }
 
@@ -1340,7 +1408,7 @@ mod test {
     struct SimpleCompleter;
     impl Completer for SimpleCompleter {
         fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
-            Ok((0, vec![line.to_string() + "t"]))
+            Ok((0, vec![line.to_owned() + "t"]))
         }
     }
 
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index 56747bc2919d8c9b274439ba80b28a9ac9e27fdd..7d8000da84a8b29d8179797291bd2b4e3951612a 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -1,6 +1,10 @@
 //! Line buffer with current cursor position
+use std::cell::RefCell;
+use std::fmt;
 use std::iter;
 use std::ops::{Deref, Range};
+use std::rc::Rc;
+use std::string::Drain;
 use std_unicode::str::UnicodeStr;
 use unicode_segmentation::UnicodeSegmentation;
 use keymap::{At, CharSearch, Movement, RepeatCount, Word};
@@ -14,10 +18,25 @@ pub enum WordAction {
     UPPERCASE,
 }
 
-#[derive(Debug)]
+pub trait ChangeListener {
+    fn insert_char(&mut self, idx: usize, c: char);
+    fn insert_str(&mut self, idx: usize, string: &str);
+    fn delete(&mut self, idx: usize, string: &str);
+}
+
 pub struct LineBuffer {
     buf: String, // Edited line buffer
     pos: usize, // Current cursor position (byte position)
+    cl: Option<Rc<RefCell<ChangeListener>>>,
+}
+
+impl fmt::Debug for LineBuffer {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("LineBuffer")
+            .field("buf", &self.buf)
+            .field("pos", &self.pos)
+            .finish()
+    }
 }
 
 impl LineBuffer {
@@ -26,17 +45,23 @@ impl LineBuffer {
         LineBuffer {
             buf: String::with_capacity(capacity),
             pos: 0,
+            cl: None,
         }
     }
 
     #[cfg(test)]
-    pub fn init(line: &str, pos: usize) -> LineBuffer {
+    pub fn init(line: &str, pos: usize, cl: Option<Rc<RefCell<ChangeListener>>>) -> LineBuffer {
         let mut lb = Self::with_capacity(MAX_LINE);
         assert!(lb.insert_str(0, line));
         lb.set_pos(pos);
+        lb.cl = cl;
         lb
     }
 
+    pub fn bind(&mut self, cl: Option<Rc<RefCell<ChangeListener>>>) {
+        self.cl = cl;
+    }
+
     /// Extracts a string slice containing the entire buffer.
     pub fn as_str(&self) -> &str {
         &self.buf
@@ -68,25 +93,27 @@ impl LineBuffer {
     /// Set line content (`buf`) and cursor position (`pos`).
     pub fn update(&mut self, buf: &str, pos: usize) {
         assert!(pos <= buf.len());
-        self.buf.clear();
+        let end = self.len();
+        self.drain(0..end);
         let max = self.buf.capacity();
         if buf.len() > max {
-            self.buf.push_str(&buf[..max]);
+            self.insert_str(0, &buf[..max]);
             if pos > max {
                 self.pos = max;
             } else {
                 self.pos = pos;
             }
         } else {
-            self.buf.push_str(buf);
+            self.insert_str(0, buf);
             self.pos = pos;
         }
     }
 
     /// Backup `src`
     pub fn backup(&mut self, src: &LineBuffer) {
-        self.buf.clear();
-        self.buf.push_str(&src.buf);
+        let end = self.len();
+        self.drain(0..end);
+        self.insert_str(0, &src.buf);
         self.pos = src.pos;
     }
 
@@ -132,13 +159,11 @@ impl LineBuffer {
             return None;
         }
         let push = self.pos == self.buf.len();
-        if push {
-            self.buf.reserve(shift);
-            for _ in 0..n {
-                self.buf.push(ch);
-            }
-        } else if n == 1 {
+        if n == 1 {
             self.buf.insert(self.pos, ch);
+            for cl in &self.cl {
+                cl.borrow_mut().insert_char(self.pos, ch);
+            }
         } else {
             let text = iter::repeat(ch).take(n).collect::<String>();
             let pos = self.pos;
@@ -157,14 +182,11 @@ impl LineBuffer {
             return None;
         }
         let push = self.pos == self.buf.len();
-        if push {
-            self.buf.reserve(shift);
-            for _ in 0..n {
-                self.buf.push_str(text);
-            }
+        let pos = self.pos;
+        if n == 1 {
+            self.insert_str(pos, text);
         } else {
             let text = iter::repeat(text).take(n).collect::<String>();
-            let pos = self.pos;
             self.insert_str(pos, &text);
         }
         self.pos += shift;
@@ -173,7 +195,9 @@ impl LineBuffer {
 
     /// Delete previously yanked text and yank/paste `text` at current position.
     pub fn yank_pop(&mut self, yank_size: usize, text: &str) -> Option<bool> {
-        self.buf.drain((self.pos - yank_size)..self.pos);
+        let end = self.pos;
+        let start = end - yank_size;
+        self.drain(start..end);
         self.pos -= yank_size;
         self.yank(text, 1)
     }
@@ -226,7 +250,8 @@ impl LineBuffer {
     pub fn delete(&mut self, n: RepeatCount) -> Option<String> {
         match self.next_pos(n) {
             Some(pos) => {
-                let chars = self.buf.drain(self.pos..pos).collect::<String>();
+                let start = self.pos;
+                let chars = self.drain(start..pos).collect::<String>();
                 Some(chars)
             }
             None => None,
@@ -235,35 +260,39 @@ impl LineBuffer {
 
     /// Delete the character at the left of the cursor.
     /// Basically that is what happens with the "Backspace" keyboard key.
-    pub fn backspace(&mut self, n: RepeatCount) -> Option<String> {
+    pub fn backspace(&mut self, n: RepeatCount) -> bool {
         match self.prev_pos(n) {
             Some(pos) => {
-                let chars = self.buf.drain(pos..self.pos).collect::<String>();
+                let end = self.pos;
+                self.drain(pos..end);
                 self.pos = pos;
-                Some(chars)
+                true
             }
-            None => None,
+            None => false,
         }
     }
 
     /// Kill the text from point to the end of the line.
-    pub fn kill_line(&mut self) -> Option<String> {
+    pub fn kill_line(&mut self) -> bool {
         if !self.buf.is_empty() && self.pos < self.buf.len() {
-            let text = self.buf.drain(self.pos..).collect();
-            Some(text)
+            let start = self.pos;
+            let end = self.buf.len();
+            self.drain(start..end);
+            true
         } else {
-            None
+            false
         }
     }
 
     /// Kill backward from point to the beginning of the line.
-    pub fn discard_line(&mut self) -> Option<String> {
+    pub fn discard_line(&mut self) -> bool {
         if self.pos > 0 && !self.buf.is_empty() {
-            let text = self.buf.drain(..self.pos).collect();
+            let end = self.pos;
+            self.drain(0..end);
             self.pos = 0;
-            Some(text)
+            true
         } else {
-            None
+            false
         }
     }
 
@@ -288,9 +317,7 @@ impl LineBuffer {
             return None;
         }
         let mut sow = 0;
-        let mut gis = self.buf[..pos]
-            .grapheme_indices(true)
-            .rev();
+        let mut gis = self.buf[..pos].grapheme_indices(true).rev();
         'outer: for _ in 0..n {
             let mut gj = gis.next();
             'inner: loop {
@@ -331,13 +358,14 @@ impl LineBuffer {
 
     /// Delete the previous word, maintaining the cursor at the start of the
     /// current word.
-    pub fn delete_prev_word(&mut self, word_def: Word, n: RepeatCount) -> Option<String> {
+    pub fn delete_prev_word(&mut self, word_def: Word, n: RepeatCount) -> bool {
         if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
-            let word = self.buf.drain(pos..self.pos).collect();
+            let end = self.pos;
+            self.drain(pos..end);
             self.pos = pos;
-            Some(word)
+            true
         } else {
-            None
+            false
         }
     }
 
@@ -443,13 +471,18 @@ impl LineBuffer {
         };
         if let Some(pos) = search_result {
             Some(match *cs {
-                CharSearch::Backward(_) => pos,
-                CharSearch::BackwardAfter(c) => pos + c.len_utf8(),
-                CharSearch::Forward(_) => shift + pos,
-                CharSearch::ForwardBefore(_) => {
-                    shift + pos - self.buf[..shift + pos].chars().next_back().unwrap().len_utf8()
-                }
-            })
+                     CharSearch::Backward(_) => pos,
+                     CharSearch::BackwardAfter(c) => pos + c.len_utf8(),
+                     CharSearch::Forward(_) => shift + pos,
+                     CharSearch::ForwardBefore(_) => {
+                         shift + pos -
+                         self.buf[..shift + pos]
+                             .chars()
+                             .next_back()
+                             .unwrap()
+                             .len_utf8()
+                     }
+                 })
         } else {
             None
         }
@@ -466,34 +499,41 @@ impl LineBuffer {
 
     /// Kill from the cursor to the end of the current word,
     /// or, if between words, to the end of the next word.
-    pub fn delete_word(&mut self, at: At, word_def: Word, n: RepeatCount) -> Option<String> {
+    pub fn delete_word(&mut self, at: At, word_def: Word, n: RepeatCount) -> bool {
         if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
-            let word = self.buf.drain(self.pos..pos).collect();
-            Some(word)
+            let start = self.pos;
+            self.drain(start..pos);
+            true
         } else {
-            None
+            false
         }
     }
 
-    pub fn delete_to(&mut self, cs: CharSearch, n: RepeatCount) -> Option<String> {
+    pub fn delete_to(&mut self, cs: CharSearch, n: RepeatCount) -> bool {
         let search_result = match cs {
             CharSearch::ForwardBefore(c) => self.search_char_pos(&CharSearch::Forward(c), n),
             _ => self.search_char_pos(&cs, n),
         };
         if let Some(pos) = search_result {
-            let chunk = match cs {
+            match cs {
                 CharSearch::Backward(_) |
                 CharSearch::BackwardAfter(_) => {
                     let end = self.pos;
                     self.pos = pos;
-                    self.buf.drain(pos..end).collect()
+                    self.drain(pos..end);
+                }
+                CharSearch::ForwardBefore(_) => {
+                    let start = self.pos;
+                    self.drain(start..pos);
+                }
+                CharSearch::Forward(c) => {
+                    let start = self.pos;
+                    self.drain(start..pos + c.len_utf8());
                 }
-                CharSearch::ForwardBefore(_) => self.buf.drain(self.pos..pos).collect(),
-                CharSearch::Forward(c) => self.buf.drain(self.pos..pos + c.len_utf8()).collect(),
             };
-            Some(chunk)
+            true
         } else {
-            None
+            false
         }
     }
 
@@ -515,7 +555,7 @@ impl LineBuffer {
                 if start == end {
                     return false;
                 }
-                let word = self.buf.drain(start..end).collect::<String>();
+                let word = self.drain(start..end).collect::<String>();
                 let result = match a {
                     WordAction::CAPITALIZE => {
                         let ch = (&word).graphemes(true).next().unwrap();
@@ -548,12 +588,12 @@ impl LineBuffer {
             return false;
         }
 
-        let w1 = self.buf[w1_beg..w1_end].to_string();
+        let w1 = self.buf[w1_beg..w1_end].to_owned();
 
-        let w2 = self.buf.drain(w2_beg..w2_end).collect::<String>();
+        let w2 = self.drain(w2_beg..w2_end).collect::<String>();
         self.insert_str(w2_beg, &w1);
 
-        self.buf.drain(w1_beg..w1_end);
+        self.drain(w1_beg..w1_end);
         self.insert_str(w1_beg, &w2);
 
         self.pos = w2_end;
@@ -564,12 +604,15 @@ impl LineBuffer {
     /// and positions the cursor to the end of text.
     pub fn replace(&mut self, range: Range<usize>, text: &str) {
         let start = range.start;
-        self.buf.drain(range);
+        self.drain(range);
         self.insert_str(start, text);
         self.pos = start + text.len();
     }
 
     pub fn insert_str(&mut self, idx: usize, s: &str) -> bool {
+        for cl in &self.cl {
+            cl.borrow_mut().insert_str(idx, s);
+        }
         if idx == self.buf.len() {
             self.buf.push_str(s);
             true
@@ -580,7 +623,14 @@ impl LineBuffer {
     }
 
     pub fn delete_range(&mut self, range: Range<usize>) {
-        self.buf.drain(range);
+        self.drain(range);
+    }
+
+    fn drain(&mut self, range: Range<usize>) -> Drain {
+        for cl in &self.cl {
+            cl.borrow_mut().delete(range.start, &self.buf[range.start..range.end]);
+        }
+        self.buf.drain(range)
     }
 
     pub fn copy(&self, mvt: Movement) -> Option<String> {
@@ -593,26 +643,26 @@ impl LineBuffer {
                 if self.pos == 0 {
                     None
                 } else {
-                    Some(self.buf[..self.pos].to_string())
+                    Some(self.buf[..self.pos].to_owned())
                 }
             }
             Movement::EndOfLine => {
                 if self.pos == self.buf.len() {
                     None
                 } else {
-                    Some(self.buf[self.pos..].to_string())
+                    Some(self.buf[self.pos..].to_owned())
                 }
             }
             Movement::BackwardWord(n, word_def) => {
                 if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
-                    Some(self.buf[pos..self.pos].to_string())
+                    Some(self.buf[pos..self.pos].to_owned())
                 } else {
                     None
                 }
             }
             Movement::ForwardWord(n, at, word_def) => {
                 if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
-                    Some(self.buf[self.pos..pos].to_string())
+                    Some(self.buf[self.pos..pos].to_owned())
                 } else {
                     None
                 }
@@ -626,27 +676,27 @@ impl LineBuffer {
                 };
                 if let Some(pos) = search_result {
                     Some(match cs {
-                        CharSearch::Backward(_) |
-                        CharSearch::BackwardAfter(_) => self.buf[pos..self.pos].to_string(),
-                        CharSearch::ForwardBefore(_) => self.buf[self.pos..pos].to_string(),
-                        CharSearch::Forward(c) => {
-                            self.buf[self.pos..pos + c.len_utf8()].to_string()
-                        }
-                    })
+                             CharSearch::Backward(_) |
+                             CharSearch::BackwardAfter(_) => self.buf[pos..self.pos].to_owned(),
+                             CharSearch::ForwardBefore(_) => self.buf[self.pos..pos].to_owned(),
+                             CharSearch::Forward(c) => {
+                                 self.buf[self.pos..pos + c.len_utf8()].to_owned()
+                             }
+                         })
                 } else {
                     None
                 }
             }
             Movement::BackwardChar(n) => {
                 if let Some(pos) = self.prev_pos(n) {
-                    Some(self.buf[pos..self.pos].to_string())
+                    Some(self.buf[pos..self.pos].to_owned())
                 } else {
                     None
                 }
             }
             Movement::ForwardChar(n) => {
                 if let Some(pos) = self.next_pos(n) {
-                    Some(self.buf[self.pos..pos].to_string())
+                    Some(self.buf[self.pos..pos].to_owned())
                 } else {
                     None
                 }
@@ -688,29 +738,55 @@ fn is_other_char(grapheme: &str) -> bool {
 
 #[cfg(test)]
 mod test {
+    use std::cell::RefCell;
+    use std::rc::Rc;
     use keymap::{At, CharSearch, Word};
-    use super::{LineBuffer, MAX_LINE, WordAction};
+    use super::{ChangeListener, LineBuffer, MAX_LINE, WordAction};
+
+    struct Listener {
+        deleted_str: Option<String>,
+    }
+
+    impl Listener {
+        fn new() -> Rc<RefCell<Listener>> {
+            let l = Listener { deleted_str: None };
+            Rc::new(RefCell::new(l))
+        }
+
+        fn assert_deleted_str_eq(&self, expected: &str) {
+            let actual = self.deleted_str.as_ref().expect("no deleted string");
+            assert_eq!(expected, actual)
+        }
+    }
+
+    impl ChangeListener for Listener {
+        fn insert_char(&mut self, _: usize, _: char) {}
+        fn insert_str(&mut self, _: usize, _: &str) {}
+        fn delete(&mut self, _: usize, string: &str) {
+            self.deleted_str = Some(string.to_owned());
+        }
+    }
 
     #[test]
     fn next_pos() {
-        let s = LineBuffer::init("ö̲g̈", 0);
+        let s = LineBuffer::init("ö̲g̈", 0, None);
         assert_eq!(7, s.len());
         let pos = s.next_pos(1);
         assert_eq!(Some(4), pos);
 
-        let s = LineBuffer::init("ö̲g̈", 4);
+        let s = LineBuffer::init("ö̲g̈", 4, None);
         let pos = s.next_pos(1);
         assert_eq!(Some(7), pos);
     }
 
     #[test]
     fn prev_pos() {
-        let s = LineBuffer::init("ö̲g̈", 4);
+        let s = LineBuffer::init("ö̲g̈", 4, None);
         assert_eq!(7, s.len());
         let pos = s.prev_pos(1);
         assert_eq!(Some(0), pos);
 
-        let s = LineBuffer::init("ö̲g̈", 7);
+        let s = LineBuffer::init("ö̲g̈", 7, None);
         let pos = s.prev_pos(1);
         assert_eq!(Some(4), pos);
     }
@@ -737,7 +813,7 @@ mod test {
 
     #[test]
     fn yank_after() {
-        let mut s = LineBuffer::init("αß", 2);
+        let mut s = LineBuffer::init("αß", 2, None);
         s.move_forward(1);
         let ok = s.yank("γδε", 1);
         assert_eq!(Some(true), ok);
@@ -747,7 +823,7 @@ mod test {
 
     #[test]
     fn yank_before() {
-        let mut s = LineBuffer::init("αε", 2);
+        let mut s = LineBuffer::init("αε", 2, None);
         let ok = s.yank("ßγδ", 1);
         assert_eq!(Some(false), ok);
         assert_eq!("αßγδε", s.buf);
@@ -756,7 +832,7 @@ mod test {
 
     #[test]
     fn moves() {
-        let mut s = LineBuffer::init("αß", 4);
+        let mut s = LineBuffer::init("αß", 4, None);
         let ok = s.move_backward(1);
         assert_eq!("αß", s.buf);
         assert_eq!(2, s.pos);
@@ -780,7 +856,7 @@ mod test {
 
     #[test]
     fn move_grapheme() {
-        let mut s = LineBuffer::init("ag̈", 4);
+        let mut s = LineBuffer::init("ag̈", 4, None);
         assert_eq!(4, s.len());
         let ok = s.move_backward(1);
         assert_eq!(true, ok);
@@ -793,36 +869,41 @@ mod test {
 
     #[test]
     fn delete() {
-        let mut s = LineBuffer::init("αß", 2);
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("αß", 2, Some(cl.clone()));
         let chars = s.delete(1);
         assert_eq!("α", s.buf);
         assert_eq!(2, s.pos);
-        assert_eq!(Some("ß".to_string()), chars);
+        assert_eq!(Some("ß".to_owned()), chars);
 
-        let chars = s.backspace(1);
+        let ok = s.backspace(1);
         assert_eq!("", s.buf);
         assert_eq!(0, s.pos);
-        assert_eq!(Some("α".to_string()), chars);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("α");
     }
 
     #[test]
     fn kill() {
-        let mut s = LineBuffer::init("αßγδε", 6);
-        let text = s.kill_line();
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("αßγδε", 6, Some(cl.clone()));
+        let ok = s.kill_line();
         assert_eq!("αßγ", s.buf);
         assert_eq!(6, s.pos);
-        assert_eq!(Some("δε".to_string()), text);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("δε");
 
         s.pos = 4;
-        let text = s.discard_line();
+        let ok = s.discard_line();
         assert_eq!("γ", s.buf);
         assert_eq!(0, s.pos);
-        assert_eq!(Some("αß".to_string()), text);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("αß");
     }
 
     #[test]
     fn transpose() {
-        let mut s = LineBuffer::init("aßc", 1);
+        let mut s = LineBuffer::init("aßc", 1, None);
         let ok = s.transpose_chars();
         assert_eq!("ßac", s.buf);
         assert_eq!(3, s.pos);
@@ -845,7 +926,7 @@ mod test {
 
     #[test]
     fn move_to_prev_word() {
-        let mut s = LineBuffer::init("a ß  c", 6);
+        let mut s = LineBuffer::init("a ß  c", 6, None);
         let ok = s.move_to_prev_word(Word::Emacs, 1);
         assert_eq!("a ß  c", s.buf);
         assert_eq!(2, s.pos);
@@ -854,7 +935,7 @@ mod test {
 
     #[test]
     fn move_to_prev_vi_word() {
-        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19);
+        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19, None);
         let ok = s.move_to_prev_word(Word::Vi, 1);
         assert!(ok);
         assert_eq!(17, s.pos);
@@ -882,7 +963,7 @@ mod test {
 
     #[test]
     fn move_to_prev_big_word() {
-        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19);
+        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19, None);
         let ok = s.move_to_prev_word(Word::Big, 1);
         assert!(ok);
         assert_eq!(17, s.pos);
@@ -898,17 +979,17 @@ mod test {
 
     #[test]
     fn move_to_forward() {
-        let mut s = LineBuffer::init("αßγδε", 2);
+        let mut s = LineBuffer::init("αßγδε", 2, None);
         let ok = s.move_to(CharSearch::ForwardBefore('ε'), 1);
         assert_eq!(true, ok);
         assert_eq!(6, s.pos);
 
-        let mut s = LineBuffer::init("αßγδε", 2);
+        let mut s = LineBuffer::init("αßγδε", 2, None);
         let ok = s.move_to(CharSearch::Forward('ε'), 1);
         assert_eq!(true, ok);
         assert_eq!(8, s.pos);
 
-        let mut s = LineBuffer::init("αßγδε", 2);
+        let mut s = LineBuffer::init("αßγδε", 2, None);
         let ok = s.move_to(CharSearch::Forward('ε'), 10);
         assert_eq!(true, ok);
         assert_eq!(8, s.pos);
@@ -916,12 +997,12 @@ mod test {
 
     #[test]
     fn move_to_backward() {
-        let mut s = LineBuffer::init("αßγδε", 8);
+        let mut s = LineBuffer::init("αßγδε", 8, None);
         let ok = s.move_to(CharSearch::BackwardAfter('ß'), 1);
         assert_eq!(true, ok);
         assert_eq!(4, s.pos);
 
-        let mut s = LineBuffer::init("αßγδε", 8);
+        let mut s = LineBuffer::init("αßγδε", 8, None);
         let ok = s.move_to(CharSearch::Backward('ß'), 1);
         assert_eq!(true, ok);
         assert_eq!(2, s.pos);
@@ -929,16 +1010,18 @@ mod test {
 
     #[test]
     fn delete_prev_word() {
-        let mut s = LineBuffer::init("a ß  c", 6);
-        let text = s.delete_prev_word(Word::Big, 1);
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("a ß  c", 6, Some(cl.clone()));
+        let ok = s.delete_prev_word(Word::Big, 1);
         assert_eq!("a c", s.buf);
         assert_eq!(2, s.pos);
-        assert_eq!(Some("ß  ".to_string()), text);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("ß  ");
     }
 
     #[test]
     fn move_to_next_word() {
-        let mut s = LineBuffer::init("a ß  c", 1);
+        let mut s = LineBuffer::init("a ß  c", 1, None);
         let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
         assert_eq!("a ß  c", s.buf);
         assert_eq!(4, s.pos);
@@ -947,7 +1030,7 @@ mod test {
 
     #[test]
     fn move_to_end_of_word() {
-        let mut s = LineBuffer::init("a ßeta  c", 1);
+        let mut s = LineBuffer::init("a ßeta  c", 1, None);
         let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
         assert_eq!("a ßeta  c", s.buf);
         assert_eq!(6, s.pos);
@@ -956,7 +1039,7 @@ mod test {
 
     #[test]
     fn move_to_end_of_vi_word() {
-        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
+        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
         let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
         assert!(ok);
         assert_eq!(4, s.pos);
@@ -984,7 +1067,7 @@ mod test {
 
     #[test]
     fn move_to_end_of_big_word() {
-        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
+        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
         let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
         assert!(ok);
         assert_eq!(4, s.pos);
@@ -1000,7 +1083,7 @@ mod test {
 
     #[test]
     fn move_to_start_of_word() {
-        let mut s = LineBuffer::init("a ß  c", 2);
+        let mut s = LineBuffer::init("a ß  c", 2, None);
         let ok = s.move_to_next_word(At::Start, Word::Emacs, 1);
         assert_eq!("a ß  c", s.buf);
         assert_eq!(6, s.pos);
@@ -1009,7 +1092,7 @@ mod test {
 
     #[test]
     fn move_to_start_of_vi_word() {
-        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
+        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
         let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
         assert!(ok);
         assert_eq!(6, s.pos);
@@ -1037,7 +1120,7 @@ mod test {
 
     #[test]
     fn move_to_start_of_big_word() {
-        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
+        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
         let ok = s.move_to_next_word(At::Start, Word::Big, 1);
         assert!(ok);
         assert_eq!(6, s.pos);
@@ -1053,76 +1136,87 @@ mod test {
 
     #[test]
     fn delete_word() {
-        let mut s = LineBuffer::init("a ß  c", 1);
-        let text = s.delete_word(At::AfterEnd, Word::Emacs, 1);
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("a ß  c", 1, Some(cl.clone()));
+        let ok = s.delete_word(At::AfterEnd, Word::Emacs, 1);
         assert_eq!("a  c", s.buf);
         assert_eq!(1, s.pos);
-        assert_eq!(Some(" ß".to_string()), text);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq(" ß");
 
-        let mut s = LineBuffer::init("test", 0);
-        let text = s.delete_word(At::AfterEnd, Word::Vi, 1);
+        let mut s = LineBuffer::init("test", 0, Some(cl.clone()));
+        let ok = s.delete_word(At::AfterEnd, Word::Vi, 1);
         assert_eq!("", s.buf);
         assert_eq!(0, s.pos);
-        assert_eq!(Some("test".to_string()), text);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("test");
     }
 
     #[test]
     fn delete_til_start_of_word() {
-        let mut s = LineBuffer::init("a ß  c", 2);
-        let text = s.delete_word(At::Start, Word::Emacs, 1);
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("a ß  c", 2, Some(cl.clone()));
+        let ok = s.delete_word(At::Start, Word::Emacs, 1);
         assert_eq!("a c", s.buf);
         assert_eq!(2, s.pos);
-        assert_eq!(Some("ß  ".to_string()), text);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("ß  ");
     }
 
     #[test]
     fn delete_to_forward() {
-        let mut s = LineBuffer::init("αßγδε", 2);
-        let text = s.delete_to(CharSearch::ForwardBefore('ε'), 1);
-        assert_eq!(Some("ßγδ".to_string()), text);
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("αßγδε", 2, Some(cl.clone()));
+        let ok = s.delete_to(CharSearch::ForwardBefore('ε'), 1);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("ßγδ");
         assert_eq!("αε", s.buf);
         assert_eq!(2, s.pos);
 
-        let mut s = LineBuffer::init("αßγδε", 2);
-        let text = s.delete_to(CharSearch::Forward('ε'), 1);
-        assert_eq!(Some("ßγδε".to_string()), text);
+        let mut s = LineBuffer::init("αßγδε", 2, Some(cl.clone()));
+        let ok = s.delete_to(CharSearch::Forward('ε'), 1);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("ßγδε");
         assert_eq!("α", s.buf);
         assert_eq!(2, s.pos);
     }
 
     #[test]
     fn delete_to_backward() {
-        let mut s = LineBuffer::init("αßγδε", 8);
-        let text = s.delete_to(CharSearch::BackwardAfter('α'), 1);
-        assert_eq!(Some("ßγδ".to_string()), text);
+        let cl = Listener::new();
+        let mut s = LineBuffer::init("αßγδε", 8, Some(cl.clone()));
+        let ok = s.delete_to(CharSearch::BackwardAfter('α'), 1);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("ßγδ");
         assert_eq!("αε", s.buf);
         assert_eq!(2, s.pos);
 
-        let mut s = LineBuffer::init("αßγδε", 8);
-        let text = s.delete_to(CharSearch::Backward('ß'), 1);
-        assert_eq!(Some("ßγδ".to_string()), text);
+        let mut s = LineBuffer::init("αßγδε", 8, Some(cl.clone()));
+        let ok = s.delete_to(CharSearch::Backward('ß'), 1);
+        assert_eq!(true, ok);
+        cl.borrow().assert_deleted_str_eq("ßγδ");
         assert_eq!("αε", s.buf);
         assert_eq!(2, s.pos);
     }
 
     #[test]
     fn edit_word() {
-        let mut s = LineBuffer::init("a ßeta  c", 1);
+        let mut s = LineBuffer::init("a ßeta  c", 1, None);
         assert!(s.edit_word(WordAction::UPPERCASE));
         assert_eq!("a SSETA  c", s.buf);
         assert_eq!(7, s.pos);
 
-        let mut s = LineBuffer::init("a ßetA  c", 1);
+        let mut s = LineBuffer::init("a ßetA  c", 1, None);
         assert!(s.edit_word(WordAction::LOWERCASE));
         assert_eq!("a ßeta  c", s.buf);
         assert_eq!(7, s.pos);
 
-        let mut s = LineBuffer::init("a ßETA  c", 1);
+        let mut s = LineBuffer::init("a ßETA  c", 1, None);
         assert!(s.edit_word(WordAction::CAPITALIZE));
         assert_eq!("a SSeta  c", s.buf);
         assert_eq!(7, s.pos);
 
-        let mut s = LineBuffer::init("test", 1);
+        let mut s = LineBuffer::init("test", 1, None);
         assert!(s.edit_word(WordAction::CAPITALIZE));
         assert_eq!("tEst", s.buf);
         assert_eq!(4, s.pos);
@@ -1130,20 +1224,20 @@ mod test {
 
     #[test]
     fn transpose_words() {
-        let mut s = LineBuffer::init("ßeta / δelta__", 15);
+        let mut s = LineBuffer::init("ßeta / δelta__", 15, None);
         assert!(s.transpose_words(1));
         assert_eq!("δelta__ / ßeta", s.buf);
         assert_eq!(16, s.pos);
 
-        let mut s = LineBuffer::init("ßeta / δelta", 14);
+        let mut s = LineBuffer::init("ßeta / δelta", 14, None);
         assert!(s.transpose_words(1));
         assert_eq!("δelta / ßeta", s.buf);
         assert_eq!(14, s.pos);
 
-        let mut s = LineBuffer::init(" / δelta", 8);
+        let mut s = LineBuffer::init(" / δelta", 8, None);
         assert!(!s.transpose_words(1));
 
-        let mut s = LineBuffer::init("ßeta / __", 9);
+        let mut s = LineBuffer::init("ßeta / __", 9, None);
         assert!(!s.transpose_words(1));
     }
 }
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index 7b77b6833cd11450d6c2560f7b7130cc8b9c7ac9..83b9479938bc02e18d4907c481a0df0be6f62841 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -100,9 +100,9 @@ impl PosixRawReader {
     fn new(config: &Config) -> Result<PosixRawReader> {
         let stdin = StdinRaw {};
         Ok(PosixRawReader {
-            chars: stdin.chars(),
-            timeout_ms: config.keyseq_timeout(),
-        })
+               chars: stdin.chars(),
+               timeout_ms: config.keyseq_timeout(),
+           })
     }
 
     fn escape_sequence(&mut self) -> Result<KeyPress> {
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index 6ad88444310b3df978ccfac4d4d38f30602a9f18..b03bddf630823c218cfa8385da735323f4c9a592 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -79,9 +79,9 @@ impl ConsoleRawReader {
     pub fn new() -> Result<ConsoleRawReader> {
         let handle = try!(get_std_handle(STDIN_FILENO));
         Ok(ConsoleRawReader {
-            handle: handle,
-            buf: None,
-        })
+               handle: handle,
+               buf: None,
+           })
     }
 }
 
@@ -288,9 +288,9 @@ impl Term for Console {
         let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
         check!(kernel32::SetConsoleMode(self.stdin_handle, raw));
         Ok(Mode {
-            original_mode: original_mode,
-            stdin_handle: self.stdin_handle,
-        })
+               original_mode: original_mode,
+               stdin_handle: self.stdin_handle,
+           })
     }
 
     fn create_reader(&self, _: &Config) -> Result<ConsoleRawReader> {
diff --git a/src/undo.rs b/src/undo.rs
index 5c6128c8da63ff04190e137b50d1494ce43135ac..1b070a89907660e1e980695fae88977d6f935fc6 100644
--- a/src/undo.rs
+++ b/src/undo.rs
@@ -6,7 +6,7 @@ use unicode_segmentation::UnicodeSegmentation;
 enum Action {
     Insert(String), // QuotedInsert, SelfInsert, Yank
     Delete(String), /* BackwardDeleteChar, BackwardKillWord, DeleteChar, KillLine, KillWholeLine, KillWord, UnixLikeDiscard, ViDeleteTo */
-    Replace(String, String), /* CapitalizeWord, Complete, DowncaseWord, Replace, TransposeChars, TransposeWords, UpcaseWord, YankPop */
+                    //Replace(String, String), /* CapitalizeWord, Complete, DowncaseWord, Replace, TransposeChars, TransposeWords, UpcaseWord, YankPop */
 }
 
 struct Change {
@@ -24,9 +24,9 @@ impl Change {
                 line.insert_str(self.idx, text);
                 line.set_pos(self.idx + text.len());
             }
-            Action::Replace(ref old, ref new) => {
+            /*Action::Replace(ref old, ref new) => {
                 line.replace(self.idx..self.idx + new.len(), old);
-            }
+            }*/
         }
     }
 
@@ -39,9 +39,9 @@ impl Change {
             Action::Delete(ref text) => {
                 line.delete_range(self.idx..self.idx + text.len());
             }
-            Action::Replace(ref old, ref new) => {
+            /*Action::Replace(ref old, ref new) => {
                 line.replace(self.idx..self.idx + old.len(), new);
-            }
+            }*/
         }
     }
 
@@ -117,9 +117,9 @@ impl Changeset {
     pub fn insert_str<S: Into<String>>(&mut self, idx: usize, string: S) {
         self.redos.clear();
         self.undos.push(Change {
-            idx: idx,
-            action: Action::Insert(string.into()),
-        });
+                            idx: idx,
+                            action: Action::Insert(string.into()),
+                        });
     }
 
     pub fn delete<S: AsRef<str> + Into<String>>(&mut self, idx: usize, string: S) {
@@ -127,9 +127,9 @@ impl Changeset {
 
         if !Self::single_char(string.as_ref()) {
             self.undos.push(Change {
-                idx: idx,
-                action: Action::Delete(string.into()),
-            });
+                                idx: idx,
+                                action: Action::Delete(string.into()),
+                            });
             return;
         }
         let last_change = self.undos.pop();
@@ -152,16 +152,16 @@ impl Changeset {
                 } else {
                     self.undos.push(last_change);
                     self.undos.push(Change {
-                        idx: idx,
-                        action: Action::Delete(string.into()),
-                    });
+                                        idx: idx,
+                                        action: Action::Delete(string.into()),
+                                    });
                 }
             }
             None => {
                 self.undos.push(Change {
-                    idx: idx,
-                    action: Action::Delete(string.into()),
-                });
+                                    idx: idx,
+                                    action: Action::Delete(string.into()),
+                                });
             }
         };
     }
@@ -172,13 +172,13 @@ impl Changeset {
         graphemes.next().is_none()
     }
 
-    pub fn replace<S: Into<String>>(&mut self, idx: usize, old: String, new: S) {
+    /*pub fn replace<S: Into<String>>(&mut self, idx: usize, old: String, new: S) {
         self.redos.clear();
         self.undos.push(Change {
             idx: idx,
             action: Action::Replace(old.into(), new.into()),
         });
-    }
+    }*/
 
     pub fn undo(&mut self, line: &mut LineBuffer) -> bool {
         match self.undos.pop() {
@@ -202,6 +202,11 @@ impl Changeset {
             None => false,
         }
     }
+
+    pub fn clear(&mut self) {
+        self.undos.clear();
+        self.redos.clear();
+    }
 }
 
 #[cfg(test)]
@@ -231,7 +236,7 @@ mod tests {
 
     #[test]
     fn test_undo_insert() {
-        let mut buf = LineBuffer::init("", 0);
+        let mut buf = LineBuffer::init("", 0, None);
         buf.insert_str(0, "Hello");
         buf.insert_str(5, ", world!");
         let mut cs = Changeset::new();
@@ -252,12 +257,12 @@ mod tests {
 
     #[test]
     fn test_undo_delete() {
-        let mut buf = LineBuffer::init("", 0);
+        let mut buf = LineBuffer::init("", 0, None);
         buf.insert_str(0, "Hello");
         let mut cs = Changeset::new();
         assert_eq!(buf.as_str(), "Hello");
 
-        cs.delete(5, ", world!".to_string());
+        cs.delete(5, ", world!".to_owned());
 
         cs.undo(&mut buf);
         assert_eq!(buf.as_str(), "Hello, world!");
@@ -268,12 +273,12 @@ mod tests {
 
     #[test]
     fn test_delete_chars() {
-        let mut buf = LineBuffer::init("", 0);
+        let mut buf = LineBuffer::init("", 0, None);
         buf.insert_str(0, "Hlo");
 
         let mut cs = Changeset::new();
-        cs.delete(1, "e".to_string());
-        cs.delete(1, "l".to_string());
+        cs.delete(1, "e".to_owned());
+        cs.delete(1, "l".to_owned());
         assert_eq!(1, cs.undos.len());
 
         cs.undo(&mut buf);
@@ -282,33 +287,33 @@ mod tests {
 
     #[test]
     fn test_backspace_chars() {
-        let mut buf = LineBuffer::init("", 0);
+        let mut buf = LineBuffer::init("", 0, None);
         buf.insert_str(0, "Hlo");
 
         let mut cs = Changeset::new();
-        cs.delete(2, "l".to_string());
-        cs.delete(1, "e".to_string());
+        cs.delete(2, "l".to_owned());
+        cs.delete(1, "e".to_owned());
         assert_eq!(1, cs.undos.len());
 
         cs.undo(&mut buf);
         assert_eq!(buf.as_str(), "Hello");
     }
 
-    #[test]
+    /*#[test]
     fn test_undo_replace() {
-        let mut buf = LineBuffer::init("", 0);
+        let mut buf = LineBuffer::init("", 0, None);
         buf.insert_str(0, "Hello, world!");
         let mut cs = Changeset::new();
         assert_eq!(buf.as_str(), "Hello, world!");
 
         buf.replace(1..5, "i");
         assert_eq!(buf.as_str(), "Hi, world!");
-        cs.replace(1, "ello".to_string(), "i");
+        cs.replace(1, "ello".to_owned(), "i");
 
         cs.undo(&mut buf);
         assert_eq!(buf.as_str(), "Hello, world!");
 
         cs.redo(&mut buf);
         assert_eq!(buf.as_str(), "Hi, world!");
-    }
+    }*/
 }