From e5ed617a7b1e5bdf850d55d5d3e533cdce694cf8 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Wed, 18 Sep 2019 06:29:02 -0700 Subject: [PATCH] =?UTF-8?q?Command=20API=20improvements:=20don=E2=80=99t?= =?UTF-8?q?=20ignore=20errors,=20don=E2=80=99t=20require=20reassigning=20s?= =?UTF-8?q?tdout=20back=20to=20itself=20(#226)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crossterm_style/src/winapi_color.rs | 4 +- .../src/terminal/winapi_terminal.rs | 2 +- crossterm_utils/src/command.rs | 21 ++++---- docs/mdbook/src/command.md | 14 ++--- examples/command.rs | 52 +++++++++++-------- examples/terminal.rs | 6 ++- 6 files changed, 54 insertions(+), 45 deletions(-) diff --git a/crossterm_style/src/winapi_color.rs b/crossterm_style/src/winapi_color.rs index ea67c9ff..458b089a 100644 --- a/crossterm_style/src/winapi_color.rs +++ b/crossterm_style/src/winapi_color.rs @@ -33,7 +33,7 @@ impl WinApiColor { impl ITerminalColor for WinApiColor { fn set_fg(&self, fg_color: Color) -> Result<()> { // init the original color in case it is not set. - let _ = init_console_color()?; + init_console_color()?; let color_value = color_value(Colored::Fg(fg_color)); @@ -60,7 +60,7 @@ impl ITerminalColor for WinApiColor { fn set_bg(&self, bg_color: Color) -> Result<()> { // init the original color in case it is not set. - let _ = init_console_color()?; + init_console_color()?; let color_value = color_value(Colored::Bg(bg_color)); diff --git a/crossterm_terminal/src/terminal/winapi_terminal.rs b/crossterm_terminal/src/terminal/winapi_terminal.rs index 86ff1c0f..0d920ade 100644 --- a/crossterm_terminal/src/terminal/winapi_terminal.rs +++ b/crossterm_terminal/src/terminal/winapi_terminal.rs @@ -266,7 +266,7 @@ pub fn clear_until_line(location: Coord, buffer_size: Size, current_attribute: u fn clear(start_location: Coord, cells_to_write: u32, current_attribute: u16) -> Result<()> { let console = Console::from(Handle::current_out_handle()?); - let _ = console.fill_whit_character(start_location, cells_to_write, ' ')?; + console.fill_whit_character(start_location, cells_to_write, ' ')?; console.fill_whit_attribute(start_location, cells_to_write, current_attribute)?; Ok(()) diff --git a/crossterm_utils/src/command.rs b/crossterm_utils/src/command.rs index 96242022..72c47318 100644 --- a/crossterm_utils/src/command.rs +++ b/crossterm_utils/src/command.rs @@ -1,7 +1,6 @@ use std::fmt::Display; use std::io::Write; -#[cfg(windows)] use crate::Result; use crate::{execute, impl_display, queue, write_cout}; @@ -32,15 +31,15 @@ pub trait Command { /// A trait that defines behaviour for a command that can be used to be executed at a later time point. /// This can be used in order to get more performance. -pub trait QueueableCommand { +pub trait QueueableCommand: Sized { /// Queues the given command for later execution. - fn queue(self, command: impl Command) -> Self; + fn queue(&mut self, command: impl Command) -> Result<&mut Self>; } /// A trait that defines behaviour for a command that will be executed immediately. -pub trait ExecutableCommand { +pub trait ExecutableCommand: Sized { /// Execute the given command directly. - fn execute(self, command: impl Command) -> Self; + fn execute(&mut self, command: impl Command) -> Result<&mut Self>; } impl QueueableCommand for T @@ -68,9 +67,9 @@ where /// This is happening because windows versions lower then 10 do not support ANSI codes, and thus they can't be written to the given buffer. /// Because of that there is no difference between `execute` and `queue` for those windows versions. /// - Queuing might sound that there is some scheduling going on, however, this means that we write to the stdout without flushing which will cause commands to be stored in the buffer without them being written to the terminal. - fn queue(mut self, command: impl Command) -> Self { - let _ = queue!(self, command); - self + fn queue(&mut self, command: impl Command) -> Result<&mut Self> { + queue!(self, command)?; + Ok(self) } } @@ -92,9 +91,9 @@ where /// - In case of Windows versions lower than 10, a direct WinApi call will be made. /// This is happening because Windows versions lower then 10 do not support ANSI codes, and thus they can't be written to the given buffer. /// Because of that there is no difference between `execute` and `queue` for those windows versions. - fn execute(mut self, command: impl Command) -> Self { - let _ = execute!(self, command); - self + fn execute(&mut self, command: impl Command) -> Result<&mut Self> { + execute!(self, command)?; + Ok(self) } } diff --git a/docs/mdbook/src/command.md b/docs/mdbook/src/command.md index c9572a30..1f175647 100644 --- a/docs/mdbook/src/command.md +++ b/docs/mdbook/src/command.md @@ -76,7 +76,7 @@ By doing this you can make efficient use of the terminal buffer and get better p ```rust let mut stdout = stdout(); -stdout = stdout.queue(Goto(5,5)); +stdout.queue(Goto(5,5))?; // some other code ... @@ -107,10 +107,10 @@ This is fine if you are not executing lots of commands. _functions_ ```rust -stdout().execute(Goto(5,5)); +stdout().execute(Goto(5,5))?; ``` The `execute` function returns it self, therefore you are able to use this to execute another command - like `stdout.execute(Goto(5,5)).execute(Clear(ClearType::All))` + like `stdout.execute(Goto(5,5))?.execute(Clear(ClearType::All))?` _macro's_ ```rust @@ -130,14 +130,14 @@ use std::io::stdout(); let mut stdout = stdout(); -stdout = stdout.execute(Clear(ClearType::All)); +stdout.execute(Clear(ClearType::All))?; for y in 0..40 { for x in 0..150 { if (y == 0 || y == 40 - 1) || (x == 0 || x == 150 - 1) { - stdout = stdout - .queue(Goto(x,y)) - .queue(PrintStyledFont( "█".magenta())); + stdout + .queue(Goto(x,y))? + .queue(PrintStyledFont( "█".magenta()))?; } } stdout.flush(); diff --git a/examples/command.rs b/examples/command.rs index 111f0171..bcced867 100644 --- a/examples/command.rs +++ b/examples/command.rs @@ -3,73 +3,81 @@ use std::io::{stdout, Write}; use crossterm::{ - execute, queue, Clear, ClearType, ExecutableCommand, Goto, Output, QueueableCommand, + execute, queue, Clear, ClearType, ExecutableCommand, Goto, Output, QueueableCommand, Result, }; /// execute commands by using normal functions -fn execute_command_directly_using_functions() { +fn execute_command_directly_using_functions() -> Result<()> { // single command - let _ = stdout().execute(Output("Text1 ".to_string())); + stdout().execute(Output("Text1 ".to_string()))?; // multiple commands - let _ = stdout() - .execute(Output("Text2 ".to_string())) - .execute(Output("Text3 ".to_string())); + stdout() + .execute(Output("Text2 ".to_string()))? + .execute(Output("Text3 ".to_string()))?; + + Ok(()) } /// execute commands by using macro's -fn execute_command_directly_using_macros() { +fn execute_command_directly_using_macros() -> Result<()> { // single command - let _ = execute!(stdout(), Output("Text1 ".to_string())); + execute!(stdout(), Output("Text1 ".to_string()))?; // multiple commands - let _ = execute!( + execute!( stdout(), Output("Text2 ".to_string()), Output("Text 3".to_string()) - ); + )?; + + Ok(()) } /// queue commands without executing them directly by using normal functions -fn later_execution_command_using_functions() { +fn later_execution_command_using_functions() -> Result<()> { let mut sdout = stdout(); // single command - sdout = sdout.queue(Output("Text1 ".to_string())); + sdout.queue(Output("Text1 ".to_string()))?; // multiple commands - sdout = sdout - .queue(Clear(ClearType::All)) - .queue(Goto(5, 5)) + sdout + .queue(Clear(ClearType::All))? + .queue(Goto(5, 5))? .queue(Output( "console cleared, and moved to coord X: 5 Y: 5 ".to_string(), - )); + ))?; ::std::thread::sleep(std::time::Duration::from_millis(2000)); // when you call this all commands will be executed - let _ = sdout.flush(); + sdout.flush()?; + + Ok(()) } /// queue commands without executing them directly by using macro's -fn later_execution_command_directly_using_macros() { +fn later_execution_command_directly_using_macros() -> Result<()> { let mut stdout = stdout(); // single command - let _ = queue!(stdout, Output("Text1 ".to_string())); + queue!(stdout, Output("Text1 ".to_string()))?; // multiple commands - let _ = queue!( + queue!( stdout, Clear(ClearType::All), Goto(5, 5), Output("console cleared, and moved to coord X: 5 Y: 5 ".to_string()) - ); + )?; ::std::thread::sleep(std::time::Duration::from_millis(2000)); // when you call this all commands will be executed - let _ = stdout.flush(); + stdout.flush()?; + + Ok(()) } // cargo run --example command diff --git a/examples/terminal.rs b/examples/terminal.rs index 0ec67400..b5acd97c 100644 --- a/examples/terminal.rs +++ b/examples/terminal.rs @@ -135,6 +135,8 @@ pub fn exit() { } // cargo run --example terminal -fn main() { - let _ = scroll_down(); +fn main() -> io::Result<()> { + scroll_down()?; + + Ok(()) }