Reuse rendering buffer

(cherry picked from commit 4d3da773f2e24625566ebe0a469fd31bbee38649)
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index e8c7db4..d6767fc 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -34,7 +34,7 @@
 pub trait Renderer {
     fn move_cursor(&mut self, old: Position, new: Position) -> Result<()>;
 
-    /// Display prompt, line and cursor in terminal output
+    /// Display `prompt`, line and cursor in terminal output
     fn refresh_line(
         &mut self,
         prompt: &str,
@@ -47,8 +47,7 @@
     ) -> Result<(Position, Position)>;
 
     /// Calculate the number of columns and rows used to display `s` on a
-    /// `cols` width terminal
-    /// starting at `orig`.
+    /// `cols` width terminal starting at `orig`.
     fn calculate_position(&self, s: &str, orig: Position) -> Position;
 
     fn write_and_flush(&mut self, buf: &[u8]) -> Result<()>;
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index 97821e8..5a8b20f 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -369,6 +369,7 @@
 pub struct PosixRenderer {
     out: Stdout,
     cols: usize, // Number of columns in terminal
+    buffer: String,
 }
 
 impl PosixRenderer {
@@ -377,6 +378,7 @@
         PosixRenderer {
             out: io::stdout(),
             cols,
+            buffer: String::with_capacity(1024),
         }
     }
 }
@@ -433,7 +435,7 @@
         highlighter: Option<&Highlighter>,
     ) -> Result<(Position, Position)> {
         use std::fmt::Write;
-        let mut ab = String::new();
+        self.buffer.clear();
 
         // calculate the position of the end of the input line
         let end_pos = self.calculate_position(line, prompt_size);
@@ -445,53 +447,55 @@
         let cursor_row_movement = old_rows.checked_sub(current_row).unwrap_or(0);
         // move the cursor down as required
         if cursor_row_movement > 0 {
-            write!(ab, "\x1b[{}B", cursor_row_movement).unwrap();
+            write!(self.buffer, "\x1b[{}B", cursor_row_movement).unwrap();
         }
         // clear old rows
         for _ in 0..old_rows {
-            ab.push_str("\r\x1b[0K\x1b[A");
+            self.buffer.push_str("\r\x1b[0K\x1b[A");
         }
         // clear the line
-        ab.push_str("\r\x1b[0K");
+        self.buffer.push_str("\r\x1b[0K");
 
         if let Some(highlighter) = highlighter {
             // display the prompt
-            ab.push_str(&highlighter.highlight_prompt(prompt));
+            self.buffer.push_str(&highlighter.highlight_prompt(prompt));
             // display the input line
-            ab.push_str(&highlighter.highlight(line, line.pos()));
+            self.buffer
+                .push_str(&highlighter.highlight(line, line.pos()));
         } else {
             // display the prompt
-            ab.push_str(prompt);
+            self.buffer.push_str(prompt);
             // display the input line
-            ab.push_str(line);
+            self.buffer.push_str(line);
         }
         // display hint
         if let Some(hint) = hint {
             let truncate = truncate(&hint, end_pos.col, self.cols);
             if let Some(highlighter) = highlighter {
-                ab.push_str(&highlighter.highlight_hint(truncate));
+                self.buffer.push_str(&highlighter.highlight_hint(truncate));
             } else {
-                ab.push_str(truncate);
+                self.buffer.push_str(truncate);
             }
         }
         // we have to generate our own newline on line wrap
         if end_pos.col == 0 && end_pos.row > 0 {
-            ab.push_str("\n");
+            self.buffer.push_str("\n");
         }
         // position the cursor
         let cursor_row_movement = end_pos.row - cursor.row;
         // move the cursor up as required
         if cursor_row_movement > 0 {
-            write!(ab, "\x1b[{}A", cursor_row_movement).unwrap();
+            write!(self.buffer, "\x1b[{}A", cursor_row_movement).unwrap();
         }
         // position the cursor within the line
         if cursor.col > 0 {
-            write!(ab, "\r\x1b[{}C", cursor.col).unwrap();
+            write!(self.buffer, "\r\x1b[{}C", cursor.col).unwrap();
         } else {
-            ab.push('\r');
+            self.buffer.push('\r');
         }
 
-        try!(self.write_and_flush(ab.as_bytes()));
+        try!(self.out.write_all(self.buffer.as_bytes()));
+        try!(self.out.flush());
         Ok((cursor, end_pos))
     }
 
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index 098cae4..313f26e 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -230,6 +230,7 @@
     out: Stdout,
     handle: HANDLE,
     cols: usize, // Number of columns in terminal
+    buffer: String,
 }
 
 impl ConsoleRenderer {
@@ -240,6 +241,7 @@
             out: io::stdout(),
             handle,
             cols,
+            buffer: String::with_capacity(1024),
         }
     }
 
@@ -307,29 +309,31 @@
             (info.dwSize.X * (old_rows as i16 + 1)) as DWORD,
             info.dwCursorPosition,
         ));
-        let mut ab = String::new();
+        self.buffer.clear();
         if let Some(highlighter) = highlighter {
             // TODO handle ansi escape code (SetConsoleTextAttribute)
             // display the prompt
-            ab.push_str(&highlighter.highlight_prompt(prompt));
+            self.buffer.push_str(&highlighter.highlight_prompt(prompt));
             // display the input line
-            ab.push_str(&highlighter.highlight(line, line.pos()));
+            self.buffer
+                .push_str(&highlighter.highlight(line, line.pos()));
         } else {
             // display the prompt
-            ab.push_str(prompt);
+            self.buffer.push_str(prompt);
             // display the input line
-            ab.push_str(line);
+            self.buffer.push_str(line);
         }
         // display hint
         if let Some(hint) = hint {
             let truncate = truncate(&hint, end_pos.col, self.cols);
             if let Some(highlighter) = highlighter {
-                ab.push_str(&highlighter.highlight_hint(truncate));
+                self.buffer.push_str(&highlighter.highlight_hint(truncate));
             } else {
-                ab.push_str(truncate);
+                self.buffer.push_str(truncate);
             }
         }
-        try!(self.write_and_flush(ab.as_bytes()));
+        try!(self.out.write_all(self.buffer.as_bytes()));
+        try!(self.out.flush());
 
         // position the cursor
         let mut info = try!(self.get_console_screen_buffer_info());