diff --git a/src/keymap.rs b/src/keymap.rs
index a63be00e2f42ff72bc72f48e83150330f1af9384..3287f53552fb0b258adb0a21d8a18f854ac7cf85 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -119,15 +119,6 @@ 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 cbe2aa12aa5eec5b692014919a9f6152c81ab1e5..b6342f6f05ab0f8257ce59e6a02cae853c4b991e 100644
--- a/src/kill_ring.rs
+++ b/src/kill_ring.rs
@@ -1,4 +1,5 @@
 //! Kill Ring
+use line_buffer::{ChangeListener, Direction};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 enum Action {
@@ -102,6 +103,18 @@ impl KillRing {
     }
 }
 
+impl ChangeListener for KillRing {
+    fn insert_char(&mut self, _: usize, _: char) {}
+    fn insert_str(&mut self, _: usize, _: &str) {}
+    fn delete(&mut self, _: usize, string: &str, dir: Direction) {
+        let mode = match dir {
+            Direction::Forward => Mode::Append,
+            Direction::Backward => Mode::Prepend,
+        };
+        self.kill(string, mode);
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::{Action, Mode, KillRing};
diff --git a/src/lib.rs b/src/lib.rs
index 0718d734d36da0cbd01f36f2ff97df6b519a673f..fc3f6fc83e344c66df414f46be8454b5d52d2e2e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,7 +57,7 @@ use tty::{RawMode, RawReader, Terminal, Term};
 
 use completion::{Completer, longest_common_prefix};
 use history::{Direction, History};
-use line_buffer::{ChangeListener, LineBuffer, MAX_LINE, WordAction};
+use line_buffer::{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};
@@ -80,6 +80,7 @@ struct State<'out, 'prompt> {
     term: Terminal, // terminal
     byte_buffer: [u8; 4],
     edit_state: EditState,
+    changes: Rc<RefCell<Changeset>>,
 }
 
 #[derive(Copy, Clone, Debug, Default)]
@@ -111,6 +112,7 @@ impl<'out, 'prompt> State<'out, 'prompt> {
             term: term,
             byte_buffer: [0; 4],
             edit_state: EditState::new(config),
+            changes: Rc::new(RefCell::new(Changeset::new())),
         }
     }
 
@@ -829,6 +831,9 @@ fn reverse_incremental_search<R: RawReader>(rdr: &mut R,
     Ok(Some(cmd))
 }
 
+static KILL_RING_NAME: &'static str = "kill_ring";
+static UNDOS_NAME: &'static str = "undos";
+
 /// Handles reading and editting the readline buffer.
 /// It will also handle special inputs in an appropriate fashion
 /// (e.g., C-c will exit readline)
@@ -842,13 +847,12 @@ fn readline_edit<C: Completer>(prompt: &str,
     let mut stdout = editor.term.create_writer();
 
     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()));
+    s.line.bind(UNDOS_NAME, s.changes.clone());
     try!(s.refresh_line());
 
     let mut rdr = try!(s.term.create_reader(&editor.config));
