From 7efa96a57b1ffd2990b621a0439e355b1c6ebf2d Mon Sep 17 00:00:00 2001
From: gwenn <gtreguier@gmail.com>
Date: Fri, 9 Sep 2016 20:47:03 +0200
Subject: [PATCH] Refactor before loading terminfo capabilities.

---
 src/lib.rs         |  87 ++++++++++++++------------------
 src/tty/mod.rs     |   1 -
 src/tty/unix.rs    | 102 ++++++++++++++++++++++++++++++-------
 src/tty/windows.rs | 122 +++++++++++++++++++++++++++++++++++----------
 4 files changed, 219 insertions(+), 93 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 214aff1d..851beaba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,17 +37,18 @@ pub mod line_buffer;
 mod char_iter;
 pub mod config;
 
-#[macro_use]
 mod tty;
 
+use std::cell::RefCell;
 use std::fmt;
 use std::io::{self, Read, Write};
 use std::mem;
 use std::path::Path;
+use std::rc::Rc;
 use std::result;
-use std::sync::atomic;
 #[cfg(unix)]
 use nix::sys::signal;
+use tty::Terminal;
 
 use encode_unicode::CharExt;
 use completion::{Completer, longest_common_prefix};
@@ -71,7 +72,7 @@ struct State<'out, 'prompt> {
     old_rows: usize, // Number of rows used so far (from start of prompt to end of input)
     history_index: usize, // The history index we are currently editing
     snapshot: LineBuffer, // Current edited line before history browsing/completion
-    output_handle: tty::Handle, // output handle (for windows)
+    term: Rc<RefCell<Terminal>>, // terminal
 }
 
 #[derive(Copy, Clone, Debug, Default)]
