Merge pull request #145 from gwenn/kkawakam

Misc
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..103ec44 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -108,6 +108,7 @@
         use std::char::decode_utf16;
         use winapi::um::wincon::{
             LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED,
+            SHIFT_PRESSED,
         };
 
         let mut rec: wincon::INPUT_RECORD = unsafe { mem::zeroed() };
@@ -125,7 +126,7 @@
             if rec.EventType == wincon::WINDOW_BUFFER_SIZE_EVENT {
                 SIGWINCH.store(true, atomic::Ordering::SeqCst);
                 debug!(target: "rustyline", "SIGWINCH");
-                return Err(error::ReadlineError::WindowResize);
+                return Err(error::ReadlineError::WindowResize); // sigwinch + err => err ignored
             } else if rec.EventType != wincon::KEY_EVENT {
                 continue;
             }
@@ -142,6 +143,7 @@
             let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0;
             let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0;
             let meta = alt && !alt_gr;
+            let shift = key_event.dwControlKeyState & SHIFT_PRESSED != 0;
 
             let utf16 = unsafe { *key_event.uChar.UnicodeChar() };
             if utf16 == 0 {
@@ -149,6 +151,8 @@
                     winuser::VK_LEFT => {
                         return Ok(if ctrl {
                             KeyPress::ControlLeft
+                        } else if shift {
+                            KeyPress::ShiftLeft
                         } else {
                             KeyPress::Left
                         })
@@ -156,6 +160,8 @@
                     winuser::VK_RIGHT => {
                         return Ok(if ctrl {
                             KeyPress::ControlRight
+                        } else if shift {
+                            KeyPress::ShiftRight
                         } else {
                             KeyPress::Right
                         })
@@ -163,6 +169,8 @@
                     winuser::VK_UP => {
                         return Ok(if ctrl {
                             KeyPress::ControlUp
+                        } else if shift {
+                            KeyPress::ShiftUp
                         } else {
                             KeyPress::Up
                         })
@@ -170,6 +178,8 @@
                     winuser::VK_DOWN => {
                         return Ok(if ctrl {
                             KeyPress::ControlDown
+                        } else if shift {
+                            KeyPress::ShiftDown
                         } else {
                             KeyPress::Down
                         })
@@ -230,6 +240,7 @@
     out: Stdout,
     handle: HANDLE,
     cols: usize, // Number of columns in terminal
+    buffer: String,
 }
 
 impl ConsoleRenderer {
@@ -240,6 +251,7 @@
             out: io::stdout(),
             handle,
             cols,
+            buffer: String::with_capacity(1024),
         }
     }
 
@@ -307,29 +319,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());
@@ -485,14 +499,14 @@
         }
         let original_stdin_mode = try!(get_console_mode(self.stdin_handle));
         // Disable these modes
-        let raw = original_stdin_mode & !(wincon::ENABLE_LINE_INPUT
+        let mut raw = original_stdin_mode & !(wincon::ENABLE_LINE_INPUT
             | wincon::ENABLE_ECHO_INPUT
             | wincon::ENABLE_PROCESSED_INPUT);
         // Enable these modes
-        let raw = raw | wincon::ENABLE_EXTENDED_FLAGS;
-        let raw = raw | wincon::ENABLE_INSERT_MODE;
-        let raw = raw | wincon::ENABLE_QUICK_EDIT_MODE;
-        let raw = raw | wincon::ENABLE_WINDOW_INPUT;
+        raw |= wincon::ENABLE_EXTENDED_FLAGS;
+        raw |= wincon::ENABLE_INSERT_MODE;
+        raw |= wincon::ENABLE_QUICK_EDIT_MODE;
+        raw |= wincon::ENABLE_WINDOW_INPUT;
         check!(consoleapi::SetConsoleMode(self.stdin_handle, raw));
 
         let original_stdout_mode = if self.stdout_isatty {