@@ -941,13 +945,15 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Kill(Movement::EndOfLine) => {
                 // Kill the text from point to the end of the line.
-                editor.set_kill_ring_mode(Mode::Append);
-                try!(edit_kill_line(&mut s))
+                s.line.bind(KILL_RING_NAME, editor.kill_ring.clone());
+                try!(edit_kill_line(&mut s));
+                s.line.unbind(KILL_RING_NAME);
             }
             Cmd::Kill(Movement::WholeLine) => {
                 try!(edit_move_home(&mut s));
-                editor.set_kill_ring_mode(Mode::Append);
-                try!(edit_kill_line(&mut s))
+                s.line.bind(KILL_RING_NAME, editor.kill_ring.clone());
+                try!(edit_kill_line(&mut s));
+                s.line.unbind(KILL_RING_NAME);
             }
             Cmd::ClearScreen => {
                 // Clear the screen leaving the current line at the top of the screen.
@@ -971,8 +977,9 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Kill(Movement::BeginningOfLine) => {
                 // Kill backward from point to the beginning of the line.
-                editor.set_kill_ring_mode(Mode::Prepend);
-                try!(edit_discard_line(&mut s))
+                s.line.bind(KILL_RING_NAME, editor.kill_ring.clone());
+                try!(edit_discard_line(&mut s));
+                s.line.unbind(KILL_RING_NAME);
             }
             #[cfg(unix)]
             Cmd::QuotedInsert => {
@@ -983,14 +990,14 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Yank(n, anchor) => {
                 // retrieve (yank) last item killed
-                if let Some(text) = editor.listener.borrow_mut().kill_ring.yank() {
+                if let Some(text) = editor.kill_ring.borrow_mut().yank() {
                     try!(edit_yank(&mut s, text, anchor, n))
                 }
             }
             Cmd::ViYankTo(mvt) => {
                 editor.reset_kill_ring();
                 if let Some(text) = s.line.copy(mvt) {
-                    editor.kill(&text, Mode::Append)
+                    editor.kill_ring.borrow_mut().kill(&text, Mode::Append)
                 }
             }
             // TODO CTRL-_ // undo
@@ -1002,8 +1009,9 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Kill(Movement::BackwardWord(n, word_def)) => {
                 // kill one word backward (until start of word)
-                editor.set_kill_ring_mode(Mode::Prepend);
-                try!(edit_delete_prev_word(&mut s, word_def, n))
+                s.line.bind(KILL_RING_NAME, editor.kill_ring.clone());
+                try!(edit_delete_prev_word(&mut s, word_def, n));
+                s.line.unbind(KILL_RING_NAME);
             }
             Cmd::BeginningOfHistory => {
                 // move to first entry in history
@@ -1027,8 +1035,9 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::Kill(Movement::ForwardWord(n, at, word_def)) => {
                 // kill one word forward (until start/end of word)
-                editor.set_kill_ring_mode(Mode::Append);
-                try!(edit_delete_word(&mut s, at, word_def, n))
+                s.line.bind(KILL_RING_NAME, editor.kill_ring.clone());
+                try!(edit_delete_word(&mut s, at, word_def, n));
+                s.line.unbind(KILL_RING_NAME);
             }
             Cmd::ForwardWord(n, at, word_def) => {
                 // move forwards one word
@@ -1052,7 +1061,7 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             Cmd::YankPop => {
                 // yank-pop
-                if let Some((yank_size, text)) = editor.listener.borrow_mut().kill_ring.yank_pop() {
+                if let Some((yank_size, text)) = editor.kill_ring.borrow_mut().yank_pop() {
                     try!(edit_yank_pop(&mut s, yank_size, text))
                 }
             }
@@ -1061,17 +1070,16 @@ fn readline_edit<C: Completer>(prompt: &str,
                 try!(edit_move_to(&mut s, cs, n))
             }
             Cmd::Kill(Movement::ViCharSearch(n, cs)) => {
-                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))
+                s.line.bind(KILL_RING_NAME, editor.kill_ring.clone());
+                try!(edit_delete_to(&mut s, cs, n));
+                s.line.unbind(KILL_RING_NAME);
             }
             Cmd::Undo => {
-                if editor.undo(&mut s.line) {
+                s.line.unbind(UNDOS_NAME);
+                if s.changes.borrow_mut().undo(&mut s.line) {
                     try!(s.refresh_line());
                 }
+                s.line.bind(UNDOS_NAME, s.changes.clone());
             }
             Cmd::Interrupt => {
                 editor.reset_kill_ring();
@@ -1130,71 +1138,10 @@ pub struct Editor<C: Completer> {
     term: Terminal,
     history: History,
     completer: Option<C>,
-    listener: Rc<RefCell<Listener>>,
+    kill_ring: Rc<RefCell<KillRing>>,
     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())
@@ -1206,7 +1153,7 @@ impl<C: Completer> Editor<C> {
             term: term,
             history: History::with_config(config),
             completer: None,
-            listener: Listener::new(),
+            kill_ring: Rc::new(RefCell::new(KillRing::new(60))),
             config: config,
         }
     }
@@ -1277,20 +1224,7 @@ impl<C: Completer> Editor<C> {
     }
 
     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()
+        self.kill_ring.borrow_mut().reset();
     }
 }
 
@@ -1328,7 +1262,9 @@ impl<'a, C: Completer> Iterator for Iter<'a, C> {
 
 #[cfg(test)]
 mod test {
+    use std::cell::RefCell;
     use std::io::Write;
+    use std::rc::Rc;
     use line_buffer::LineBuffer;
     use history::History;
     use completion::Completer;
@@ -1337,6 +1273,7 @@ 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,
@@ -1358,6 +1295,7 @@ mod test {
             term: term,
             byte_buffer: [0; 4],
             edit_state: EditState::new(&config),
+            changes: Rc::new(RefCell::new(Changeset::new())),
         }
     }
 
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index 7d8000da84a8b29d8179797291bd2b4e3951612a..6813eaa716c1fd0e837e51fe6b1776c3d14ea035 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -1,5 +1,6 @@
 //! Line buffer with current cursor position
 use std::cell::RefCell;
+use std::collections::HashMap;
 use std::fmt;
 use std::iter;
 use std::ops::{Deref, Range};
@@ -18,16 +19,28 @@ pub enum WordAction {
     UPPERCASE,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Direction {
+    Forward,
+    Backward
+}
+
+impl Default for Direction {
+    fn default() -> Direction {
+        Direction::Forward
+    }
+}
+
 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);
+    fn delete(&mut self, idx: usize, string: &str, dir: Direction);
 }
 
 pub struct LineBuffer {
     buf: String, // Edited line buffer
     pos: usize, // Current cursor position (byte position)
-    cl: Option<Rc<RefCell<ChangeListener>>>,
+    cl: HashMap<&'static str, Rc<RefCell<ChangeListener>>>,
 }
 
 impl fmt::Debug for LineBuffer {
@@ -45,7 +58,7 @@ impl LineBuffer {
         LineBuffer {
             buf: String::with_capacity(capacity),
             pos: 0,
-            cl: None,
+            cl: HashMap::new(),
         }
     }
 
@@ -54,12 +67,17 @@ impl LineBuffer {
         let mut lb = Self::with_capacity(MAX_LINE);
         assert!(lb.insert_str(0, line));
         lb.set_pos(pos);
-        lb.cl = cl;
+        if cl.is_some() {
+            lb.bind("test", cl.unwrap());
+        }
         lb
     }
 
-    pub fn bind(&mut self, cl: Option<Rc<RefCell<ChangeListener>>>) {
-        self.cl = cl;
+    pub fn bind(&mut self, key: &'static str, cl: Rc<RefCell<ChangeListener>>) {
+        self.cl.insert(key, cl);
+    }
+    pub fn unbind(&mut self, key: &'static str) {
+        self.cl.remove(key);
     }
 
     /// Extracts a string slice containing the entire buffer.
@@ -94,7 +112,7 @@ impl LineBuffer {
     pub fn update(&mut self, buf: &str, pos: usize) {
         assert!(pos <= buf.len());
         let end = self.len();
-        self.drain(0..end);
+        self.drain(0..end, Direction::default());
         let max = self.buf.capacity();
         if buf.len() > max {
             self.insert_str(0, &buf[..max]);
@@ -112,7 +130,7 @@ impl LineBuffer {
     /// Backup `src`
     pub fn backup(&mut self, src: &LineBuffer) {
         let end = self.len();
-        self.drain(0..end);
+        self.drain(0..end, Direction::default());
         self.insert_str(0, &src.buf);
         self.pos = src.pos;
     }
@@ -161,7 +179,7 @@ impl LineBuffer {
         let push = self.pos == self.buf.len();
         if n == 1 {
             self.buf.insert(self.pos, ch);
-            for cl in &self.cl {
+            for (_, cl) in &self.cl {
                 cl.borrow_mut().insert_char(self.pos, ch);
             }
         } else {
@@ -197,7 +215,7 @@ impl LineBuffer {
     pub fn yank_pop(&mut self, yank_size: usize, text: &str) -> Option<bool> {
         let end = self.pos;
         let start = end - yank_size;
-        self.drain(start..end);
+        self.drain(start..end, Direction::default());
         self.pos -= yank_size;
         self.yank(text, 1)
     }
@@ -251,7 +269,7 @@ impl LineBuffer {
         match self.next_pos(n) {
             Some(pos) => {
                 let start = self.pos;
-                let chars = self.drain(start..pos).collect::<String>();
+                let chars = self.drain(start..pos, Direction::Forward).collect::<String>();
                 Some(chars)
             }
             None => None,
@@ -264,7 +282,7 @@ impl LineBuffer {
         match self.prev_pos(n) {
             Some(pos) => {
                 let end = self.pos;
-                self.drain(pos..end);
+                self.drain(pos..end, Direction::Backward);
                 self.pos = pos;
                 true
             }
@@ -277,7 +295,7 @@ impl LineBuffer {
         if !self.buf.is_empty() && self.pos < self.buf.len() {
             let start = self.pos;
             let end = self.buf.len();
-            self.drain(start..end);
+            self.drain(start..end, Direction::Forward);
             true
         } else {
             false
@@ -288,7 +306,7 @@ impl LineBuffer {
     pub fn discard_line(&mut self) -> bool {
         if self.pos > 0 && !self.buf.is_empty() {
             let end = self.pos;
-            self.drain(0..end);
+            self.drain(0..end, Direction::Backward);
             self.pos = 0;
             true
         } else {
@@ -361,7 +379,7 @@ impl LineBuffer {
     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 end = self.pos;
-            self.drain(pos..end);
+            self.drain(pos..end, Direction::Backward);
             self.pos = pos;
             true
         } else {
@@ -502,7 +520,7 @@ impl LineBuffer {
     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 start = self.pos;
-            self.drain(start..pos);
+            self.drain(start..pos, Direction::Forward);
             true
         } else {
             false
@@ -520,15 +538,15 @@ impl LineBuffer {
                 CharSearch::BackwardAfter(_) => {
                     let end = self.pos;
                     self.pos = pos;
-                    self.drain(pos..end);
+                    self.drain(pos..end, Direction::Backward);
                 }
                 CharSearch::ForwardBefore(_) => {
                     let start = self.pos;
-                    self.drain(start..pos);
+                    self.drain(start..pos, Direction::Forward);
                 }
                 CharSearch::Forward(c) => {
                     let start = self.pos;
-                    self.drain(start..pos + c.len_utf8());
+                    self.drain(start..pos + c.len_utf8(), Direction::Forward);
                 }
             };
             true
@@ -555,7 +573,7 @@ impl LineBuffer {
                 if start == end {
                     return false;
                 }
-                let word = self.drain(start..end).collect::<String>();
+                let word = self.drain(start..end, Direction::default()).collect::<String>();
                 let result = match a {
                     WordAction::CAPITALIZE => {
                         let ch = (&word).graphemes(true).next().unwrap();
@@ -590,10 +608,10 @@ impl LineBuffer {
 
         let w1 = self.buf[w1_beg..w1_end].to_owned();
 
-        let w2 = self.drain(w2_beg..w2_end).collect::<String>();
+        let w2 = self.drain(w2_beg..w2_end, Direction::default()).collect::<String>();
         self.insert_str(w2_beg, &w1);
 
-        self.drain(w1_beg..w1_end);
+        self.drain(w1_beg..w1_end, Direction::default());
         self.insert_str(w1_beg, &w2);
 
         self.pos = w2_end;
@@ -604,13 +622,13 @@ 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.drain(range);
+        self.drain(range, Direction::default());
         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 {
+        for (_, cl) in &self.cl {
             cl.borrow_mut().insert_str(idx, s);
         }
         if idx == self.buf.len() {
@@ -623,12 +641,13 @@ impl LineBuffer {
     }
 
     pub fn delete_range(&mut self, range: Range<usize>) {
-        self.drain(range);
+        self.set_pos(range.start);
+        self.drain(range, Direction::default());
     }
 
-    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]);
+    fn drain(&mut self, range: Range<usize>, dir: Direction) -> Drain {
+        for (_, cl) in &self.cl {
+            cl.borrow_mut().delete(range.start, &self.buf[range.start..range.end], dir);
         }
         self.buf.drain(range)
     }
@@ -741,7 +760,7 @@ mod test {
     use std::cell::RefCell;
     use std::rc::Rc;
     use keymap::{At, CharSearch, Word};
-    use super::{ChangeListener, LineBuffer, MAX_LINE, WordAction};
+    use super::{ChangeListener, Direction, LineBuffer, MAX_LINE, WordAction};
 
     struct Listener {
         deleted_str: Option<String>,
@@ -762,7 +781,7 @@ mod test {
     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) {
+        fn delete(&mut self, _: usize, string: &str, _: Direction) {
             self.deleted_str = Some(string.to_owned());
         }
     }
diff --git a/src/undo.rs b/src/undo.rs
index 1b070a89907660e1e980695fae88977d6f935fc6..710b4c09f4ded933a5543be5623f348e3a6f37da 100644
--- a/src/undo.rs
+++ b/src/undo.rs
@@ -1,5 +1,5 @@
 //! Undo API
-use line_buffer::LineBuffer;
+use line_buffer::{ChangeListener, Direction, LineBuffer};
 use std_unicode::str::UnicodeStr;
 use unicode_segmentation::UnicodeSegmentation;
 
@@ -202,10 +202,17 @@ impl Changeset {
             None => false,
         }
     }
+}
 
-    pub fn clear(&mut self) {
-        self.undos.clear();
-        self.redos.clear();
+impl ChangeListener for Changeset {
+    fn insert_char(&mut self, idx: usize, c: char) {
+        self.insert(idx, c);
+    }
+    fn insert_str(&mut self, idx: usize, string: &str) {
+        self.insert_str(idx, string);
+    }
+    fn delete(&mut self, idx: usize, string: &str, _: Direction) {
+        self.delete(idx, string);
     }
 }