Repeated insert and replace char
diff --git a/src/lib.rs b/src/lib.rs
index 1b0c625..52a0bc7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -309,9 +309,9 @@
 
 /// Insert the character `ch` at cursor current position.
 fn edit_insert(s: &mut State, ch: char, count: u16) -> Result<()> {
-    if let Some(push) = s.line.insert(ch) {
+    if let Some(push) = s.line.insert(ch, count) {
         if push {
-            if s.cursor.col + ch.width().unwrap_or(0) < s.cols {
+            if count == 1 && s.cursor.col + ch.width().unwrap_or(0) < s.cols {
                 // Avoid a full update of the line in the trivial case.
                 let cursor = calculate_position(&s.line[..s.line.pos()], s.prompt_size, s.cols);
                 s.cursor = cursor;
@@ -327,6 +327,17 @@
     }
 }
 
+/// Replace a single (or count) character(s) under the cursor (Vi mode)
+fn edit_replace_char(s: &mut State, ch: char, count: u16) -> Result<()> {
+    if s.line.delete(count) {
+        s.line.insert(ch, count);
+        s.line.move_left(1);
+        s.refresh_line()
+    } else {
+        Ok(())
+    }
+}
+
 // Yank/paste `text` at current position.
 fn edit_yank(s: &mut State, text: &str, anchor: Anchor, count: u16) -> Result<()> {
     if s.line.yank(text, anchor, count).is_some() {
@@ -874,9 +885,7 @@
             }
             Cmd::Replace(count, c) => {
                 editor.kill_ring.reset();
-                try!(edit_delete(&mut s, count));
-                try!(edit_insert(&mut s, c, count));
-                try!(edit_move_left(&mut s, 1))
+                try!(edit_replace_char(&mut s, c, count));
             }
             Cmd::EndOfFile => {
                 editor.kill_ring.reset();
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index bd05986..fa113d0 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -1,4 +1,5 @@
 //! Line buffer with current cursor position
+use std::iter;
 use std::ops::{Deref, Range};
 use keymap::{Anchor, At, CharSearch, Word};
 
@@ -108,16 +109,25 @@
     /// and advance cursor position accordingly.
     /// Return `None` when maximum buffer size has been reached,
     /// `true` when the character has been appended to the end of the line.
-    pub fn insert(&mut self, ch: char) -> Option<bool> {
-        let shift = ch.len_utf8();
+    pub fn insert(&mut self, ch: char, count: u16) -> Option<bool> {
+        let shift = ch.len_utf8() * count as usize;
         if self.buf.len() + shift > self.buf.capacity() {
             return None;
         }
         let push = self.pos == self.buf.len();
         if push {
-            self.buf.push(ch);
+            self.buf.reserve(shift);
+            for _ in 0..count {
+                self.buf.push(ch);
+            }
         } else {
-            self.buf.insert(self.pos, ch);
+            if count == 1 {
+                self.buf.insert(self.pos, ch);
+            } else {
+                let text = iter::repeat(ch).take(count as usize).collect::<String>();
+                let pos = self.pos;
+                self.insert_str(pos, &text);
+            }
         }
         self.pos += shift;
         Some(push)
@@ -195,15 +205,6 @@
         }
     }
 
-    /// Replace a single character under the cursor (Vi mode)
-    pub fn replace_char(&mut self, ch: char) -> Option<bool> {
-        if self.delete(1) {
-            self.insert(ch)
-        } else {
-            None
-        }
-    }
-
     /// Delete the character at the right of the cursor without altering the cursor
     /// position. Basically this is what happens with the "Delete" keyboard key.
     pub fn delete(&mut self, count: u16) -> bool {
@@ -639,18 +640,18 @@
     #[test]
     fn insert() {
         let mut s = LineBuffer::with_capacity(MAX_LINE);
-        let push = s.insert('α').unwrap();
+        let push = s.insert('α', 1).unwrap();
         assert_eq!("α", s.buf);
         assert_eq!(2, s.pos);
         assert_eq!(true, push);
 
-        let push = s.insert('ß').unwrap();
+        let push = s.insert('ß', 1).unwrap();
         assert_eq!("αß", s.buf);
         assert_eq!(4, s.pos);
         assert_eq!(true, push);
 
         s.pos = 0;
-        let push = s.insert('γ').unwrap();
+        let push = s.insert('γ', 1).unwrap();
         assert_eq!("γαß", s.buf);
         assert_eq!(2, s.pos);
         assert_eq!(false, push);