Merge pull request #152 from eminence/custom_output_stream

Allow customization of the output stream
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/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/lib.rs b/src/lib.rs
index 6546ec1..90b3ac2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -640,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
 }
 
@@ -686,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),
@@ -878,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/tty/mod.rs b/src/tty/mod.rs
index e36ff80..1c6bf41 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -3,7 +3,7 @@
 use unicode_segmentation::UnicodeSegmentation;
 use unicode_width::UnicodeWidthStr;
 
-use config::{ColorMode, Config};
+use config::{ColorMode, Config, OutputStreamType};
 use highlight::Highlighter;
 use keys::KeyPress;
 use line_buffer::LineBuffer;
@@ -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 b1a47d9..8ea87a4 100644
--- a/src/tty/test.rs
+++ b/src/tty/test.rs
@@ -4,7 +4,7 @@
 use std::vec::IntoIter;
 
 use super::{truncate, Position, RawMode, RawReader, Renderer, Term};
-use config::{ColorMode, Config};
+use config::{ColorMode, Config, OutputStreamType};
 use error::ReadlineError;
 use highlight::Highlighter;
 use keys::KeyPress;
@@ -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 ed7980f..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 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;
@@ -28,14 +30,14 @@
 static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb", "cons25", "emacs"];
 
 //#[allow(clippy::identity_conversion)]
-fn get_win_size() -> (usize, usize) {
+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),
         }
@@ -382,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),
         }
@@ -557,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;
     }
 
@@ -568,7 +571,7 @@
     /// 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
     }
 }
@@ -600,6 +603,7 @@
     stdin_isatty: bool,
     stdout_isatty: bool,
     pub(crate) color_mode: ColorMode,
+    stream_type: OutputStreamType,
 }
 
 impl Term for PosixTerminal {
@@ -607,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();
@@ -680,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 65b699f..b4bf70e 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 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(())
@@ -94,8 +97,12 @@
 }
 
 impl ConsoleRawReader {
-    pub fn new() -> Result<ConsoleRawReader> {
-        let handle = try!(get_std_handle(STDIN_FILENO));
+    pub fn new(stream: OutputStreamType) -> Result<ConsoleRawReader> {
+        let handle = try!(get_std_handle(if stream == OutputStreamType::Stdout {
+            STDIN_FILENO
+        } else {
+            STDERR_FILENO
+        }));
         Ok(ConsoleRawReader {
             handle,
             buf: [0; 2],
@@ -243,18 +250,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),
@@ -431,10 +438,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 {}
@@ -444,7 +452,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 {
@@ -454,8 +462,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()
@@ -466,10 +479,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,
         }
     }
 
@@ -485,7 +499,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,
         }
@@ -515,16 +529,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
         };
@@ -532,16 +546,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)
     }
 }