Tests: Vi mode
diff --git a/src/test/common.rs b/src/test/common.rs
index 2d5a959..de00f37 100644
--- a/src/test/common.rs
+++ b/src/test/common.rs
@@ -1,150 +1,262 @@
 ///! Basic commands tests.
 use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
+use config::EditMode;
 use consts::KeyPress;
 use error::ReadlineError;
 
 #[test]
 fn home_key() {
-    assert_cursor(("", ""), &[KeyPress::Home, KeyPress::Enter], ("", ""));
-    assert_cursor(("Hi", ""), &[KeyPress::Home, KeyPress::Enter], ("", "Hi"));
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("", ""),
+            &[KeyPress::Home, KeyPress::Enter],
+            ("", ""),
+        );
+        assert_cursor(
+            *mode,
+            ("Hi", ""),
+            &[KeyPress::Home, KeyPress::Enter],
+            ("", "Hi"),
+        );
+    }
 }
 
 #[test]
 fn end_key() {
-    assert_cursor(("", ""), &[KeyPress::End, KeyPress::Enter], ("", ""));
-    assert_cursor(("H", "i"), &[KeyPress::End, KeyPress::Enter], ("Hi", ""));
-    assert_cursor(("", "Hi"), &[KeyPress::End, KeyPress::Enter], ("Hi", ""));
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(*mode, ("", ""), &[KeyPress::End, KeyPress::Enter], ("", ""));
+        assert_cursor(
+            *mode,
+            ("H", "i"),
+            &[KeyPress::End, KeyPress::Enter],
+            ("Hi", ""),
+        );
+        assert_cursor(
+            *mode,
+            ("", "Hi"),
+            &[KeyPress::End, KeyPress::Enter],
+            ("Hi", ""),
+        );
+    }
 }
 
 #[test]
 fn left_key() {
-    assert_cursor(("Hi", ""), &[KeyPress::Left, KeyPress::Enter], ("H", "i"));
-    assert_cursor(("H", "i"), &[KeyPress::Left, KeyPress::Enter], ("", "Hi"));
-    assert_cursor(("", "Hi"), &[KeyPress::Left, KeyPress::Enter], ("", "Hi"));
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("Hi", ""),
+            &[KeyPress::Left, KeyPress::Enter],
+            ("H", "i"),
+        );
+        assert_cursor(
+            *mode,
+            ("H", "i"),
+            &[KeyPress::Left, KeyPress::Enter],
+            ("", "Hi"),
+        );
+        assert_cursor(
+            *mode,
+            ("", "Hi"),
+            &[KeyPress::Left, KeyPress::Enter],
+            ("", "Hi"),
+        );
+    }
 }
 
 #[test]
 fn right_key() {
-    assert_cursor(("", ""), &[KeyPress::Right, KeyPress::Enter], ("", ""));
-    assert_cursor(("", "Hi"), &[KeyPress::Right, KeyPress::Enter], ("H", "i"));
-    assert_cursor(
-        ("B", "ye"),
-        &[KeyPress::Right, KeyPress::Enter],
-        ("By", "e"),
-    );
-    assert_cursor(("H", "i"), &[KeyPress::Right, KeyPress::Enter], ("Hi", ""));
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("", ""),
+            &[KeyPress::Right, KeyPress::Enter],
+            ("", ""),
+        );
+        assert_cursor(
+            *mode,
+            ("", "Hi"),
+            &[KeyPress::Right, KeyPress::Enter],
+            ("H", "i"),
+        );
+        assert_cursor(
+            *mode,
+            ("B", "ye"),
+            &[KeyPress::Right, KeyPress::Enter],
+            ("By", "e"),
+        );
+        assert_cursor(
+            *mode,
+            ("H", "i"),
+            &[KeyPress::Right, KeyPress::Enter],
+            ("Hi", ""),
+        );
+    }
 }
 
 #[test]
 fn enter_key() {
-    assert_line(&[KeyPress::Enter], "");
-    assert_line(&[KeyPress::Char('a'), KeyPress::Enter], "a");
-    assert_line_with_initial(("Hi", ""), &[KeyPress::Enter], "Hi");
-    assert_line_with_initial(("", "Hi"), &[KeyPress::Enter], "Hi");
-    assert_line_with_initial(("H", "i"), &[KeyPress::Enter], "Hi");
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_line(*mode, &[KeyPress::Enter], "");
+        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Enter], "a");
+        assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Enter], "Hi");
+        assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Enter], "Hi");
+        assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Enter], "Hi");
+    }
 }
 
 #[test]
 fn newline_key() {
-    assert_line(&[KeyPress::Ctrl('J')], "");
-    assert_line(&[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_line(*mode, &[KeyPress::Ctrl('J')], "");
+        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
+    }
 }
 
 #[test]
 fn eof_key() {
-    let mut editor = init_editor(&[KeyPress::Ctrl('D')]);
-    let err = editor.readline(">>");
-    assert_matches!(err, Err(ReadlineError::Eof));
-
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('D')]);
+        let err = editor.readline(">>");
+        assert_matches!(err, Err(ReadlineError::Eof));
+    }
     assert_line(
+        EditMode::Emacs,
         &[KeyPress::Char('a'), KeyPress::Ctrl('D'), KeyPress::Enter],
         "a",
     );
