Skip to content

Commit

Permalink
Command API experiment (#175)
Browse files Browse the repository at this point in the history
- Command API to introduce easier usability, better performance, and more control over to which buffer to write, and when to flush the buffer to the terminal.
  • Loading branch information
TimonPost committed Jul 24, 2019
1 parent 7260da1 commit 1a60924
Show file tree
Hide file tree
Showing 44 changed files with 1,409 additions and 368 deletions.
14 changes: 7 additions & 7 deletions Cargo.toml
Expand Up @@ -28,16 +28,16 @@ members = [
"crossterm_style",
"crossterm_terminal",
"crossterm_input",
"crossterm_screen",
"crossterm_screen"
]

[dependencies]
crossterm_screen = { optional = true, version = "0.2.3" }
crossterm_cursor = { optional = true, version = "0.2.4" }
crossterm_terminal = { optional = true, version = "0.2.4" }
crossterm_style = { optional = true, version = "0.3.3" }
crossterm_input = { optional = true, version = "0.3.6" }
crossterm_utils = { optional = false, version = "0.2.3" }
crossterm_screen = { optional = true, path = "./crossterm_screen" }
crossterm_cursor = { optional = true, path = "./crossterm_cursor" }
crossterm_terminal = { optional = true, path = "./crossterm_terminal" }
crossterm_style = { optional = true, path = "./crossterm_style" }
crossterm_input = { optional = true, path = "./crossterm_input" }
crossterm_utils = { optional = false, path = "./crossterm_utils"}

[lib]
name = "crossterm"
Expand Down
34 changes: 9 additions & 25 deletions README.md
Expand Up @@ -71,7 +71,6 @@ crossterm = "0.9.6"
- [Examples](https://github.com/TimonPost/crossterm/tree/master/examples)

## Features
These are the features from this crate:

- Cross-platform
- Multithreaded (send, sync)
Expand Down Expand Up @@ -105,16 +104,19 @@ These are the features from this crate:
## Examples
These are some basic examples demonstrating how to use this crate. See [examples](https://github.com/TimonPost/crossterm/blob/master/examples/) for more.

### Command API

My first recommendation is to use the [command API](https://timonpost.github.io/crossterm/docs/command.html) because this might replace some of the existing API in the future.
Because it is more convenient, faster, and easier to use.

### Crossterm Type
This is a wrapper for all the modules crossterm provides like terminal, cursor, styling and input.
This is a wrapper for all the modules crossterm provides like terminal, cursor, styling, and input.

Good documentation can be found at the following places: [docs](https://docs.rs/crossterm/), [examples](https://github.com/TimonPost/crossterm/blob/master/examples/crossterm.rs).

```rust
// screen whereon the `Crossterm` methods will be executed.
let crossterm = Crossterm::new();

// get instance of the modules, whereafter you can use the methods the particularly module provides.
let color = crossterm.color();
let cursor = crossterm.cursor();
let terminal = crossterm.terminal();
Expand All @@ -138,9 +140,6 @@ println!("{} Underlined {} No Underline", Attribute::Underlined, Attribute::NoUn
// you could also call different attribute methods on a `&str` and keep on chaining if needed.
let styled_text = "Bold Underlined".bold().underlined();
println!("{}", styled_text);

// old-way but still usable
let styled_text = style("Bold Underlined").bold().underlined();
```

_style text with colors_
Expand All @@ -151,9 +150,6 @@ println!("{} Blue background color", Colored::Bg(Color::Blue));
// you can also call different coloring methods on a `&str`.
let styled_text = "Bold Underlined".red().on_blue();
println!("{}", styled_text);

// old-way but still usable
let styled_text = style("Bold Underlined").with(Color::Red).on(Color::Blue);
```
_style text with RGB and ANSI Value_
```rust
Expand Down Expand Up @@ -209,7 +205,6 @@ cursor.hide();
cursor.show();
// blink or not blinking of the cursor (not widely supported)
cursor.blink(true)

```

### Terminal
Expand Down Expand Up @@ -311,7 +306,7 @@ input.disable_mouse_mode().unwrap();
```

### Alternate and Raw Screen
These concepts are a little more complex and would take over the README, please checkout the [docs](https://docs.rs/crossterm_screen/), [book](https://timonpost.github.io/crossterm/docs/screen.html), and [examples](https://github.com/TimonPost/crossterm/tree/master/examples).
These concepts are a little more complex and would take over the README, please check out the [docs](https://docs.rs/crossterm_screen/), [book](https://timonpost.github.io/crossterm/docs/screen.html), and [examples](https://github.com/TimonPost/crossterm/tree/master/examples).

## Used By
- [Broot](https://dystroy.org/broot/)
Expand All @@ -334,29 +329,18 @@ These concepts are a little more complex and would take over the README, please
This crate supports all Unix terminals and Windows terminals down to Windows 7; however, not all of the terminals have been tested.
If you have used this library for a terminal other than the above list without issues, then feel free to add it to the above list - I really would appreciate it!

## Notice
This library is mostly stable now, and I don't expect it to change much.
If there are any changes that will affect previous versions I will [describe](https://github.com/TimonPost/crossterm/blob/master/docs/UPGRADE.md) what to change to upgrade.

## Todo
- Tests
Find a way to test: color, alternate screen, rawscreen

## Contributing

I highly appreciate it when you contribute to this crate.
Also, since my native language is not English my grammar and sentence order will not be perfect.
So improving this by correcting these mistakes will help both me and the reader of the docs.

Check [Contributing](https://github.com/TimonPost/crossterm/blob/master/docs/Contributing.md) for more info about branches and code architecture.
Please visit the discord or issue list for more information

## Authors

* **Timon Post** - *Project Owner & creator*

## Support

Crossterm took a lot of time to develop, I really appreciate any donation given to support the development of crossterm.
Crossterm took a lot of time to develop, I appreciate any donation given to support the development of crossterm.

[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Z8QK6XU749JB2)

Expand Down
2 changes: 1 addition & 1 deletion crossterm_cursor/Cargo.toml
Expand Up @@ -16,4 +16,4 @@ winapi = { version = "0.3.7", features = ["wincon","winnt","minwindef"] }
crossterm_winapi = "0.1.4"

[dependencies]
crossterm_utils = "0.2.3"
crossterm_utils = {path="../crossterm_utils"}
65 changes: 63 additions & 2 deletions crossterm_cursor/examples/cursor.rs
Expand Up @@ -86,7 +86,68 @@ pub fn blink_cursor() {
cursor.blink(false);
}

use self::crossterm_cursor::{
execute, queue, BlinkOff, BlinkOn, Command, Down, ExecutableCommand, Goto, Hide, Left, Output,
QueueableCommand, ResetPos, Right, SavePos, Show, Up,
};
use std::fmt::Display;
use std::io::{stdout, Write};
use std::thread;
use std::time::{Duration, Instant};

fn benchmark_cursor_goto() -> f32 {
let mut stdout = ::std::io::stdout();

let instant1 = Instant::now();
for i in 0..10 {
for x in 0..200 {
for y in 0..50 {
queue!(stdout, Goto(x, y), Hide, Output(y.to_string()));
}
}
}

let new_api = instant1.elapsed();
let cursor = cursor();
let instant2 = Instant::now();
for i in 0..10 {
for x in 0..200 {
for y in 0..50 {
cursor.goto(x, y);
print!("{}", y.to_string());
}
}
}
let old_api = instant2.elapsed();

let speed_improvement = ((old_api.as_millis() as f32 - new_api.as_millis() as f32)
/ old_api.as_millis() as f32)
* 100.;

speed_improvement
}

fn start_goto_benchmark() {
let mut stdout = ::std::io::stdout();

let mut performance_metrics = Vec::new();
for i in 1..=20 {
performance_metrics.push(benchmark_cursor_goto());
}

println!(
"Average Performance Improvement mesearued 10 times {:.2} %",
performance_metrics.iter().sum::<f32>() / 20.
);
}

fn main() {
goto();
pos();
let mut stdout = ::std::io::stdout();

stdout
.queue(Goto(5, 5))
.queue(Output("#".to_string()))
.flush();

println!("out: {}", Output("1".to_string()));
}
52 changes: 40 additions & 12 deletions crossterm_cursor/src/cursor/ansi_cursor.rs
Expand Up @@ -6,7 +6,35 @@ use super::ITerminalCursor;
use crate::sys::get_cursor_position;
use std::io::Write;

use crossterm_utils::Result;
use crossterm_utils::{write_cout, ErrorKind, Result};

#[inline]
pub fn get_goto_ansi(x: u16, y: u16) -> String {
format!(csi!("{};{}H"), y + 1, x + 1)
}
#[inline]
pub fn get_move_up_ansi(count: u16) -> String {
format!(csi!("{}A"), count)
}
#[inline]
pub fn get_move_right_ansi(count: u16) -> String {
format!(csi!("{}C"), count)
}
#[inline]
pub fn get_move_down_ansi(count: u16) -> String {
format!(csi!("{}B"), count)
}
#[inline]
pub fn get_move_left_ansi(count: u16) -> String {
format!(csi!("{}D"), count)
}

pub static SAFE_POS_ANSI: &'static str = csi!("s");
pub static RESET_POS_ANSI: &'static str = csi!("u");
pub static HIDE_ANSI: &'static str = csi!("?25l");
pub static SHOW_ANSI: &'static str = csi!("?25h");
pub static BLINK_ON_ANSI: &'static str = csi!("?12h");
pub static BLINK_OFF_ANSI: &'static str = csi!("?12l");

/// This struct is an ANSI implementation for cursor related actions.
pub struct AnsiCursor;
Expand All @@ -19,7 +47,7 @@ impl AnsiCursor {

impl ITerminalCursor for AnsiCursor {
fn goto(&self, x: u16, y: u16) -> Result<()> {
write_cout!(format!(csi!("{};{}H"), y + 1, x + 1))?;
write_cout!(get_goto_ansi(x, y))?;
Ok(())
}

Expand All @@ -28,50 +56,50 @@ impl ITerminalCursor for AnsiCursor {
}

fn move_up(&self, count: u16) -> Result<()> {
write_cout!(&format!(csi!("{}A"), count))?;
write_cout!(get_move_up_ansi(count))?;
Ok(())
}

fn move_right(&self, count: u16) -> Result<()> {
write_cout!(&format!(csi!("{}C"), count))?;
write_cout!(get_move_right_ansi(count))?;
Ok(())
}

fn move_down(&self, count: u16) -> Result<()> {
write_cout!(&format!(csi!("{}B"), count))?;
write_cout!(get_move_down_ansi(count))?;
Ok(())
}

fn move_left(&self, count: u16) -> Result<()> {
write_cout!(&format!(csi!("{}D"), count))?;
write_cout!(get_move_left_ansi(count))?;
Ok(())
}

fn save_position(&self) -> Result<()> {
write_cout!(csi!("s"))?;
write_cout!(SAFE_POS_ANSI)?;
Ok(())
}

fn reset_position(&self) -> Result<()> {
write_cout!(csi!("u"))?;
write_cout!(RESET_POS_ANSI)?;
Ok(())
}

fn hide(&self) -> Result<()> {
write_cout!(csi!("?25l"))?;
write_cout!(HIDE_ANSI)?;
Ok(())
}

fn show(&self) -> Result<()> {
write_cout!(csi!("?25h"))?;
write_cout!(SHOW_ANSI)?;
Ok(())
}

fn blink(&self, blink: bool) -> Result<()> {
if blink {
write_cout!(csi!("?12h"))?;
write_cout!(BLINK_ON_ANSI)?;
} else {
write_cout!(csi!("?12l"))?;
write_cout!(BLINK_OFF_ANSI)?;
}
Ok(())
}
Expand Down

0 comments on commit 1a60924

Please sign in to comment.