From 213eff2c33f765eff4e972efbf8b058fbec32c96 Mon Sep 17 00:00:00 2001 From: gwenn <gtreguier@gmail.com> Date: Sun, 10 Jul 2016 14:54:27 +0200 Subject: [PATCH] Introduce State.output_handle field on windows. It seems that we need both (out and output_handle) --- src/lib.rs | 90 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c29a61a3..95ed4ac5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,8 @@ struct State<'out, 'prompt> { cols: usize, // Number of columns in terminal history_index: usize, // The history index we are currently editing. snapshot: LineBuffer, // Current edited line before history browsing/completion + #[cfg(windows)] + output_handle: winapi::HANDLE, } #[derive(Copy, Clone, Debug, Default)] @@ -75,14 +77,15 @@ struct Position { } impl<'out, 'prompt> State<'out, 'prompt> { + #[cfg(unix)] fn new(out: &'out mut Write, prompt: &'prompt str, - capacity: usize, - cols: usize, history_index: usize) - -> State<'out, 'prompt> { + -> Result<State<'out, 'prompt>> { + let capacity = MAX_LINE; + let cols = get_columns(); let prompt_size = calculate_position(prompt, Default::default(), cols); - State { + let state = State { out: out, prompt: prompt, prompt_size: prompt_size, @@ -91,7 +94,30 @@ impl<'out, 'prompt> State<'out, 'prompt> { cols: cols, history_index: history_index, snapshot: LineBuffer::with_capacity(capacity), - } + }; + Ok(state) + } + #[cfg(windows)] + fn new(out: &'out mut Write, + prompt: &'prompt str, + history_index: usize) + -> Result<State<'out, 'prompt>> { + let handle = try!(get_std_handle(STDOUT_FILENO)); + let capacity = MAX_LINE; + let cols = get_columns(handle); + let prompt_size = calculate_position(prompt, Default::default(), cols); + let state = State { + out: out, + prompt: prompt, + prompt_size: prompt_size, + line: LineBuffer::with_capacity(capacity), + cursor: prompt_size, + cols: cols, + history_index: history_index, + snapshot: LineBuffer::with_capacity(capacity), + output_handle: handle, + }; + Ok(state) } fn snapshot(&mut self) { @@ -159,6 +185,16 @@ impl<'out, 'prompt> State<'out, 'prompt> { fn refresh(&mut self, prompt: &str, prompt_size: Position) -> Result<()> { unimplemented!() } + + #[cfg(unix)] + fn update_columns(&mut self) { + self.cols = get_columns(); + } + + #[cfg(windows)] + fn update_columns(&mut self) { + self.cols = get_columns(self.output_handle); + } } impl<'out, 'prompt> fmt::Debug for State<'out, 'prompt> { @@ -327,12 +363,7 @@ fn get_columns() -> usize { } } #[cfg(windows)] -fn get_columns() -> usize { - let handle = get_std_handle(STDOUT_FILENO); - if handle.is_err() { - return 80; - } - let handle = handle.unwrap(); +fn get_columns(handle: winapi::HANDLE) -> usize { let mut info = unsafe { mem::zeroed() }; match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } { 0 => 80, @@ -348,12 +379,12 @@ fn write_and_flush(w: &mut Write, buf: &[u8]) -> Result<()> { /// Clear the screen. Used to handle ctrl+l #[cfg(unix)] -fn clear_screen(out: &mut Write) -> Result<()> { - write_and_flush(out, b"\x1b[H\x1b[2J") +fn clear_screen(s: &mut State) -> Result<()> { + write_and_flush(s.out, b"\x1b[H\x1b[2J") } #[cfg(windows)] -fn clear_screen(_: &mut Write) -> Result<()> { - let handle = try!(get_std_handle(STDOUT_FILENO)); +fn clear_screen(s: &mut State) -> Result<()> { + let handle = s.output_handle; let mut info = unsafe { mem::zeroed() }; check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info)); let coord = winapi::COORD { X: 0, Y: 0 }; @@ -849,7 +880,6 @@ impl Read for InputBuffer { } } - /// Handles reading and editting the readline buffer. /// It will also handle special inputs in an appropriate fashion /// (e.g., C-c will exit readline) @@ -861,10 +891,10 @@ fn readline_edit(prompt: &str, original_mode: Mode) -> Result<String> { let mut stdout = io::stdout(); - try!(write_and_flush(&mut stdout, prompt.as_bytes())); kill_ring.reset(); - let mut s = State::new(&mut stdout, prompt, MAX_LINE, get_columns(), history.len()); + let mut s = try!(State::new(&mut stdout, prompt, history.len())); + try!(s.refresh_line()); let stdin = try!(stdin()); let mut chars = stdin.chars(); // TODO stdin.lock() ??? @@ -872,7 +902,7 @@ fn readline_edit(prompt: &str, loop { let c = chars.next().unwrap(); if c.is_err() && SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst) { - s.cols = get_columns(); + s.update_columns(); try!(s.refresh_line()); continue; } @@ -961,7 +991,7 @@ fn readline_edit(prompt: &str, } KeyPress::CTRL_L => { // Clear the screen leaving the current line at the top of the screen. - try!(clear_screen(s.out)); + try!(clear_screen(&mut s)); try!(s.refresh_line()) } KeyPress::CTRL_N => { @@ -1241,11 +1271,30 @@ mod test { use State; use super::Result; + #[cfg(unix)] + fn init_state<'out>(out: &'out mut Write, + line: &str, + pos: usize, + cols: usize) + -> State<'out, 'static> { + State { + out: out, + prompt: "", + prompt_size: Default::default(), + line: LineBuffer::init(line, pos), + cursor: Default::default(), + cols: cols, + history_index: 0, + snapshot: LineBuffer::with_capacity(100), + } + } + #[cfg(windows)] fn init_state<'out>(out: &'out mut Write, line: &str, pos: usize, cols: usize) -> State<'out, 'static> { + use std::ptr; State { out: out, prompt: "", @@ -1255,6 +1304,7 @@ mod test { cols: cols, history_index: 0, snapshot: LineBuffer::with_capacity(100), + output_handle: ptr::null_mut(), } } -- GitLab