-    assert_line_with_initial(("", "Hi"), &[KeyPress::Ctrl('D'), KeyPress::Enter], "i");
+    assert_line(
+        EditMode::Vi,
+        &[KeyPress::Char('a'), KeyPress::Ctrl('D')],
+        "a",
+    );
+    assert_line_with_initial(
+        EditMode::Emacs,
+        ("", "Hi"),
+        &[KeyPress::Ctrl('D'), KeyPress::Enter],
+        "i",
+    );
+    assert_line_with_initial(EditMode::Vi, ("", "Hi"), &[KeyPress::Ctrl('D')], "Hi");
 }
 
 #[test]
 fn interrupt_key() {
-    let mut editor = init_editor(&[KeyPress::Ctrl('C')]);
-    let err = editor.readline(">>");
-    assert_matches!(err, Err(ReadlineError::Interrupted));
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
+        let err = editor.readline(">>");
+        assert_matches!(err, Err(ReadlineError::Interrupted));
 
-    let mut editor = init_editor(&[KeyPress::Ctrl('C')]);
-    let err = editor.readline_with_initial(">>", ("Hi", ""));
-    assert_matches!(err, Err(ReadlineError::Interrupted));
+        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
+        let err = editor.readline_with_initial(">>", ("Hi", ""));
+        assert_matches!(err, Err(ReadlineError::Interrupted));
+    }
 }
 
 #[test]
 fn delete_key() {
-    assert_cursor(("a", ""), &[KeyPress::Delete, KeyPress::Enter], ("a", ""));
-    assert_cursor(("", "a"), &[KeyPress::Delete, KeyPress::Enter], ("", ""));
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("a", ""),
+            &[KeyPress::Delete, KeyPress::Enter],
+            ("a", ""),
+        );
+        assert_cursor(
+            *mode,
+            ("", "a"),
+            &[KeyPress::Delete, KeyPress::Enter],
+            ("", ""),
+        );
+    }
 }
 
 #[test]
 fn ctrl_t() {
-    assert_cursor(
-        ("a", "b"),
-        &[KeyPress::Ctrl('T'), KeyPress::Enter],
-        ("ba", ""),
-    );
-    assert_cursor(
-        ("ab", "cd"),
-        &[KeyPress::Ctrl('T'), KeyPress::Enter],
-        ("acb", "d"),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("a", "b"),
+            &[KeyPress::Ctrl('T'), KeyPress::Enter],
+            ("ba", ""),
+        );
+        assert_cursor(
+            *mode,
+            ("ab", "cd"),
+            &[KeyPress::Ctrl('T'), KeyPress::Enter],
+            ("acb", "d"),
+        );
+    }
 }
 
 #[test]
 fn ctrl_u() {
-    assert_cursor(
-        ("start of line ", "end"),
-        &[KeyPress::Ctrl('U'), KeyPress::Enter],
-        ("", "end"),
-    );
-    assert_cursor(
-        ("", "end"),
-        &[KeyPress::Ctrl('U'), KeyPress::Enter],
-        ("", "end"),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("start of line ", "end"),
+            &[KeyPress::Ctrl('U'), KeyPress::Enter],
+            ("", "end"),
+        );
+        assert_cursor(
+            *mode,
+            ("", "end"),
+            &[KeyPress::Ctrl('U'), KeyPress::Enter],
+            ("", "end"),
+        );
+    }
 }
 
 #[test]
 fn ctrl_v() {
-    assert_cursor(
-        ("", ""),
-        &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
-        ("\t", ""),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("", ""),
+            &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
+            ("\t", ""),
+        );
+    }
 }
 
 #[test]
 fn ctrl_w() {
-    assert_cursor(
-        ("Hello, ", "world"),
-        &[KeyPress::Ctrl('W'), KeyPress::Enter],
-        ("", "world"),
-    );
-    assert_cursor(
-        ("Hello, world.", ""),
-        &[KeyPress::Ctrl('W'), KeyPress::Enter],
-        ("Hello, ", ""),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("Hello, ", "world"),
+            &[KeyPress::Ctrl('W'), KeyPress::Enter],
+            ("", "world"),
+        );
+        assert_cursor(
+            *mode,
+            ("Hello, world.", ""),
+            &[KeyPress::Ctrl('W'), KeyPress::Enter],
+            ("Hello, ", ""),
+        );
+    }
 }
 
 #[test]
 fn ctrl_y() {
-    assert_cursor(
-        ("Hello, ", "world"),
-        &[KeyPress::Ctrl('W'), KeyPress::Ctrl('Y'), KeyPress::Enter],
-        ("Hello, ", "world"),
-    );
+    for mode in &[EditMode::Emacs /* FIXME, EditMode::Vi */] {
+        assert_cursor(
+            *mode,
+            ("Hello, ", "world"),
+            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('Y'), KeyPress::Enter],
+            ("Hello, ", "world"),
+        );
+    }
 }
 
 #[test]
 fn ctrl__() {
-    assert_cursor(
-        ("Hello, ", "world"),
-        &[KeyPress::Ctrl('W'), KeyPress::Ctrl('_'), KeyPress::Enter],
-        ("Hello, ", "world"),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_cursor(
+            *mode,
+            ("Hello, ", "world"),
+            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('_'), KeyPress::Enter],
+            ("Hello, ", "world"),
+        );
+    }
 }