@@ -82,12 +83,12 @@ struct Position {
 
 impl<'out, 'prompt> State<'out, 'prompt> {
     fn new(out: &'out mut Write,
-           output_handle: tty::Handle,
+           term: Rc<RefCell<Terminal>>,
            prompt: &'prompt str,
            history_index: usize)
            -> State<'out, 'prompt> {
         let capacity = MAX_LINE;
-        let cols = tty::get_columns(output_handle);
+        let cols = term.borrow().get_columns();
         let prompt_size = calculate_position(prompt, Position::default(), cols);
         State {
             out: out,
@@ -99,7 +100,7 @@ impl<'out, 'prompt> State<'out, 'prompt> {
             old_rows: prompt_size.row,
             history_index: history_index,
             snapshot: LineBuffer::with_capacity(capacity),
-            output_handle: output_handle,
+            term: term,
         }
     }
 
@@ -175,24 +176,21 @@ impl<'out, 'prompt> State<'out, 'prompt> {
 
     #[cfg(windows)]
     fn refresh(&mut self, prompt: &str, prompt_size: Position) -> Result<()> {
-        let handle = self.output_handle;
         // calculate the position of the end of the input line
         let end_pos = calculate_position(&self.line, prompt_size, self.cols);
         // calculate the desired position of the cursor
         let cursor = calculate_position(&self.line[..self.line.pos()], prompt_size, self.cols);
 
+        let mut term = self.term.borrow_mut();
         // position at the start of the prompt, clear to end of previous input
-        let mut info = unsafe { mem::zeroed() };
-        check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
+        let mut info = try!(term.get_console_screen_buffer_info());
         info.dwCursorPosition.X = 0;
         info.dwCursorPosition.Y -= self.cursor.row as i16;
-        check!(kernel32::SetConsoleCursorPosition(handle, info.dwCursorPosition));
+        try!(term.set_console_cursor_position(info.dwCursorPosition));
         let mut _count = 0;
-        check!(kernel32::FillConsoleOutputCharacterA(handle,
-                                                 ' ' as winapi::CHAR,
-                                                 (info.dwSize.X * (self.old_rows as i16 +1)) as winapi::DWORD,
-                                                 info.dwCursorPosition,
-                                                 &mut _count));
+        try!(term.fill_console_output_character(
+                                                 (info.dwSize.X * (self.old_rows as i16 +1)) as u32,
+                                                 info.dwCursorPosition));
         let mut ab = String::new();
         // display the prompt
         ab.push_str(prompt); // TODO handle ansi escape code (SetConsoleTextAttribute)
@@ -201,10 +199,10 @@ impl<'out, 'prompt> State<'out, 'prompt> {
         try!(write_and_flush(self.out, ab.as_bytes()));
 
         // position the cursor
-        check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
+        let mut info = try!(term.get_console_screen_buffer_info());
         info.dwCursorPosition.X = cursor.col as i16;
         info.dwCursorPosition.Y -= (end_pos.row - cursor.row) as i16;
-        check!(kernel32::SetConsoleCursorPosition(handle, info.dwCursorPosition));
+        try!(term.set_console_cursor_position(info.dwCursorPosition));
 
         self.cursor = cursor;
         self.old_rows = end_pos.row;
@@ -213,7 +211,7 @@ impl<'out, 'prompt> State<'out, 'prompt> {
     }
 
     fn update_columns(&mut self) {
-        self.cols = tty::get_columns(self.output_handle);
+        self.cols = self.term.borrow().get_columns();
     }
 }
 
@@ -646,7 +644,7 @@ fn page_completions<R: Read>(rdr: &mut tty::RawReader<R>,
                                  .unwrap() + min_col_pad);
     let num_cols = s.cols / max_width;
 
-    let mut pause_row = tty::get_rows(s.output_handle) - 1;
+    let mut pause_row = s.term.borrow().get_rows() - 1;
     let num_rows = (candidates.len() + num_cols - 1) / num_cols;
     let mut ab = String::new();
     for row in 0..num_rows {
@@ -665,7 +663,7 @@ fn page_completions<R: Read>(rdr: &mut tty::RawReader<R>,
                 KeyPress::Char('y') |
                 KeyPress::Char('Y') |
                 KeyPress::Char(' ') => {
-                    pause_row += tty::get_rows(s.output_handle) - 1;
+                    pause_row += s.term.borrow().get_rows() - 1;
                 }
                 KeyPress::Enter => {
                     pause_row += 1;
@@ -785,17 +783,16 @@ fn readline_edit<C: Completer>(prompt: &str,
     let completer = editor.completer.as_ref().map(|c| c as &Completer);
 
     let mut stdout = io::stdout();
-    let stdout_handle = try!(tty::stdout_handle());
 
     editor.kill_ring.reset();
-    let mut s = State::new(&mut stdout, stdout_handle, prompt, editor.history.len());
+    let mut s = State::new(&mut stdout, editor.term.clone(), prompt, editor.history.len());
     try!(s.refresh_line());
 
-    let mut rdr = try!(tty::RawReader::new(io::stdin()));
+    let mut rdr = try!(s.term.borrow().create_reader());
 
     loop {
         let rk = rdr.next_key(true);
-        if rk.is_err() && tty::SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst) {
+        if rk.is_err() && s.term.borrow().sigwinch() {
             s.update_columns();
             try!(s.refresh_line());
             continue;
@@ -884,7 +881,7 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             KeyPress::Ctrl('L') => {
                 // Clear the screen leaving the current line at the top of the screen.
-                try!(tty::clear_screen(&mut s.out, s.output_handle));
+                try!(s.term.borrow_mut().clear_screen(&mut s.out));
                 try!(s.refresh_line())
             }
             KeyPress::Ctrl('N') |
@@ -931,9 +928,9 @@ fn readline_edit<C: Completer>(prompt: &str,
             }
             #[cfg(unix)]
             KeyPress::Ctrl('Z') => {
-                try!(tty::disable_raw_mode(original_mode));
+                try!(s.term.borrow_mut().disable_raw_mode(original_mode));
                 try!(signal::raise(signal::SIGSTOP));
-                try!(tty::enable_raw_mode()); // TODO original_mode may have changed
+                try!(s.term.borrow_mut().enable_raw_mode()); // TODO original_mode may have changed
                 try!(s.refresh_line())
             }
             // TODO CTRL-_ // undo
@@ -1050,9 +1047,7 @@ fn readline_direct() -> Result<String> {
 
 /// Line editor
 pub struct Editor<C: Completer> {
-    unsupported_term: bool,
-    stdin_isatty: bool,
-    stdout_isatty: bool,
+    term: Rc<RefCell<Terminal>>,
     history: History,
     completer: Option<C>,
     kill_ring: KillRing,
@@ -1061,30 +1056,25 @@ pub struct Editor<C: Completer> {
 
 impl<C: Completer> Editor<C> {
     pub fn new(config: Config) -> Editor<C> {
-        let editor = Editor {
-            unsupported_term: tty::is_unsupported_term(),
-            stdin_isatty: tty::is_a_tty(tty::STDIN_FILENO),
-            stdout_isatty: tty::is_a_tty(tty::STDOUT_FILENO),
+        let term = Rc::new(RefCell::new(Terminal::new()));
+        Editor {
+            term: term,
             history: History::new(config),
             completer: None,
             kill_ring: KillRing::new(60),
             config: config,
-        };
-        if !editor.unsupported_term && editor.stdin_isatty && editor.stdout_isatty {
-            tty::install_sigwinch_handler();
         }
-        editor
     }
 
     /// This method will read a line from STDIN and will display a `prompt`
     pub fn readline(&mut self, prompt: &str) -> Result<String> {
-        if self.unsupported_term {
+        if self.term.borrow().is_unsupported() {
             // Write prompt and flush it to stdout
             let mut stdout = io::stdout();
             try!(write_and_flush(&mut stdout, prompt.as_bytes()));
 
             readline_direct()
-        } else if !self.stdin_isatty {
+        } else if !self.term.borrow().is_stdin_tty() {
             // Not a tty: read from file / pipe.
             readline_direct()
         } else {
@@ -1121,33 +1111,32 @@ impl<C: Completer> Editor<C> {
 
 impl<C: Completer> fmt::Debug for Editor<C> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("State")
-            .field("unsupported_term", &self.unsupported_term)
-            .field("stdin_isatty", &self.stdin_isatty)
+        f.debug_struct("Editor")
+            .field("term", &self.term)
+            .field("config", &self.config)
             .finish()
     }
 }
 
 #[cfg(all(unix,test))]
 mod test {
+    use std::cell::RefCell;
     use std::io::Write;
+    use std::rc::Rc;
     use line_buffer::LineBuffer;
     use history::History;
     use completion::Completer;
     use config::Config;
     use {Position, State};
     use super::Result;
-    use tty::Handle;
-
-    fn default_handle() -> Handle {
-        ()
-    }
+    use tty::Terminal;
 
     fn init_state<'out>(out: &'out mut Write,
                         line: &str,
                         pos: usize,
                         cols: usize)
                         -> State<'out, 'static> {
+        let term = Rc::new(RefCell::new(Terminal::new()));
         State {
             out: out,
             prompt: "",
@@ -1158,7 +1147,7 @@ mod test {
             old_rows: 0,
             history_index: 0,
             snapshot: LineBuffer::with_capacity(100),
-            output_handle: default_handle(),
+            term: term,
         }
     }
 
diff --git a/src/tty/mod.rs b/src/tty/mod.rs
index 22c67938..82e2ed67 100644
--- a/src/tty/mod.rs
+++ b/src/tty/mod.rs
@@ -2,7 +2,6 @@
 
 // If on Windows platform import Windows TTY module
 // and re-export into mod.rs scope
-#[macro_use]
 #[cfg(windows)]
 mod windows;
 #[cfg(windows)]
diff --git a/src/tty/unix.rs b/src/tty/unix.rs
index ff1d0b31..a08029a5 100644
--- a/src/tty/unix.rs
+++ b/src/tty/unix.rs
@@ -12,10 +12,9 @@ use consts::{self, KeyPress};
 use ::Result;
 use ::error;
 
-pub type Handle = ();
 pub type Mode = termios::Termios;
-pub const STDIN_FILENO: libc::c_int = libc::STDIN_FILENO;
-pub const STDOUT_FILENO: libc::c_int = libc::STDOUT_FILENO;
+const STDIN_FILENO: libc::c_int = libc::STDIN_FILENO;
+const STDOUT_FILENO: libc::c_int = libc::STDOUT_FILENO;
 
 /// Unsupported Terminals that don't support RAW mode
 static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb", "cons25", "emacs"];
@@ -31,14 +30,14 @@ const TIOCGWINSZ: libc::c_int = 0x5413;
 
 /// Try to get the number of columns in the current terminal,
 /// or assume 80 if it fails.
-pub fn get_columns(_: Handle) -> usize {
+fn get_columns() -> usize {
     let (cols, _) = get_win_size();
     cols
 }
 
 /// Try to get the number of rows in the current terminal,
 /// or assume 24 if it fails.
-pub fn get_rows(_: Handle) -> usize {
+fn get_rows() -> usize {
     let (_, rows) = get_win_size();
     rows
 }
@@ -66,7 +65,7 @@ fn get_win_size() -> (usize, usize) {
 
 /// Check TERM environment variable to see if current term is in our
 /// unsupported list
-pub fn is_unsupported_term() -> bool {
+fn is_unsupported_term() -> bool {
     use std::ascii::AsciiExt;
     match std::env::var("TERM") {
         Ok(term) => {
@@ -82,11 +81,10 @@ pub fn is_unsupported_term() -> bool {
 
 
 /// Return whether or not STDIN, STDOUT or STDERR is a TTY
-pub fn is_a_tty(fd: libc::c_int) -> bool {
+fn is_a_tty(fd: libc::c_int) -> bool {
     unsafe { libc::isatty(fd) != 0 }
 }
 
-/// Enable raw mode for the TERM
 pub fn enable_raw_mode() -> Result<Mode> {
     use nix::errno::Errno::ENOTTY;
     use nix::sys::termios::{BRKINT, CS8, ECHO, ICANON, ICRNL, IEXTEN, INPCK, ISIG, ISTRIP, IXON,
@@ -110,18 +108,12 @@ pub fn enable_raw_mode() -> Result<Mode> {
     Ok(original_mode)
 }
 
-/// Disable Raw mode for the term
 pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
     try!(termios::tcsetattr(STDIN_FILENO, termios::TCSAFLUSH, &original_mode));
     Ok(())
 }
 
-pub fn stdout_handle() -> Result<Handle> {
-    Ok(())
-}
-
-/// Clear the screen. Used to handle ctrl+l
-pub fn clear_screen(w: &mut Write, _: Handle) -> Result<()> {
+fn clear_screen(w: &mut Write) -> Result<()> {
     try!(w.write_all(b"\x1b[H\x1b[2J"));
     try!(w.flush());
     Ok(())
@@ -222,9 +214,9 @@ impl<R: Read> RawReader<R> {
 }
 
 static SIGWINCH_ONCE: sync::Once = sync::ONCE_INIT;
-pub static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
+static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
 
-pub fn install_sigwinch_handler() {
+fn install_sigwinch_handler() {
     SIGWINCH_ONCE.call_once(|| unsafe {
         let sigwinch = signal::SigAction::new(signal::SigHandler::Handler(sigwinch_handler),
                                               signal::SaFlag::empty(),
@@ -236,3 +228,79 @@ pub fn install_sigwinch_handler() {
 extern "C" fn sigwinch_handler(_: signal::SigNum) {
     SIGWINCH.store(true, atomic::Ordering::SeqCst);
 }
+
+pub type Terminal = PosixTerminal;
+
+#[derive(Debug)]
+pub struct PosixTerminal {
+    unsupported: bool,
+    stdin_isatty: bool,
+}
+
+impl PosixTerminal {
+    pub fn new() -> PosixTerminal {
+        let term = PosixTerminal {
+            unsupported: is_unsupported_term(),
+            stdin_isatty: is_a_tty(STDIN_FILENO),
+        };
+        if !term.unsupported && term.stdin_isatty && is_a_tty(STDOUT_FILENO) {
+            install_sigwinch_handler();
+        }
+        term
+    }
+
+    // Init checks:
+
+    /// Check if current terminal can provide a rich line-editing user interface.
+    pub fn is_unsupported(&self) -> bool {
+        self.unsupported
+    }
+
+    /// check if stdin is connected to a terminal.
+    pub fn is_stdin_tty(&self) -> bool {
+        self.stdin_isatty
+    }
+
+    // Init if terminal-style mode:
+
+    // pub fn load_capabilities(&mut self) -> Result<()> {
+    // Ok(())
+    // }
+
+    // Interactive loop:
+
+    /// Enable RAW mode for the terminal.
+    pub fn enable_raw_mode(&mut self) -> Result<Mode> {
+        enable_raw_mode()
+    }
+
+    /// Disable RAW mode for the terminal.
+    pub fn disable_raw_mode(&mut self, mode: Mode) -> Result<()> {
+        disable_raw_mode(mode)
+    }
+
+    /// Get the number of columns in the current terminal.
+    pub fn get_columns(&self) -> usize {
+        get_columns()
+    }
+
+    /// Get the number of rows in the current terminal.
+    pub fn get_rows(&self) -> usize {
+        get_rows()
+    }
+
+    /// Create a RAW reader
+    pub fn create_reader(&self) -> Result<RawReader<std::io::Stdin>> {
+        RawReader::new(std::io::stdin())
+    }
+
+    /// Check if a SIGWINCH signal has been received
+    pub fn sigwinch(&self) -> bool {
+        SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst)
+    }
+
+    /// Clear the screen. Used to handle ctrl+l
+    pub fn clear_screen(&mut self, w: &mut Write) -> Result<()> {
+        clear_screen(w)
+    }
+}
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index f1b09587..e0e62d04 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -11,10 +11,9 @@ use consts::{self, KeyPress};
 use ::error;
 use ::Result;
 
-pub type Handle = winapi::HANDLE;
 pub type Mode = winapi::DWORD;
-pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
-pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;
+const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
+const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;
 
 fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
     let handle = unsafe { kernel32::GetStdHandle(fd) };
@@ -40,21 +39,17 @@ macro_rules! check {
     };
 }
 
-/// Try to get the number of columns in the current terminal,
-/// or assume 80 if it fails.
-pub fn get_columns(handle: Handle) -> usize {
+fn get_columns(handle: winapi::HANDLE) -> usize {
     let (cols, _) = get_win_size(handle);
     cols
 }
 
-/// Try to get the number of rows in the current terminal,
-/// or assume 24 if it fails.
-pub fn get_rows(handle: Handle) -> usize {
+fn get_rows(handle: winapi::HANDLE) -> usize {
     let (_, rows) = get_win_size(handle);
     rows
 }
 
-fn get_win_size(handle: Handle) -> (usize, usize) {
+fn get_win_size(handle: winapi::HANDLE) -> (usize, usize) {
     let mut info = unsafe { mem::zeroed() };
     match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
         0 => (80, 24),
@@ -62,11 +57,6 @@ fn get_win_size(handle: Handle) -> (usize, usize) {
     }
 }
 
-/// Checking for an unsupported TERM in windows is a no-op
-pub fn is_unsupported_term() -> bool {
-    false
-}
-
 fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
     let mut original_mode = 0;
     check!(kernel32::GetConsoleMode(handle, &mut original_mode));
@@ -74,7 +64,7 @@ fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
 }
 
 /// Return whether or not STDIN, STDOUT or STDERR is a TTY
-pub fn is_a_tty(fd: winapi::DWORD) -> bool {
+fn is_a_tty(fd: winapi::DWORD) -> bool {
     let handle = get_std_handle(fd);
     match handle {
         Ok(handle) => {
@@ -85,7 +75,6 @@ pub fn is_a_tty(fd: winapi::DWORD) -> bool {
     }
 }
 
-/// Enable raw mode for the TERM
 pub fn enable_raw_mode() -> Result<Mode> {
     let handle = try!(get_std_handle(STDIN_FILENO));
     let original_mode = try!(get_console_mode(handle));
@@ -102,20 +91,14 @@ pub fn enable_raw_mode() -> Result<Mode> {
     Ok(original_mode)
 }
 
-/// Disable Raw mode for the term
 pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
     let handle = try!(get_std_handle(STDIN_FILENO));
     check!(kernel32::SetConsoleMode(handle, original_mode));
     Ok(())
 }
 
-pub fn stdout_handle() -> Result<Handle> {
-    let handle = try!(get_std_handle(STDOUT_FILENO));
-    Ok(handle)
-}
-
 /// Clear the screen. Used to handle ctrl+l
-pub fn clear_screen(_: &mut Write, handle: Handle) -> Result<()> {
+fn clear_screen(_: &mut Write, handle: winapi::HANDLE) -> Result<()> {
     let mut info = unsafe { mem::zeroed() };
     check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
     let coord = winapi::COORD { X: 0, Y: 0 };
@@ -236,8 +219,95 @@ impl<R: Read> Iterator for RawReader<R> {
     }
 }
 
-pub static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
+static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;
+
+pub type Terminal = Console;
+
+#[derive(Debug)]
+pub struct Console {
+    stdin_isatty: bool,
+    stdout_handle: winapi::HANDLE,
+}
+
+impl Console {
+    pub fn new() -> Console {
+        use std::ptr;
+        let stdout_handle = get_std_handle(STDOUT_FILENO).unwrap_or(ptr::null_mut());
+        Console {
+            stdin_isatty: is_a_tty(STDIN_FILENO),
+            stdout_handle: stdout_handle,
+        }
+    }
+
+    /// Checking for an unsupported TERM in windows is a no-op
+    pub fn is_unsupported(&self) -> bool {
+        false
+    }
+
+    pub fn is_stdin_tty(&self) -> bool {
+        self.stdin_isatty
+    }
 
-pub fn install_sigwinch_handler() {
+    // pub fn install_sigwinch_handler(&mut self) {
     // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
+    // }
+
+    pub fn load_capabilities(&mut self) -> Result<()> {
+        Ok(())
+    }
+
+    /// Enable raw mode for the TERM
+    pub fn enable_raw_mode(&mut self) -> Result<Mode> {
+        enable_raw_mode()
+    }
+
+    /// Disable Raw mode for the term
+    pub fn disable_raw_mode(&mut self, mode: Mode) -> Result<()> {
+        disable_raw_mode(mode)
+    }
+
+    /// Try to get the number of columns in the current terminal,
+    /// or assume 80 if it fails.
+    pub fn get_columns(&self) -> usize {
+        get_columns(self.stdout_handle)
+    }
+
+    /// Try to get the number of rows in the current terminal,
+    /// or assume 24 if it fails.
+    pub fn get_rows(&self) -> usize {
+        get_rows(self.stdout_handle)
+    }
+
+    pub fn create_reader(&self) -> Result<RawReader<io::Stdin>> {
+        RawReader::new(io::stdin()) // FIXME
+    }
+
+    pub fn sigwinch(&self) -> bool {
+        SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst)
+    }
+
+    pub fn clear_screen(&mut self, w: &mut Write) -> Result<()> {
+        clear_screen(w, self.stdout_handle)
+    }
+
+    pub fn get_console_screen_buffer_info(&self) -> Result<winapi::CONSOLE_SCREEN_BUFFER_INFO> {
+        let mut info = unsafe { mem::zeroed() };
+        check!(kernel32::GetConsoleScreenBufferInfo(self.stdout_handle, &mut info));
+        Ok(info)
+    }
+
+    pub fn set_console_cursor_position(&mut self, pos: winapi::COORD) -> Result<()> {
+        check!(kernel32::SetConsoleCursorPosition(self.stdout_handle, pos));
+        Ok(())
+    }
+
+    pub fn fill_console_output_character(&mut self, length: winapi::DWORD, pos: winapi::COORD) -> Result<()> {
+        let mut _count = 0;
+        check!(kernel32::FillConsoleOutputCharacterA(self.stdout_handle,
+                                                 ' ' as winapi::CHAR,
+                                                 length,
+                                                 pos,
+                                                 &mut _count));
+        Ok(())
+    }
 }
-- 
GitLab