Command API improvements: don’t ignore errors, don’t require reassigning stdout back to itself (#226)
This commit is contained in:
parent
1b307c2010
commit
e5ed617a7b
@ -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));
|
||||
|
||||
|
@ -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(())
|
||||
|
@ -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<T: Display> {
|
||||
pub trait QueueableCommand<T: Display>: Sized {
|
||||
/// Queues the given command for later execution.
|
||||
fn queue(self, command: impl Command<AnsiType = T>) -> Self;
|
||||
fn queue(&mut self, command: impl Command<AnsiType = T>) -> Result<&mut Self>;
|
||||
}
|
||||
|
||||
/// A trait that defines behaviour for a command that will be executed immediately.
|
||||
pub trait ExecutableCommand<T: Display> {
|
||||
pub trait ExecutableCommand<T: Display>: Sized {
|
||||
/// Execute the given command directly.
|
||||
fn execute(self, command: impl Command<AnsiType = T>) -> Self;
|
||||
fn execute(&mut self, command: impl Command<AnsiType = T>) -> Result<&mut Self>;
|
||||
}
|
||||
|
||||
impl<T, A> QueueableCommand<A> 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<AnsiType = A>) -> Self {
|
||||
let _ = queue!(self, command);
|
||||
self
|
||||
fn queue(&mut self, command: impl Command<AnsiType = A>) -> 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<AnsiType = A>) -> Self {
|
||||
let _ = execute!(self, command);
|
||||
self
|
||||
fn execute(&mut self, command: impl Command<AnsiType = A>) -> Result<&mut Self> {
|
||||
execute!(self, command)?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -135,6 +135,8 @@ pub fn exit() {
|
||||
}
|
||||
|
||||
// cargo run --example terminal
|
||||
fn main() {
|
||||
let _ = scroll_down();
|
||||
fn main() -> io::Result<()> {
|
||||
scroll_down()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user