diff --git a/src/test/emacs.rs b/src/test/emacs.rs
index 6494b1a..67a1b10 100644
--- a/src/test/emacs.rs
+++ b/src/test/emacs.rs
@@ -1,10 +1,12 @@
 //! Emacs specific key bindings
 use super::{assert_cursor, assert_history};
+use config::EditMode;
 use consts::KeyPress;
 
 #[test]
 fn ctrl_a() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Ctrl('A'), KeyPress::Enter],
         ("", "Hi"),
@@ -14,6 +16,7 @@
 #[test]
 fn ctrl_e() {
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[KeyPress::Ctrl('E'), KeyPress::Enter],
         ("Hi", ""),
@@ -23,16 +26,19 @@
 #[test]
 fn ctrl_b() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Ctrl('B'), KeyPress::Enter],
         ("H", "i"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Meta('2'), KeyPress::Ctrl('B'), KeyPress::Enter],
         ("", "Hi"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[
             KeyPress::Meta('-'),
@@ -47,16 +53,19 @@
 #[test]
 fn ctrl_f() {
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[KeyPress::Ctrl('F'), KeyPress::Enter],
         ("H", "i"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[KeyPress::Meta('2'), KeyPress::Ctrl('F'), KeyPress::Enter],
         ("Hi", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[
             KeyPress::Meta('-'),
@@ -71,16 +80,19 @@
 #[test]
 fn ctrl_h() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Ctrl('H'), KeyPress::Enter],
         ("H", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Meta('2'), KeyPress::Ctrl('H'), KeyPress::Enter],
         ("", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[
             KeyPress::Meta('-'),
@@ -94,13 +106,20 @@
 
 #[test]
 fn backspace() {
-    assert_cursor(("", ""), &[KeyPress::Backspace, KeyPress::Enter], ("", ""));
     assert_cursor(
+        EditMode::Emacs,
+        ("", ""),
+        &[KeyPress::Backspace, KeyPress::Enter],
+        ("", ""),
+    );
+    assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Backspace, KeyPress::Enter],
         ("H", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[KeyPress::Backspace, KeyPress::Enter],
         ("", "Hi"),
@@ -110,16 +129,19 @@
 #[test]
 fn ctrl_k() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Ctrl('K'), KeyPress::Enter],
         ("Hi", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hi"),
         &[KeyPress::Ctrl('K'), KeyPress::Enter],
         ("", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("B", "ye"),
         &[KeyPress::Ctrl('K'), KeyPress::Enter],
         ("B", ""),
@@ -129,6 +151,7 @@
 #[test]
 fn ctrl_n() {
     assert_history(
+        EditMode::Emacs,
         &["line1", "line2"],
         &[
             KeyPress::Ctrl('P'),
@@ -143,6 +166,7 @@
 #[test]
 fn ctrl_p() {
     assert_history(
+        EditMode::Emacs,
         &["line1"],
         &[KeyPress::Ctrl('P'), KeyPress::Enter],
         ("line1", ""),
@@ -162,6 +186,7 @@
 #[test]
 fn ctrl_x_ctrl_u() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hello, ", "world"),
         &[
             KeyPress::Ctrl('W'),
@@ -176,16 +201,19 @@
 #[test]
 fn meta_b() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hello, world!", ""),
         &[KeyPress::Meta('B'), KeyPress::Enter],
         ("Hello, ", "world!"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("Hello, world!", ""),
         &[KeyPress::Meta('2'), KeyPress::Meta('B'), KeyPress::Enter],
         ("", "Hello, world!"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hello, world!"),
         &[KeyPress::Meta('-'), KeyPress::Meta('B'), KeyPress::Enter],
         ("Hello", ", world!"),
@@ -195,16 +223,19 @@
 #[test]
 fn meta_f() {
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hello, world!"),
         &[KeyPress::Meta('F'), KeyPress::Enter],
         ("Hello", ", world!"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "Hello, world!"),
         &[KeyPress::Meta('2'), KeyPress::Meta('F'), KeyPress::Enter],
         ("Hello, world", "!"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("Hello, world!", ""),
         &[KeyPress::Meta('-'), KeyPress::Meta('F'), KeyPress::Enter],
         ("Hello, ", "world!"),
@@ -214,11 +245,13 @@
 #[test]
 fn meta_c() {
     assert_cursor(
+        EditMode::Emacs,
         ("hi", ""),
         &[KeyPress::Meta('C'), KeyPress::Enter],
         ("hi", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "hi"),
         &[KeyPress::Meta('C'), KeyPress::Enter],
         ("Hi", ""),
@@ -234,11 +267,13 @@
 #[test]
 fn meta_l() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hi", ""),
         &[KeyPress::Meta('L'), KeyPress::Enter],
         ("Hi", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "HI"),
         &[KeyPress::Meta('L'), KeyPress::Enter],
         ("hi", ""),
@@ -254,11 +289,13 @@
 #[test]
 fn meta_u() {
     assert_cursor(
+        EditMode::Emacs,
         ("hi", ""),
         &[KeyPress::Meta('U'), KeyPress::Enter],
         ("hi", ""),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("", "hi"),
         &[KeyPress::Meta('U'), KeyPress::Enter],
         ("HI", ""),
@@ -274,11 +311,13 @@
 #[test]
 fn meta_d() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hello", ", world!"),
         &[KeyPress::Meta('D'), KeyPress::Enter],
         ("Hello", "!"),
     );
     assert_cursor(
+        EditMode::Emacs,
         ("Hello", ", world!"),
         &[KeyPress::Meta('2'), KeyPress::Meta('D'), KeyPress::Enter],
         ("Hello", ""),
@@ -288,6 +327,7 @@
 #[test]
 fn meta_t() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hello", ", world!"),
         &[KeyPress::Meta('T'), KeyPress::Enter],
         ("world, Hello", "!"),
@@ -303,6 +343,7 @@
 #[test]
 fn meta_y() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hello, world", "!"),
         &[
             KeyPress::Ctrl('W'),
@@ -319,6 +360,7 @@
 #[test]
 fn meta_backspace() {
     assert_cursor(
+        EditMode::Emacs,
         ("Hello, wor", "ld!"),
         &[KeyPress::Meta('\x08'), KeyPress::Enter],
         ("Hello, ", "ld!"),
@@ -328,6 +370,7 @@
 #[test]
 fn meta_digit() {
     assert_cursor(
+        EditMode::Emacs,
         ("", ""),
         &[KeyPress::Meta('3'), KeyPress::Char('h'), KeyPress::Enter],
         ("hhh", ""),
diff --git a/src/test/history.rs b/src/test/history.rs
index 2397884..faa7a3f 100644
--- a/src/test/history.rs
+++ b/src/test/history.rs
@@ -1,140 +1,177 @@
 //! History related commands tests
 use super::assert_history;
+use config::EditMode;
 use consts::KeyPress;
 
 #[test]
 fn down_key() {
-    assert_history(&["line1"], &[KeyPress::Down, KeyPress::Enter], ("", ""));
-    assert_history(
-        &["line1", "line2"],
-        &[KeyPress::Up, KeyPress::Up, KeyPress::Down, KeyPress::Enter],
-        ("line2", ""),
-    );
-    assert_history(
-        &["line1"],
-        &[
-            KeyPress::Char('a'),
-            KeyPress::Up,
-            KeyPress::Down, // restore original line
-            KeyPress::Enter,
-        ],
-        ("a", ""),
-    );
-    assert_history(
-        &["line1"],
-        &[
-            KeyPress::Char('a'),
-            KeyPress::Down, // noop
-            KeyPress::Enter,
-        ],
-        ("a", ""),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_history(
+            *mode,
+            &["line1"],
+            &[KeyPress::Down, KeyPress::Enter],
+            ("", ""),
+        );
+        assert_history(
+            *mode,
+            &["line1", "line2"],
+            &[KeyPress::Up, KeyPress::Up, KeyPress::Down, KeyPress::Enter],
+            ("line2", ""),
+        );
+        assert_history(
+            *mode,
+            &["line1"],
+            &[
+                KeyPress::Char('a'),
+                KeyPress::Up,
+                KeyPress::Down, // restore original line
+                KeyPress::Enter,
+            ],
+            ("a", ""),
+        );
+        assert_history(
+            *mode,
+            &["line1"],
+            &[
+                KeyPress::Char('a'),
+                KeyPress::Down, // noop
+                KeyPress::Enter,
+            ],
+            ("a", ""),
+        );
+    }
 }
 
 #[test]
 fn up_key() {
-    assert_history(&[], &[KeyPress::Up, KeyPress::Enter], ("", ""));
-    assert_history(&["line1"], &[KeyPress::Up, KeyPress::Enter], ("line1", ""));
-    assert_history(
-        &["line1", "line2"],
-        &[KeyPress::Up, KeyPress::Up, KeyPress::Enter],
-        ("line1", ""),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_history(*mode, &[], &[KeyPress::Up, KeyPress::Enter], ("", ""));
+        assert_history(
+            *mode,
+            &["line1"],
+            &[KeyPress::Up, KeyPress::Enter],
+            ("line1", ""),
+        );
+        assert_history(
+            *mode,
+            &["line1", "line2"],
+            &[KeyPress::Up, KeyPress::Up, KeyPress::Enter],
+            ("line1", ""),
+        );
+    }
 }
 
 #[test]
 fn ctrl_r() {
-    assert_history(
-        &[],
-        &[KeyPress::Ctrl('R'), KeyPress::Char('o'), KeyPress::Enter],
-        ("o", ""),
-    );
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('o'),
-            KeyPress::Right, // just to assert cursor pos
-            KeyPress::Enter,
-        ],
-        ("cargo", ""),
-    );
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('u'),
-            KeyPress::Right, // just to assert cursor pos
-            KeyPress::Enter,
-        ],
-        ("ru", "stc"),
-    );
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('r'),
-            KeyPress::Char('u'),
-            KeyPress::Right, // just to assert cursor pos
-            KeyPress::Enter,
-        ],
-        ("r", "ustc"),
-    );
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('r'),
-            KeyPress::Ctrl('R'),
-            KeyPress::Right, // just to assert cursor pos
-            KeyPress::Enter,
-        ],
-        ("r", "ustc"),
-    );
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('r'),
-            KeyPress::Char('z'), // no match
-            KeyPress::Right,     // just to assert cursor pos
-            KeyPress::Enter,
-        ],
-        ("car", "go"),
-    );
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Char('a'),
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('r'),
-            KeyPress::Ctrl('G'), // abort (FIXME: doesn't work with vi mode)
-            KeyPress::Enter,
-        ],
-        ("a", ""),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_history(
+            *mode,
+            &[],
+            &[KeyPress::Ctrl('R'), KeyPress::Char('o'), KeyPress::Enter],
+            ("o", ""),
+        );
+        assert_history(
+            *mode,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('o'),
+                KeyPress::Right, // just to assert cursor pos
+                KeyPress::Enter,
+            ],
+            ("cargo", ""),
+        );
+        assert_history(
+            *mode,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('u'),
+                KeyPress::Right, // just to assert cursor pos
+                KeyPress::Enter,
+            ],
+            ("ru", "stc"),
+        );
+        assert_history(
+            *mode,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('r'),
+                KeyPress::Char('u'),
+                KeyPress::Right, // just to assert cursor pos
+                KeyPress::Enter,
+            ],
+            ("r", "ustc"),
+        );
+        assert_history(
+            *mode,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('r'),
+                KeyPress::Ctrl('R'),
+                KeyPress::Right, // just to assert cursor pos
+                KeyPress::Enter,
+            ],
+            ("r", "ustc"),
+        );
+        assert_history(
+            *mode,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('r'),
+                KeyPress::Char('z'), // no match
+                KeyPress::Right,     // just to assert cursor pos
+                KeyPress::Enter,
+            ],
+            ("car", "go"),
+        );
+        assert_history(
+            EditMode::Emacs,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Char('a'),
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('r'),
+                KeyPress::Ctrl('G'), // abort (FIXME: doesn't work with vi mode)
+                KeyPress::Enter,
+            ],
+            ("a", ""),
+        );
+    }
 }
 
 #[test]
 fn ctrl_s() {
-    assert_history(
-        &["rustc", "cargo"],
-        &[
-            KeyPress::Ctrl('R'),
-            KeyPress::Char('r'),
-            KeyPress::Ctrl('R'),
-            KeyPress::Ctrl('S'),
-            KeyPress::Right, // just to assert cursor pos
-            KeyPress::Enter,
-        ],
-        ("car", "go"),
-    );
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_history(
+            *mode,
+            &["rustc", "cargo"],
+            &[
+                KeyPress::Ctrl('R'),
+                KeyPress::Char('r'),
+                KeyPress::Ctrl('R'),
+                KeyPress::Ctrl('S'),
+                KeyPress::Right, // just to assert cursor pos
+                KeyPress::Enter,
+            ],
+            ("car", "go"),
+        );
+    }
 }
 
 #[test]
 fn meta_lt() {
-    assert_history(&[""], &[KeyPress::Meta('<'), KeyPress::Enter], ("", ""));
     assert_history(
+        EditMode::Emacs,
+        &[""],
+        &[KeyPress::Meta('<'), KeyPress::Enter],
+        ("", ""),
+    );
+    assert_history(
+        EditMode::Emacs,
         &["rustc", "cargo"],
         &[KeyPress::Meta('<'), KeyPress::Enter],
         ("rustc", ""),
@@ -143,13 +180,20 @@
 
 #[test]
 fn meta_gt() {
-    assert_history(&[""], &[KeyPress::Meta('>'), KeyPress::Enter], ("", ""));
     assert_history(
+        EditMode::Emacs,
+        &[""],
+        &[KeyPress::Meta('>'), KeyPress::Enter],
+        ("", ""),
+    );
+    assert_history(
+        EditMode::Emacs,
         &["rustc", "cargo"],
         &[KeyPress::Meta('<'), KeyPress::Meta('>'), KeyPress::Enter],
         ("", ""),
     );
     assert_history(
+        EditMode::Emacs,
         &["rustc", "cargo"],
         &[
             KeyPress::Char('a'),
diff --git a/src/test/mod.rs b/src/test/mod.rs
index f9c9538..6732e08 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -4,7 +4,7 @@
 
 use super::{Editor, Result};
 use completion::Completer;
-use config::Config;
+use config::{Config, EditMode};
 use consts::KeyPress;
 use edit::init_state;
 use keymap::{Cmd, InputState};
@@ -13,9 +13,12 @@
 mod common;
 mod emacs;
 mod history;
+mod vi_cmd;
+mod vi_insert;
 
-fn init_editor(keys: &[KeyPress]) -> Editor<()> {
-    let mut editor = Editor::<()>::new();
+fn init_editor(mode: EditMode, keys: &[KeyPress]) -> Editor<()> {
+    let config = Config::builder().edit_mode(mode).build();
+    let mut editor = Editor::<()>::with_config(config);
     editor.term.keys.extend(keys.iter().cloned());
     editor
 }
@@ -48,25 +51,43 @@
     assert_eq!(4, s.line.pos());
 }
 
-fn assert_line(keys: &[KeyPress], expected_line: &str) {
-    let mut editor = init_editor(keys);
+// `keys`: keys to press
+// `expected_line`: line after enter key
+fn assert_line(mode: EditMode, keys: &[KeyPress], expected_line: &str) {
+    let mut editor = init_editor(mode, keys);
     let actual_line = editor.readline(">>").unwrap();
     assert_eq!(expected_line, actual_line);
 }
-fn assert_line_with_initial(initial: (&str, &str), keys: &[KeyPress], expected_line: &str) {
-    let mut editor = init_editor(keys);
+
+// `initial`: line status before `keys` pressed: strings before and after cursor
+// `keys`: keys to press
+// `expected_line`: line after enter key
+fn assert_line_with_initial(
+    mode: EditMode,
+    initial: (&str, &str),
+    keys: &[KeyPress],
+    expected_line: &str,
+) {
+    let mut editor = init_editor(mode, keys);
     let actual_line = editor.readline_with_initial(">>", initial).unwrap();
     assert_eq!(expected_line, actual_line);
 }
-fn assert_cursor(initial: (&str, &str), keys: &[KeyPress], expected: (&str, &str)) {
-    let mut editor = init_editor(keys);
+
+// `initial`: line status before `keys` pressed: strings before and after cursor
+// `keys`: keys to press
+// `expected`: line status before enter key: strings before and after cursor
+fn assert_cursor(mode: EditMode, initial: (&str, &str), keys: &[KeyPress], expected: (&str, &str)) {
+    let mut editor = init_editor(mode, keys);
     let actual_line = editor.readline_with_initial("", initial).unwrap();
     assert_eq!(expected.0.to_owned() + expected.1, actual_line);
     assert_eq!(expected.0.len(), editor.term.cursor);
 }
 
-fn assert_history(entries: &[&str], keys: &[KeyPress], expected: (&str, &str)) {
-    let mut editor = init_editor(keys);
+// `entries`: history entries before `keys` pressed
+// `keys`: keys to press
+// `expected`: line status before enter key: strings before and after cursor
+fn assert_history(mode: EditMode, entries: &[&str], keys: &[KeyPress], expected: (&str, &str)) {
+    let mut editor = init_editor(mode, keys);
     for entry in entries {
         editor.history.add(*entry);
     }
@@ -77,5 +98,7 @@
 
 #[test]
 fn unknown_esc_key() {
-    assert_line(&[KeyPress::UnknownEscSeq, KeyPress::Enter], "");
+    for mode in &[EditMode::Emacs, EditMode::Vi] {
+        assert_line(*mode, &[KeyPress::UnknownEscSeq, KeyPress::Enter], "");
+    }
 }
diff --git a/src/test/vi_cmd.rs b/src/test/vi_cmd.rs
new file mode 100644
index 0000000..b621758
--- /dev/null
+++ b/src/test/vi_cmd.rs
@@ -0,0 +1,390 @@
+//! Vi command mode specific key bindings
+use super::{assert_cursor, assert_history};
+use config::EditMode;
+use consts::KeyPress;
+
+#[test]
+fn dollar() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hi"),
+        &[KeyPress::Esc, KeyPress::Char('$'), KeyPress::Enter],
+        ("Hi", ""), // FIXME
+    );
+}
+
+/*#[test]
+fn dot() {
+    // TODO
+}*/
+
+#[test]
+fn zero() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hi", ""),
+        &[KeyPress::Esc, KeyPress::Char('0'), KeyPress::Enter],
+        ("", "Hi"),
+    );
+}
+
+#[test]
+fn caret() {
+    assert_cursor(
+        EditMode::Vi,
+        (" Hi", ""),
+        &[KeyPress::Esc, KeyPress::Char('^'), KeyPress::Enter],
+        (" ", "Hi"),
+    );
+}
+
+#[test]
+fn a() {
+    assert_cursor(
+        EditMode::Vi,
+        ("B", "e"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('a'),
+            KeyPress::Char('y'),
+            KeyPress::Enter,
+        ],
+        ("By", "e"),
+    );
+}
+
+#[test]
+fn uppercase_a() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "By"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('A'),
+            KeyPress::Char('e'),
+            KeyPress::Enter,
+        ],
+        ("Bye", ""),
+    );
+}
+
+#[test]
+fn b() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, world!", ""),
+        &[KeyPress::Esc, KeyPress::Char('b'), KeyPress::Enter],
+        ("Hello, ", "world!"),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, world!", ""),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('2'),
+            KeyPress::Char('b'),
+            KeyPress::Enter,
+        ],
+        ("Hello", ", world!"),
+    );
+}
+
+#[test]
+fn uppercase_b() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, world!", ""),
+        &[KeyPress::Esc, KeyPress::Char('B'), KeyPress::Enter],
+        ("Hello, ", "world!"),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, world!", ""),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('2'),
+            KeyPress::Char('B'),
+            KeyPress::Enter,
+        ],
+        ("", "Hello, world!"),
+    );
+}
+
+#[test]
+fn ctrl_k() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hi", ""),
+        &[KeyPress::Esc, KeyPress::Ctrl('K'), KeyPress::Enter],
+        ("H", ""),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hi"),
+        &[KeyPress::Esc, KeyPress::Ctrl('K'), KeyPress::Enter],
+        ("", ""),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("By", "e"),
+        &[KeyPress::Esc, KeyPress::Ctrl('K'), KeyPress::Enter],
+        ("B", ""),
+    );
+}
+
+#[test]
+fn e() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[KeyPress::Esc, KeyPress::Char('e'), KeyPress::Enter],
+        ("Hell", "o, world!"),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('2'),
+            KeyPress::Char('e'),
+            KeyPress::Enter,
+        ],
+        ("Hello, worl", "d!"),
+    );
+}
+
+#[test]
+fn uppercase_e() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[KeyPress::Esc, KeyPress::Char('E'), KeyPress::Enter],
+        ("Hello", ", world!"),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('2'),
+            KeyPress::Char('E'),
+            KeyPress::Enter,
+        ],
+        ("Hello, world", "!"),
+    );
+}
+
+#[test]
+fn i() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Be", ""),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('i'),
+            KeyPress::Char('y'),
+            KeyPress::Enter,
+        ],
+        ("By", "e"),
+    );
+}
+
+#[test]
+fn uppercase_i() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Be", ""),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('I'),
+            KeyPress::Char('y'),
+            KeyPress::Enter,
+        ],
+        ("y", "Be"),
+    );
+}
+
+#[test]
+fn u() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, ", "world"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Ctrl('W'),
+            KeyPress::Char('u'),
+            KeyPress::Enter,
+        ],
+        ("Hello,", " world"),
+    );
+}
+
+#[test]
+fn w() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[KeyPress::Esc, KeyPress::Char('w'), KeyPress::Enter],
+        ("Hello", ", world!"),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('2'),
+            KeyPress::Char('w'),
+            KeyPress::Enter,
+        ],
+        ("Hello, ", "world!"),
+    );
+}
+
+#[test]
+fn uppercase_w() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[KeyPress::Esc, KeyPress::Char('W'), KeyPress::Enter],
+        ("Hello, ", "world!"),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hello, world!"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Char('2'),
+            KeyPress::Char('W'),
+            KeyPress::Enter,
+        ],
+        ("Hello, world", "!"),
+    );
+}
+
+#[test]
+fn x() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", "a"),
+        &[KeyPress::Esc, KeyPress::Char('x'), KeyPress::Enter],
+        ("", ""),
+    );
+}
+
+#[test]
+fn uppercase_x() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hi", ""),
+        &[KeyPress::Esc, KeyPress::Char('X'), KeyPress::Enter],
+        ("", "i"),
+    );
+}
+
+#[test]
+fn h() {
+    for key in &[
+        KeyPress::Char('h'),
+        KeyPress::Ctrl('H'),
+        KeyPress::Backspace,
+    ] {
+        assert_cursor(
+            EditMode::Vi,
+            ("Bye", ""),
+            &[KeyPress::Esc, *key, KeyPress::Enter],
+            ("B", "ye"),
+        );
+        assert_cursor(
+            EditMode::Vi,
+            ("Bye", ""),
+            &[KeyPress::Esc, KeyPress::Char('2'), *key, KeyPress::Enter],
+            ("", "Bye"),
+        );
+    }
+}
+
+#[test]
+fn l() {
+    for key in &[KeyPress::Char('l'), KeyPress::Char(' ')] {
+        assert_cursor(
+            EditMode::Vi,
+            ("", "Hi"),
+            &[KeyPress::Esc, *key, KeyPress::Enter],
+            ("H", "i"),
+        );
+        assert_cursor(
+            EditMode::Vi,
+            ("", "Hi"),
+            &[KeyPress::Esc, KeyPress::Char('2'), *key, KeyPress::Enter],
+            ("Hi", ""),
+        );
+    }
+}
+
+#[test]
+fn j() {
+    for key in &[
+        KeyPress::Char('j'),
+        KeyPress::Char('+'),
+        KeyPress::Ctrl('N'),
+    ] {
+        assert_history(
+            EditMode::Vi,
+            &["line1", "line2"],
+            &[
+                KeyPress::Esc,
+                KeyPress::Ctrl('P'),
+                KeyPress::Ctrl('P'),
+                *key,
+                KeyPress::Enter,
+            ],
+            ("line2", ""),
+        );
+    }
+}
+
+#[test]
+fn k() {
+    for key in &[
+        KeyPress::Char('k'),
+        KeyPress::Char('-'),
+        KeyPress::Ctrl('P'),
+    ] {
+        assert_history(
+            EditMode::Vi,
+            &["line1"],
+            &[KeyPress::Esc, *key, KeyPress::Enter],
+            ("line1", ""),
+        );
+    }
+}
+
+#[test]
+fn p() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, ", "world"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Ctrl('W'),
+            KeyPress::Char('p'),
+            KeyPress::Enter,
+        ],
+        (" Hello", ",world"),
+    );
+}
+
+#[test]
+fn uppercase_p() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hello, ", "world"),
+        &[
+            KeyPress::Esc,
+            KeyPress::Ctrl('W'),
+            KeyPress::Char('P'),
+            KeyPress::Enter,
+        ],
+        ("Hello", ", world"),
+    );
+}
diff --git a/src/test/vi_insert.rs b/src/test/vi_insert.rs
new file mode 100644
index 0000000..cf86680
--- /dev/null
+++ b/src/test/vi_insert.rs
@@ -0,0 +1,56 @@
+//! Vi insert mode specific key bindings
+use super::assert_cursor;
+use config::EditMode;
+use consts::KeyPress;
+
+#[test]
+fn insert_mode_by_default() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", ""),
+        &[KeyPress::Char('a'), KeyPress::Enter],
+        ("a", ""),
+    );
+}
+
+#[test]
+fn ctrl_h() {
+    assert_cursor(
+        EditMode::Vi,
+        ("Hi", ""),
+        &[KeyPress::Ctrl('H'), KeyPress::Enter],
+        ("H", ""),
+    );
+}
+
+#[test]
+fn backspace() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", ""),
+        &[KeyPress::Backspace, KeyPress::Enter],
+        ("", ""),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("Hi", ""),
+        &[KeyPress::Backspace, KeyPress::Enter],
+        ("H", ""),
+    );
+    assert_cursor(
+        EditMode::Vi,
+        ("", "Hi"),
+        &[KeyPress::Backspace, KeyPress::Enter],
+        ("", "Hi"),
+    );
+}
+
+#[test]
+fn esc() {
+    assert_cursor(
+        EditMode::Vi,
+        ("", ""),
+        &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Enter],
+        ("", "a"),
+    );
+}