From 27295c462028f9babc9699f3b4084928e0e536e9 Mon Sep 17 00:00:00 2001 From: gwenn <gtreguier@gmail.com> Date: Sun, 10 Jul 2016 16:25:07 +0200 Subject: [PATCH] Start implementing refresh on windows. --- src/lib.rs | 118 +++++++++++++++++++++++------------------------------ 1 file changed, 51 insertions(+), 67 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 95ed4ac5..3ca1aec6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,19 @@ use kill_ring::KillRing; /// The error type for I/O and Linux Syscalls (Errno) pub type Result<T> = result::Result<T, error::ReadlineError>; +#[cfg(unix)] +type Handle = (); +#[cfg(windows)] +type Handle = winapi::HANDLE; +#[cfg(windows)] +macro_rules! check { + ($funcall:expr) => ( + if unsafe { $funcall } == 0 { + try!(Err(io::Error::last_os_error())); + } + ); +} + // Represent the state during line editing. struct State<'out, 'prompt> { out: &'out mut Write, @@ -66,8 +79,7 @@ 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, + output_handle: Handle, // output handle (for windows) } #[derive(Copy, Clone, Debug, Default)] @@ -77,36 +89,15 @@ struct Position { } impl<'out, 'prompt> State<'out, 'prompt> { - #[cfg(unix)] - fn new(out: &'out mut Write, - prompt: &'prompt str, - history_index: usize) - -> Result<State<'out, 'prompt>> { - let capacity = MAX_LINE; - let cols = get_columns(); - 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), - }; - Ok(state) - } - #[cfg(windows)] fn new(out: &'out mut Write, + output_handle: Handle, prompt: &'prompt str, history_index: usize) - -> Result<State<'out, 'prompt>> { - let handle = try!(get_std_handle(STDOUT_FILENO)); + -> State<'out, 'prompt> { let capacity = MAX_LINE; - let cols = get_columns(handle); + let cols = get_columns(output_handle); let prompt_size = calculate_position(prompt, Default::default(), cols); - let state = State { + State { out: out, prompt: prompt, prompt_size: prompt_size, @@ -115,9 +106,8 @@ impl<'out, 'prompt> State<'out, 'prompt> { cols: cols, history_index: history_index, snapshot: LineBuffer::with_capacity(capacity), - output_handle: handle, - }; - Ok(state) + output_handle: output_handle, + } } fn snapshot(&mut self) { @@ -144,7 +134,9 @@ impl<'out, 'prompt> State<'out, 'prompt> { fn refresh(&mut self, prompt: &str, prompt_size: Position) -> Result<()> { use std::fmt::Write; + // 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 ab = String::new(); @@ -183,15 +175,23 @@ impl<'out, 'prompt> State<'out, 'prompt> { #[cfg(windows)] fn refresh(&mut self, prompt: &str, prompt_size: Position) -> Result<()> { - unimplemented!() - } + let handle = s.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); - #[cfg(unix)] - fn update_columns(&mut self) { - self.cols = get_columns(); + // position at the end of the prompt, clear to end of previous input + let mut info = unsafe { mem::zeroed() }; + check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info)); + info.dwCursorPosition.X = self.prompt_size.col; + inf.dwCursorPosition.Y -= self.cursor.row - self.prompt_size.row; + check!(kernel32::SetConsoleCursorPosition(handle, coord)); + + self.cursor = cursor; + unimplemented!() } - #[cfg(windows)] fn update_columns(&mut self) { self.cols = get_columns(self.output_handle); } @@ -259,14 +259,6 @@ const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE; #[cfg(windows)] const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE; #[cfg(windows)] -macro_rules! check { - ($funcall:expr) => ( - if unsafe { $funcall } == 0 { - try!(Err(io::Error::last_os_error())); - } - ); -} -#[cfg(windows)] fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> { let handle = unsafe { kernel32::GetStdHandle(fd) }; if handle == winapi::INVALID_HANDLE_VALUE { @@ -341,7 +333,7 @@ const TIOCGWINSZ: libc::c_ulong = 0x5413; target_os = "android", target_os = "macos", target_os = "freebsd"))] -fn get_columns() -> usize { +fn get_columns(_: Handle) -> usize { use std::mem::zeroed; use libc::c_ushort; use libc; @@ -363,7 +355,7 @@ fn get_columns() -> usize { } } #[cfg(windows)] -fn get_columns(handle: winapi::HANDLE) -> usize { +fn get_columns(handle: Handle) -> usize { let mut info = unsafe { mem::zeroed() }; match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } { 0 => 80, @@ -870,6 +862,16 @@ fn stdin() -> Result<InputBuffer> { Ok(InputBuffer(handle)) } +#[cfg(unix)] +fn stdout_handle() -> Result<Handle> { + Ok(()) +} +#[cfg(windows)] +fn stdout_handle() -> Result<Handle> { + let handle = try!(get_std_handle(STDOUT_FILENO)); + Ok(handle) +} + #[cfg(windows)] struct InputBuffer(winapi::HANDLE); #[cfg(windows)] @@ -891,9 +893,10 @@ fn readline_edit(prompt: &str, original_mode: Mode) -> Result<String> { let mut stdout = io::stdout(); + let stdout_handle = try!(stdout_handle()); kill_ring.reset(); - let mut s = try!(State::new(&mut stdout, prompt, history.len())); + let mut s = State::new(&mut stdout, stdout_handle, prompt, history.len()); try!(s.refresh_line()); let stdin = try!(stdin()); @@ -1271,30 +1274,11 @@ 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: "", @@ -1304,7 +1288,7 @@ mod test { cols: cols, history_index: 0, snapshot: LineBuffer::with_capacity(100), - output_handle: ptr::null_mut(), + output_handle: Default::default(), } } -- GitLab