Merge pull request #155 from gwenn/surrogate

 Simplify surrogate pair handling on windows
diff --git a/Cargo.toml b/Cargo.toml
index 30a2fa1..a8ed288 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rustyline"
-version = "2.0.1"
+version = "2.1.0"
 authors = ["Katsu Kawakami <kkawa1570@gmail.com>"]
 description = "Rustyline, a readline implementation based on Antirez's Linenoise"
 documentation = "http://docs.rs/rustyline"
diff --git a/README.md b/README.md
index 5468a87..ea66ccc 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@
 
 ```toml
 [dependencies]
-rustyline = "2.0.1"
+rustyline = "2.1.0"
 ```
 
 ## Features
diff --git a/TODO.md b/TODO.md
index d4cd263..75b2667 100644
--- a/TODO.md
+++ b/TODO.md
@@ -9,7 +9,7 @@
 Color
 - [X] ANSI Colors & Windows 10+
 - [ ] ANSI Colors & Windows <10 (https://docs.rs/console/0.6.1/console/fn.strip_ansi_codes.html ? https://github.com/mattn/go-colorable/blob/master/colorable_windows.go)
-- [ ] Syntax highlighting
+- [ ] Syntax highlighting (https://github.com/trishume/syntect/)
 - [ ] clicolors spec (https://docs.rs/console/0.6.1/console/fn.colors_enabled.html)
 
 Completion
@@ -76,6 +76,8 @@
 Unix
 - [ ] Terminfo (https://github.com/Stebalien/term)
 - [ ] [ncurses](https://crates.io/crates/ncurses) alternative backend ?
+- [ ] [bracketed paste mode](https://cirw.in/blog/bracketed-paste)
+- [ ] async stdin (https://github.com/Rufflewind/tokio-file-unix)
 
 Windows
 - [ ] is_atty is not working with cygwin/msys (https://github.com/softprops/atty works but then how to make `enable_raw_mode` works ?)
diff --git a/examples/example.rs b/examples/example.rs
index e02f665..497bc34 100644
--- a/examples/example.rs
+++ b/examples/example.rs
@@ -5,6 +5,7 @@
 use std::borrow::Cow::{self, Borrowed, Owned};
 
 use rustyline::completion::{Completer, FilenameCompleter, Pair};
+use rustyline::config::OutputStreamType;
 use rustyline::error::ReadlineError;
 use rustyline::highlight::Highlighter;
 use rustyline::hint::Hinter;
@@ -56,6 +57,7 @@
         .history_ignore_space(true)
         .completion_type(CompletionType::List)
         .edit_mode(EditMode::Emacs)
+        .output_stream(OutputStreamType::Stdout)
         .build();
     let h = MyHelper(FilenameCompleter::new());
     let mut rl = Editor::with_config(config);
diff --git a/src/completion.rs b/src/completion.rs
index ab7a020..39fe213 100644
--- a/src/completion.rs
+++ b/src/completion.rs
@@ -299,20 +299,30 @@
     };
 
     let mut entries: Vec<Pair> = Vec::new();
-    for entry in try!(dir.read_dir()) {
-        let entry = try!(entry);
-        if let Some(s) = entry.file_name().to_str() {
-            if s.starts_with(file_name) {
-                if let Ok(metadata) = fs::metadata(entry.path()) {
-                    let mut path = String::from(dir_name) + s;
-                    if metadata.is_dir() {
-                        path.push(sep);
+
+    // if dir doesn't exist, then don't offer any completions
+    if !dir.exists() {
+        return Ok(entries);
+    }
+
+    // if any of the below IO operations have errors, just ignore them
+    if let Ok(read_dir) = dir.read_dir() {
+        for entry in read_dir {
+            if let Ok(entry) = entry {
+                if let Some(s) = entry.file_name().to_str() {
+                    if s.starts_with(file_name) {
+                        if let Ok(metadata) = fs::metadata(entry.path()) {
+                            let mut path = String::from(dir_name) + s;
+                            if metadata.is_dir() {
+                                path.push(sep);
+                            }
+                            entries.push(Pair {
+                                display: String::from(s),
+                                replacement: escape(path, esc_char, break_chars, quote),
+                            });
+                        } // else ignore PermissionDenied
                     }
-                    entries.push(Pair {
-                        display: String::from(s),
-                        replacement: escape(path, esc_char, break_chars, quote),
-                    });
-                } // else ignore PermissionDenied
+                }
             }
         }
     }
diff --git a/src/config.rs b/src/config.rs
index c82a234..e59a308 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -22,6 +22,8 @@
     auto_add_history: bool,
     /// if colors should be enabled.
     color_mode: ColorMode,
+    /// Whether to use stdout or stderr
+    output_stream: OutputStreamType,
 }
 
 impl Config {
@@ -99,6 +101,14 @@
     pub(crate) fn set_color_mode(&mut self, color_mode: ColorMode) {
         self.color_mode = color_mode;
     }
+
+    pub fn output_stream(&self) -> OutputStreamType {
+        self.output_stream
+    }
+
+    pub(crate) fn set_output_stream(&mut self, stream: OutputStreamType) {
+        self.output_stream = stream;
+    }
 }
 
 impl Default for Config {
@@ -113,6 +123,7 @@
             edit_mode: EditMode::Emacs,
             auto_add_history: false,
             color_mode: ColorMode::Enabled,
+            output_stream: OutputStreamType::Stdout,
         }
     }
 }
@@ -149,6 +160,13 @@
     Disabled,
 }
 
+/// Should the editor use stdout or stderr
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum OutputStreamType {
+    Stderr,
+    Stdout,
+}
+
 /// Configuration builder
 #[derive(Debug, Default)]
 pub struct Builder {
@@ -231,6 +249,14 @@
         self
     }
 
+    /// Whether to use stdout or stderr.
+    ///
+    /// Be default, use stdout
+    pub fn output_stream(mut self, stream: OutputStreamType) -> Builder {
+        self.set_output_stream(stream);
+        self
+    }
+
     pub fn build(self) -> Config {
         self.p
     }
@@ -303,4 +329,11 @@
     fn set_color_mode(&mut self, color_mode: ColorMode) {
         self.config_mut().set_color_mode(color_mode);
     }
+
+    /// Whether to use stdout or stderr
+    ///
+    /// By default, use stdout
+    fn set_output_stream(&mut self, stream: OutputStreamType) {
+        self.config_mut().set_output_stream(stream);
+    }
 }
diff --git a/src/edit.rs b/src/edit.rs
index f9fcca8..7d706f5 100644
--- a/src/edit.rs
+++ b/src/edit.rs
@@ -32,6 +32,7 @@
     pub changes: Rc<RefCell<Changeset>>, // changes to line, for undo/redo
     pub hinter: Option<&'out Hinter>,
     pub highlighter: Option<&'out Highlighter>,
+    no_hint: bool, // `false` if an hint has been displayed
 }
 
 impl<'out, 'prompt> State<'out, 'prompt> {
@@ -57,6 +58,7 @@
             changes: Rc::new(RefCell::new(Changeset::new())),
             hinter,
             highlighter,
+            no_hint: true,
         }
     }
 
@@ -130,10 +132,12 @@
         Ok(())
     }
 
-    fn hint(&self) -> Option<String> {
+    fn hint(&mut self) -> Option<String> {
         if let Some(hinter) = self.hinter {
+            self.no_hint = false;
             hinter.hint(self.line.as_str(), self.line.pos())
         } else {
+            self.no_hint = true;
             None
         }
     }
@@ -186,10 +190,11 @@
         if let Some(push) = self.line.insert(ch, n) {
             if push {
                 let prompt_size = self.prompt_size;
+                let no_previous_hint = self.no_hint;
                 let hint = self.hint();
                 if n == 1
                     && self.cursor.col + ch.width().unwrap_or(0) < self.out.get_columns()
-                    && hint.is_none() // TODO refresh only current line
+                    && (hint.is_none() && no_previous_hint) // TODO refresh only current line
                     && !self.highlighter.map_or(true, |h| h.highlight_char(ch.encode_utf8(&mut self.byte_buffer)))
                 {
                     // Avoid a full update of the line in the trivial case.
@@ -322,13 +327,12 @@
     }
 
     pub fn edit_insert_text(&mut self, text: &str) -> Result<()> {
-        if !text.is_empty() {
-            let cursor = self.line.pos();
-            self.line.insert_str(cursor, text);
-            self.refresh_line()
-        } else {
-            Ok(())
+        if text.is_empty() {
+            return Ok(());
         }
+        let cursor = self.line.pos();
+        self.line.insert_str(cursor, text);
+        self.refresh_line()
     }
 
     pub fn edit_delete(&mut self, n: RepeatCount) -> Result<()> {
@@ -506,6 +510,7 @@
         changes: Rc::new(RefCell::new(Changeset::new())),
         hinter: None,
         highlighter: None,
+        no_hint: true,
     }
 }
 
diff --git a/src/error.rs b/src/error.rs
index f7c1abd..c49595b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -10,6 +10,7 @@
 
 /// The error type for Rustyline errors that can arise from
 /// I/O related errors or Errno when using the nix-rust library
+/// #[non_exhaustive]
 #[derive(Debug)]
 pub enum ReadlineError {
     /// I/O Error
diff --git a/src/keymap.rs b/src/keymap.rs
index 877a12d..9841f78 100644
--- a/src/keymap.rs
+++ b/src/keymap.rs
@@ -5,13 +5,14 @@
 use super::Result;
 use config::Config;
 use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
 use tty::RawReader;
 
 /// The number of times one command should be repeated.
 pub type RepeatCount = usize;
 
 /// Commands
+/// #[non_exhaustive]
 #[derive(Debug, Clone, PartialEq)]
 pub enum Cmd {
     /// abort
@@ -479,20 +480,17 @@
         loop {
             try!(wrt.refresh_prompt_and_line(&format!("(arg: {}) ", self.num_args)));
             let key = try!(rdr.next_key(false));
-            match key {
-                KeyPress::Char(digit @ '0'...'9') => {
-                    if self.num_args.abs() < 1000 {
-                        // shouldn't ever need more than 4 digits
-                        self.num_args = self
-                            .num_args
-                            .saturating_mul(10)
-                            .saturating_add(digit.to_digit(10).unwrap() as i16);
-                    }
+            if let KeyPress::Char(digit @ '0'...'9') = key {
+                if self.num_args.abs() < 1000 {
+                    // shouldn't ever need more than 4 digits
+                    self.num_args = self
+                        .num_args
+                        .saturating_mul(10)
+                        .saturating_add(digit.to_digit(10).unwrap() as i16);
                 }
-                _ => {
-                    try!(wrt.refresh_line());
-                    return Ok(key);
-                }
+            } else {
+                try!(wrt.refresh_line());
+                return Ok(key);
             };
         }
     }
diff --git a/src/consts.rs b/src/keys.rs
similarity index 94%
rename from src/consts.rs
rename to src/keys.rs
index 5841016..c355e5a 100644
--- a/src/consts.rs
+++ b/src/keys.rs
@@ -1,9 +1,11 @@
 //! Key constants
 
+/// #[non_exhaustive]
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum KeyPress {
     UnknownEscSeq,
-    Backspace,
+    Backspace, // Ctrl('H')
+    BackTab,
     Char(char),
     ControlDown,
     ControlLeft,
@@ -14,7 +16,7 @@
     Down,
     End,
     Enter, // Ctrl('M')
-    Esc,
+    Esc,   // Ctrl('[')
     F(u8),
     Home,
     Insert,
@@ -32,7 +34,7 @@
     Up,
 }
 
-#[allow(match_same_arms)]
+//#[allow(clippy::match_same_arms)]
 pub fn char_to_key_press(c: char) -> KeyPress {
     if !c.is_control() {
         return KeyPress::Char(c);
diff --git a/src/kill_ring.rs b/src/kill_ring.rs
index b5d8778..03a202f 100644
--- a/src/kill_ring.rs
+++ b/src/kill_ring.rs
@@ -41,34 +41,31 @@
 
     /// Add `text` to the kill-ring.
     pub fn kill(&mut self, text: &str, dir: Mode) {
-        match self.last_action {
-            Action::Kill => {
-                if self.slots.capacity() == 0 {
-                    // disabled
-                    return;
-                }
-                match dir {
-                    Mode::Append => self.slots[self.index].push_str(text),
-                    Mode::Prepend => self.slots[self.index].insert_str(0, text),
-                };
+        if let Action::Kill = self.last_action {
+            if self.slots.capacity() == 0 {
+                // disabled
+                return;
             }
-            _ => {
-                self.last_action = Action::Kill;
-                if self.slots.capacity() == 0 {
-                    // disabled
-                    return;
-                }
-                if self.index == self.slots.capacity() - 1 {
-                    // full
-                    self.index = 0;
-                } else if !self.slots.is_empty() {
-                    self.index += 1;
-                }
-                if self.index == self.slots.len() {
-                    self.slots.push(String::from(text))
-                } else {
-                    self.slots[self.index] = String::from(text);
-                }
+            match dir {
+                Mode::Append => self.slots[self.index].push_str(text),
+                Mode::Prepend => self.slots[self.index].insert_str(0, text),
+            };
+        } else {
+            self.last_action = Action::Kill;
+            if self.slots.capacity() == 0 {
+                // disabled
+                return;
+            }
+            if self.index == self.slots.capacity() - 1 {
+                // full
+                self.index = 0;
+            } else if !self.slots.is_empty() {
+                self.index += 1;
+            }
+            if self.index == self.slots.len() {
+                self.slots.push(String::from(text))
+            } else {
+                self.slots[self.index] = String::from(text);
             }
         }
     }
diff --git a/src/lib.rs b/src/lib.rs
index f6f68ea..90b3ac2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,6 +16,8 @@
 //! }
 //! ```
 #![allow(unknown_lints)]
+// #![feature(non_exhaustive)]
+// #![feature(tool_lints)]
 
 extern crate dirs;
 extern crate libc;
@@ -33,13 +35,13 @@
 
 pub mod completion;
 pub mod config;
-mod consts;
 mod edit;
 pub mod error;
 pub mod highlight;
 pub mod hint;
 pub mod history;
 mod keymap;
+mod keys;
 mod kill_ring;
 pub mod line_buffer;
 mod undo;
@@ -58,13 +60,13 @@
 
 use completion::{longest_common_prefix, Candidate, Completer};
 pub use config::{ColorMode, CompletionType, Config, EditMode, HistoryDuplicates};
-pub use consts::KeyPress;
 use edit::State;
 use highlight::Highlighter;
 use hint::Hinter;
 use history::{Direction, History};
 pub use keymap::{Anchor, At, CharSearch, Cmd, Movement, RepeatCount, Word};
 use keymap::{InputState, Refresher};
+pub use keys::KeyPress;
 use kill_ring::{KillRing, Mode};
 use line_buffer::WordAction;
 
@@ -638,7 +640,11 @@
         }
     }
     drop(guard); // try!(disable_raw_mode(original_mode));
-    println!();
+    editor
+        .term
+        .create_writer()
+        .write_and_flush("\n".as_bytes())
+        .unwrap();
     user_input
 }
 
@@ -675,7 +681,7 @@
     custom_bindings: Arc<RwLock<HashMap<KeyPress, Cmd>>>,
 }
 
-#[allow(new_without_default)]
+//#[allow(clippy::new_without_default)]
 impl<H: Helper> Editor<H> {
     /// Create an editor with the default configuration
     pub fn new() -> Editor<H> {
@@ -684,7 +690,7 @@
 
     /// Create an editor with a specific configuration.
     pub fn with_config(config: Config) -> Editor<H> {
-        let term = Terminal::new(config.color_mode());
+        let term = Terminal::new(config.color_mode(), config.output_stream());
         Editor {
             term,
             history: History::with_config(config),
@@ -876,6 +882,61 @@
     }
 }
 
+enum StdStream {
+    Stdout(io::Stdout),
+    Stderr(io::Stderr),
+}
+impl StdStream {
+    fn from_stream_type(t: config::OutputStreamType) -> StdStream {
+        match t {
+            config::OutputStreamType::Stderr => StdStream::Stderr(io::stderr()),
+            config::OutputStreamType::Stdout => StdStream::Stdout(io::stdout()),
+        }
+    }
+}
+#[cfg(unix)]
+impl std::os::unix::io::AsRawFd for StdStream {
+    fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
+        match self {
+            StdStream::Stdout(e) => e.as_raw_fd(),
+            StdStream::Stderr(e) => e.as_raw_fd(),
+        }
+    }
+}
+impl io::Write for StdStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match self {
+            StdStream::Stdout(ref mut e) => e.write(buf),
+            StdStream::Stderr(ref mut e) => e.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match self {
+            StdStream::Stdout(ref mut e) => e.flush(),
+            StdStream::Stderr(ref mut e) => e.flush(),
+        }
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        match self {
+            StdStream::Stdout(ref mut e) => e.write_all(buf),
+            StdStream::Stderr(ref mut e) => e.write_all(buf),
+        }
+    }
+
+    fn write_fmt(&mut self, fmt: std::fmt::Arguments) -> io::Result<()> {
+        match self {
+            StdStream::Stdout(ref mut e) => e.write_fmt(fmt),
+            StdStream::Stderr(ref mut e) => e.write_fmt(fmt),
+        }
+    }
+
+    fn by_ref(&mut self) -> &mut StdStream {
+        self
+    }
+}
+
 #[cfg(test)]
 #[macro_use]
 extern crate assert_matches;
diff --git a/src/line_buffer.rs b/src/line_buffer.rs
index e17fd62..ae3fe70 100644
--- a/src/line_buffer.rs
+++ b/src/line_buffer.rs
@@ -364,25 +364,19 @@
             sow = 0;
             let mut gj = gis.next();
             'inner: loop {
-                match gj {
-                    Some((j, y)) => {
-                        let gi = gis.next();
-                        match gi {
-                            Some((_, x)) => {
-                                if is_start_of_word(word_def, x, y) {
-                                    sow = j;
-                                    break 'inner;
-                                }
-                                gj = gi;
-                            }
-                            None => {
-                                break 'outer;
-                            }
+                if let Some((j, y)) = gj {
+                    let gi = gis.next();
+                    if let Some((_, x)) = gi {
+                        if is_start_of_word(word_def, x, y) {
+                            sow = j;
+                            break 'inner;
                         }
-                    }
-                    None => {
+                        gj = gi;
+                    } else {
                         break 'outer;
                     }
+                } else {
+                    break 'outer;
                 }
             }
         }
@@ -428,32 +422,26 @@
             wp = 0;
             gi = gis.next();
             'inner: loop {
-                match gi {
-                    Some((i, x)) => {
-                        let gj = gis.next();
-                        match gj {
-                            Some((j, y)) => {
-                                if at == At::Start && is_start_of_word(word_def, x, y) {
-                                    wp = j;
-                                    break 'inner;
-                                } else if at != At::Start && is_end_of_word(word_def, x, y) {
-                                    if word_def == Word::Emacs || at == At::AfterEnd {
-                                        wp = j;
-                                    } else {
-                                        wp = i;
-                                    }
-                                    break 'inner;
-                                }
-                                gi = gj;
+                if let Some((i, x)) = gi {
+                    let gj = gis.next();
+                    if let Some((j, y)) = gj {
+                        if at == At::Start && is_start_of_word(word_def, x, y) {
+                            wp = j;
+                            break 'inner;
+                        } else if at != At::Start && is_end_of_word(word_def, x, y) {
+                            if word_def == Word::Emacs || at == At::AfterEnd {
+                                wp = j;
+                            } else {
+                                wp = i;
                             }
-                            None => {
-                                break 'outer;
-                            }
+                            break 'inner;
                         }
-                    }
-                    None => {
+                        gi = gj;
+                    } else {
                         break 'outer;
                     }
+                } else {
+                    break 'outer;
                 }
             }
         }
diff --git a/src/test/common.rs b/src/test/common.rs
index 7fe8b17..29bde74 100644
--- a/src/test/common.rs
+++ b/src/test/common.rs
@@ -1,8 +1,8 @@
 ///! Basic commands tests.
 use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
 use config::EditMode;
-use consts::KeyPress;
 use error::ReadlineError;
+use keys::KeyPress;
 
 #[test]
 fn home_key() {
diff --git a/src/test/emacs.rs b/src/test/emacs.rs
index 67a1b10..a4c738e 100644
--- a/src/test/emacs.rs
+++ b/src/test/emacs.rs
@@ -1,7 +1,7 @@
 //! Emacs specific key bindings
 use super::{assert_cursor, assert_history};
 use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
 
 #[test]
 fn ctrl_a() {
diff --git a/src/test/history.rs b/src/test/history.rs
index faa7a3f..dc3f8f0 100644
--- a/src/test/history.rs
+++ b/src/test/history.rs
@@ -1,7 +1,7 @@
 //! History related commands tests
 use super::assert_history;
 use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
 
 #[test]
 fn down_key() {
diff --git a/src/test/mod.rs b/src/test/mod.rs
index 1ce9881..8642b03 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -4,9 +4,9 @@
 use super::{Editor, Result};
 use completion::Completer;
 use config::{Config, EditMode};
-use consts::KeyPress;
 use edit::init_state;
 use keymap::{Cmd, InputState};
+use keys::KeyPress;
 use tty::Sink;
 
 mod common;
diff --git a/src/test/vi_cmd.rs b/src/test/vi_cmd.rs
index 1c1e4e9..d8ec793 100644
--- a/src/test/vi_cmd.rs
+++ b/src/test/vi_cmd.rs
@@ -1,7 +1,7 @@
 //! Vi command mode specific key bindings
 use super::{assert_cursor, assert_history};
 use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
 
 #[test]
 fn dollar() {
diff --git a/src/test/vi_insert.rs b/src/test/vi_insert.rs
index cf86680..fa3c881 100644
--- a/src/test/vi_insert.rs
+++ b/src/test/vi_insert.rs
@@ -1,7 +1,7 @@
 //! Vi insert mode specific key bindings
 use super::assert_cursor;
 use config::EditMode;
-use consts::KeyPress;
+use keys::KeyPress;
 
 #[test]
 fn insert_mode_by_default() {
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index d6767fc..1c6bf41 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -3,9 +3,9 @@
 use unicode_segmentation::UnicodeSegmentation;
 use unicode_width::UnicodeWidthStr;
 
-use config::{ColorMode, Config};
-use consts::KeyPress;
+use config::{ColorMode, Config, OutputStreamType};
 use highlight::Highlighter;
+use keys::KeyPress;
 use line_buffer::LineBuffer;
 use Result;
 
@@ -139,7 +139,7 @@
     type Writer: Renderer; // rl_outstream
     type Mode: RawMode;
 
-    fn new(color_mode: ColorMode) -> Self;
+    fn new(color_mode: ColorMode, stream: OutputStreamType) -> Self;
     /// Check if current terminal can provide a rich line-editing user
     /// interface.
     fn is_unsupported(&self) -> bool;
diff --git a/src/tty/test.rs b/src/tty/test.rs
index 75844be..8ea87a4 100644
--- a/src/tty/test.rs
+++ b/src/tty/test.rs
@@ -4,10 +4,10 @@
 use std::vec::IntoIter;
 
 use super::{truncate, Position, RawMode, RawReader, Renderer, Term};
-use config::{ColorMode, Config};
-use consts::KeyPress;
+use config::{ColorMode, Config, OutputStreamType};
 use error::ReadlineError;
 use highlight::Highlighter;
+use keys::KeyPress;
 use line_buffer::LineBuffer;
 use Result;
 
@@ -129,7 +129,7 @@
     type Reader = IntoIter<KeyPress>;
     type Writer = Sink;
 
-    fn new(color_mode: ColorMode) -> DummyTerminal {
+    fn new(color_mode: ColorMode, _stream: OutputStreamType) -> DummyTerminal {
         DummyTerminal {
             keys: Vec::new(),
             cursor: 0,
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index 5a8b20f..f07a02d 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -1,6 +1,7 @@
 //! Unix specific definitions
 use std;
-use std::io::{self, Read, Stdout, Write};
+use std::io::{self, Read, Write};
+use std::os::unix::io::AsRawFd;
 use std::sync;
 use std::sync::atomic;
 
@@ -14,12 +15,13 @@
 use utf8parse::{Parser, Receiver};
 
 use super::{truncate, width, Position, RawMode, RawReader, Renderer, Term};
-use config::{ColorMode, Config};
-use consts::{self, KeyPress};
+use config::{ColorMode, Config, OutputStreamType};
 use error;
 use highlight::Highlighter;
+use keys::{self, KeyPress};
 use line_buffer::LineBuffer;
 use Result;
+use StdStream;
 
 const STDIN_FILENO: libc::c_int = libc::STDIN_FILENO;
 const STDOUT_FILENO: libc::c_int = libc::STDOUT_FILENO;
@@ -27,15 +29,15 @@
 /// Unsupported Terminals that don't support RAW mode
 static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb", "cons25", "emacs"];
 
-#[allow(identity_conversion)]
-fn get_win_size() -> (usize, usize) {
+//#[allow(clippy::identity_conversion)]
+fn get_win_size<T: AsRawFd + ?Sized>(fileno: &T) -> (usize, usize) {
     use std::mem::zeroed;
 
     unsafe {
         let mut size: libc::winsize = zeroed();
         // https://github.com/rust-lang/libc/pull/704
         // FIXME: ".into()" used as a temporary fix for a libc bug
-        match libc::ioctl(STDOUT_FILENO, libc::TIOCGWINSZ.into(), &mut size) {
+        match libc::ioctl(fileno.as_raw_fd(), libc::TIOCGWINSZ.into(), &mut size) {
             0 => (size.ws_col as usize, size.ws_row as usize), // TODO getCursorPosition
             _ => (80, 24),
         }
@@ -163,6 +165,20 @@
                     self.extended_escape(seq2)
                 }
             }
+        } else if seq2 == '[' {
+            let seq3 = try!(self.next_char());
+            // Linux console
+            Ok(match seq3 {
+                'A' => KeyPress::F(1),
+                'B' => KeyPress::F(2),
+                'C' => KeyPress::F(3),
+                'D' => KeyPress::F(4),
+                'E' => KeyPress::F(5),
+                _ => {
+                    debug!(target: "rustyline", "unsupported esc sequence: ESC [ [ {:?}", seq3);
+                    KeyPress::UnknownEscSeq
+                }
+            })
         } else {
             // ANSI
             Ok(match seq2 {
@@ -172,6 +188,7 @@
                 'D' => KeyPress::Left,  // kcub1
                 'F' => KeyPress::End,
                 'H' => KeyPress::Home, // khome
+                'Z' => KeyPress::BackTab,
                 _ => {
                     debug!(target: "rustyline", "unsupported esc sequence: ESC [ {:?}", seq2);
                     KeyPress::UnknownEscSeq
@@ -251,13 +268,13 @@
                         ('2', 'D') => KeyPress::ShiftLeft,
                         _ => {
                             debug!(target: "rustyline",
-                                   "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
+                                   "unsupported esc sequence: ESC [ 1 ; {} {:?}", seq4, seq5);
                             KeyPress::UnknownEscSeq
                         }
                     })
                 } else {
                     debug!(target: "rustyline",
-                           "unsupported esc sequence: ESC [ {} ; {} {}", seq2, seq4, seq5);
+                           "unsupported esc sequence: ESC [ {} ; {} {:?}", seq2, seq4, seq5);
                     Ok(KeyPress::UnknownEscSeq)
                 }
             } else {
@@ -296,8 +313,8 @@
             'S' => KeyPress::F(4),  // kf4
             'a' => KeyPress::ControlUp,
             'b' => KeyPress::ControlDown,
-            'c' => KeyPress::ControlRight,
-            'd' => KeyPress::ControlLeft,
+            'c' => KeyPress::ControlRight, // rxvt
+            'd' => KeyPress::ControlLeft,  // rxvt
             _ => {
                 debug!(target: "rustyline", "unsupported esc sequence: ESC O {:?}", seq2);
                 KeyPress::UnknownEscSeq
@@ -310,7 +327,7 @@
     fn next_key(&mut self, single_esc_abort: bool) -> Result<KeyPress> {
         let c = try!(self.next_char());
 
-        let mut key = consts::char_to_key_press(c);
+        let mut key = keys::char_to_key_press(c);
         if key == KeyPress::Esc {
             let timeout_ms = if single_esc_abort && self.timeout_ms == -1 {
                 0
@@ -367,16 +384,17 @@
 
 /// Console output writer
 pub struct PosixRenderer {
-    out: Stdout,
+    out: StdStream,
     cols: usize, // Number of columns in terminal
     buffer: String,
 }
 
 impl PosixRenderer {
-    fn new() -> PosixRenderer {
-        let (cols, _) = get_win_size();
+    fn new(stream_type: OutputStreamType) -> PosixRenderer {
+        let out = StdStream::from_stream_type(stream_type);
+        let (cols, _) = get_win_size(&out);
         PosixRenderer {
-            out: io::stdout(),
+            out: out,
             cols,
             buffer: String::with_capacity(1024),
         }
@@ -542,7 +560,7 @@
 
     /// Try to update the number of columns in the current terminal,
     fn update_size(&mut self) {
-        let (cols, _) = get_win_size();
+        let (cols, _) = get_win_size(&self.out);
         self.cols = cols;
     }
 
@@ -553,13 +571,13 @@
     /// Try to get the number of rows in the current terminal,
     /// or assume 24 if it fails.
     fn get_rows(&self) -> usize {
-        let (_, rows) = get_win_size();
+        let (_, rows) = get_win_size(&self.out);
         rows
     }
 }
 
 static SIGWINCH_ONCE: sync::Once = sync::ONCE_INIT;
-static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
+static SIGWINCH: atomic::AtomicBool = atomic::AtomicBool::new(false);
 
 fn install_sigwinch_handler() {
     SIGWINCH_ONCE.call_once(|| unsafe {
@@ -585,6 +603,7 @@
     stdin_isatty: bool,
     stdout_isatty: bool,
     pub(crate) color_mode: ColorMode,
+    stream_type: OutputStreamType,
 }
 
 impl Term for PosixTerminal {
@@ -592,12 +611,13 @@
     type Reader = PosixRawReader;
     type Writer = PosixRenderer;
 
-    fn new(color_mode: ColorMode) -> PosixTerminal {
+    fn new(color_mode: ColorMode, stream_type: OutputStreamType) -> PosixTerminal {
         let term = PosixTerminal {
             unsupported: is_unsupported_term(),
             stdin_isatty: is_a_tty(STDIN_FILENO),
             stdout_isatty: is_a_tty(STDOUT_FILENO),
             color_mode,
+            stream_type,
         };
         if !term.unsupported && term.stdin_isatty && term.stdout_isatty {
             install_sigwinch_handler();
@@ -645,8 +665,9 @@
             | InputFlags::ISTRIP
             | InputFlags::IXON);
         // we don't want raw output, it turns newlines into straight linefeeds
-        // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST); // disable all output
-        // processing
+        // disable all output processing
+        // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST);
+
         // character-size mark (8 bits)
         raw.control_flags |= ControlFlags::CS8;
         // disable echoing, canonical mode, extended input processing and signals
@@ -664,7 +685,7 @@
     }
 
     fn create_writer(&self) -> PosixRenderer {
-        PosixRenderer::new()
+        PosixRenderer::new(self.stream_type)
     }
 }
 
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index 857fbfc..afe70ce 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -1,5 +1,5 @@
 //! Windows specific definitions
-use std::io::{self, Stdout, Write};
+use std::io::{self, Write};
 use std::mem;
 use std::sync::atomic;
 
@@ -9,15 +9,18 @@
 use winapi::um::{consoleapi, handleapi, processenv, winbase, wincon, winuser};
 
 use super::{truncate, Position, RawMode, RawReader, Renderer, Term};
+use config::OutputStreamType;
 use config::{ColorMode, Config};
-use consts::{self, KeyPress};
 use error;
 use highlight::Highlighter;
+use keys::{self, KeyPress};
 use line_buffer::LineBuffer;
 use Result;
+use StdStream;
 
 const STDIN_FILENO: DWORD = winbase::STD_INPUT_HANDLE;
 const STDOUT_FILENO: DWORD = winbase::STD_OUTPUT_HANDLE;
+const STDERR_FILENO: DWORD = winbase::STD_ERROR_HANDLE;
 
 fn get_std_handle(fd: DWORD) -> Result<HANDLE> {
     let handle = unsafe { processenv::GetStdHandle(fd) };
@@ -66,8 +69,8 @@
 pub struct ConsoleMode {
     original_stdin_mode: DWORD,
     stdin_handle: HANDLE,
-    original_stdout_mode: Option<DWORD>,
-    stdout_handle: HANDLE,
+    original_stdstream_mode: Option<DWORD>,
+    stdstream_handle: HANDLE,
 }
 
 impl RawMode for Mode {
@@ -77,10 +80,10 @@
             self.stdin_handle,
             self.original_stdin_mode,
         ));
-        if let Some(original_stdout_mode) = self.original_stdout_mode {
+        if let Some(original_stdstream_mode) = self.original_stdstream_mode {
             check!(consoleapi::SetConsoleMode(
-                self.stdout_handle,
-                original_stdout_mode,
+                self.stdstream_handle,
+                original_stdstream_mode,
             ));
         }
         Ok(())
@@ -93,7 +96,7 @@
 }
 
 impl ConsoleRawReader {
-    pub fn new() -> Result<ConsoleRawReader> {
+    pub fn new(stream: OutputStreamType) -> Result<ConsoleRawReader> {
         let handle = try!(get_std_handle(STDIN_FILENO));
         Ok(ConsoleRawReader { handle })
     }
@@ -221,7 +224,13 @@
                 if meta {
                     return Ok(KeyPress::Meta(c));
                 } else {
-                    return Ok(consts::char_to_key_press(c));
+                    let mut key = keys::char_to_key_press(c);
+                    if key == KeyPress::Tab && shift {
+                        key = KeyPress::BackTab;
+                    } else if key == KeyPress::Char(' ') && ctrl {
+                        key = KeyPress::Ctrl(' ');
+                    }
+                    return Ok(key);
                 }
             }
         }
@@ -229,18 +238,18 @@
 }
 
 pub struct ConsoleRenderer {
-    out: Stdout,
+    out: StdStream,
     handle: HANDLE,
     cols: usize, // Number of columns in terminal
     buffer: String,
 }
 
 impl ConsoleRenderer {
-    fn new(handle: HANDLE) -> ConsoleRenderer {
+    fn new(handle: HANDLE, stream_type: OutputStreamType) -> ConsoleRenderer {
         // Multi line editing is enabled by ENABLE_WRAP_AT_EOL_OUTPUT mode
         let (cols, _) = get_win_size(handle);
         ConsoleRenderer {
-            out: io::stdout(),
+            out: StdStream::from_stream_type(stream_type),
             handle,
             cols,
             buffer: String::with_capacity(1024),
@@ -417,10 +426,11 @@
 pub struct Console {
     stdin_isatty: bool,
     stdin_handle: HANDLE,
-    stdout_isatty: bool,
-    stdout_handle: HANDLE,
+    stdstream_isatty: bool,
+    stdstream_handle: HANDLE,
     pub(crate) color_mode: ColorMode,
     ansi_colors_supported: bool,
+    stream_type: OutputStreamType,
 }
 
 impl Console {}
@@ -430,7 +440,7 @@
     type Reader = ConsoleRawReader;
     type Writer = ConsoleRenderer;
 
-    fn new(color_mode: ColorMode) -> Console {
+    fn new(color_mode: ColorMode, stream_type: OutputStreamType) -> Console {
         use std::ptr;
         let stdin_handle = get_std_handle(STDIN_FILENO);
         let stdin_isatty = match stdin_handle {
@@ -440,8 +450,13 @@
             }
             Err(_) => false,
         };
-        let stdout_handle = get_std_handle(STDOUT_FILENO);
-        let stdout_isatty = match stdout_handle {
+
+        let stdstream_handle = get_std_handle(if stream_type == OutputStreamType::Stdout {
+            STDOUT_FILENO
+        } else {
+            STDERR_FILENO
+        });
+        let stdstream_isatty = match stdstream_handle {
             Ok(handle) => {
                 // If this function doesn't fail then fd is a TTY
                 get_console_mode(handle).is_ok()
@@ -452,10 +467,11 @@
         Console {
             stdin_isatty,
             stdin_handle: stdin_handle.unwrap_or(ptr::null_mut()),
-            stdout_isatty,
-            stdout_handle: stdout_handle.unwrap_or(ptr::null_mut()),
+            stdstream_isatty,
+            stdstream_handle: stdstream_handle.unwrap_or(ptr::null_mut()),
             color_mode,
             ansi_colors_supported: false,
+            stream_type,
         }
     }
 
@@ -471,7 +487,7 @@
     fn colors_enabled(&self) -> bool {
         // TODO ANSI Colors & Windows <10
         match self.color_mode {
-            ColorMode::Enabled => self.stdout_isatty && self.ansi_colors_supported,
+            ColorMode::Enabled => self.stdstream_isatty && self.ansi_colors_supported,
             ColorMode::Forced => true,
             ColorMode::Disabled => false,
         }
@@ -501,16 +517,16 @@
         raw |= wincon::ENABLE_WINDOW_INPUT;
         check!(consoleapi::SetConsoleMode(self.stdin_handle, raw));
 
-        let original_stdout_mode = if self.stdout_isatty {
-            let original_stdout_mode = try!(get_console_mode(self.stdout_handle));
+        let original_stdstream_mode = if self.stdstream_isatty {
+            let original_stdstream_mode = try!(get_console_mode(self.stdstream_handle));
             // To enable ANSI colors (Windows 10 only):
             // https://docs.microsoft.com/en-us/windows/console/setconsolemode
-            if original_stdout_mode & wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
-                let raw = original_stdout_mode | wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+            if original_stdstream_mode & wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
+                let raw = original_stdstream_mode | wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
                 self.ansi_colors_supported =
-                    unsafe { consoleapi::SetConsoleMode(self.stdout_handle, raw) != 0 };
+                    unsafe { consoleapi::SetConsoleMode(self.stdstream_handle, raw) != 0 };
             }
-            Some(original_stdout_mode)
+            Some(original_stdstream_mode)
         } else {
             None
         };
@@ -518,16 +534,16 @@
         Ok(Mode {
             original_stdin_mode,
             stdin_handle: self.stdin_handle,
-            original_stdout_mode,
-            stdout_handle: self.stdout_handle,
+            original_stdstream_mode,
+            stdstream_handle: self.stdstream_handle,
         })
     }
 
     fn create_reader(&self, _: &Config) -> Result<ConsoleRawReader> {
-        ConsoleRawReader::new()
+        ConsoleRawReader::new(self.stream_type)
     }
 
     fn create_writer(&self) -> ConsoleRenderer {
-        ConsoleRenderer::new(self.stdout_handle)
+        ConsoleRenderer::new(self.stdstream_handle, self.stream_type)
     }
 }