From b7497bae62091b15d2c4e6dc65cb955c1efabf4f Mon Sep 17 00:00:00 2001 From: Timon Post Date: Sat, 16 Nov 2019 19:24:36 +0100 Subject: [PATCH 1/5] Added interactive test --- examples/src/bin/foo.rs | 0 interactive-test/Cargo.toml | 19 +++ interactive-test/src/macros.rs | 29 ++++ interactive-test/src/main.rs | 125 +++++++++++++++ interactive-test/src/test.rs | 4 + interactive-test/src/test/attribute.rs | 47 ++++++ interactive-test/src/test/color.rs | 194 ++++++++++++++++++++++++ interactive-test/src/test/cursor.rs | 201 +++++++++++++++++++++++++ interactive-test/src/test/input.rs | 1 + 9 files changed, 620 insertions(+) create mode 100644 examples/src/bin/foo.rs create mode 100644 interactive-test/Cargo.toml create mode 100644 interactive-test/src/macros.rs create mode 100644 interactive-test/src/main.rs create mode 100644 interactive-test/src/test.rs create mode 100644 interactive-test/src/test/attribute.rs create mode 100644 interactive-test/src/test/color.rs create mode 100644 interactive-test/src/test/cursor.rs create mode 100644 interactive-test/src/test/input.rs diff --git a/examples/src/bin/foo.rs b/examples/src/bin/foo.rs new file mode 100644 index 0000000..e69de29 diff --git a/interactive-test/Cargo.toml b/interactive-test/Cargo.toml new file mode 100644 index 0000000..c794c0c --- /dev/null +++ b/interactive-test/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "interactive-test" +version = "0.0.1" +authors = ["Robert Vojta "] +edition = "2018" +description = "Interactive test for the anes." +repository = "https://github.com/zrzka/anes-rs" +documentation = "https://docs.rs/anes/" +license = "MIT OR Apache-2.0" +exclude = ["target", "Cargo.lock"] +readme = "README.md" +publish = false + +[badges] +maintenance = { status = "experimental" } + +[dependencies] +crossterm = {git="https://github.com/crossterm-rs/crossterm"} +anes = "0.1.4" \ No newline at end of file diff --git a/interactive-test/src/macros.rs b/interactive-test/src/macros.rs new file mode 100644 index 0000000..973a2bc --- /dev/null +++ b/interactive-test/src/macros.rs @@ -0,0 +1,29 @@ +macro_rules! run_tests { + ( + $dst:expr, + $( + $testfn:ident + ),* + $(,)? + ) => { + use crossterm::{queue, style, terminal, cursor}; + $( + queue!( + $dst, + style::ResetColor, + terminal::Clear(terminal::ClearType::All), + cursor::MoveTo(1, 1), + cursor::Show, + cursor::EnableBlinking + )?; + + $testfn($dst)?; + + match $crate::read_char() { + Ok('q') => return Ok(()), + Err(e) => return Err(e), + _ => {}, + }; + )* + } +} diff --git a/interactive-test/src/main.rs b/interactive-test/src/main.rs new file mode 100644 index 0000000..64b3e88 --- /dev/null +++ b/interactive-test/src/main.rs @@ -0,0 +1,125 @@ +use std::io::{self, Write}; + +pub use crossterm::{ + cursor, execute, input, queue, screen, style, + terminal::{self, ClearType}, + Command, Output, Result, +}; + +#[macro_use] +mod macros; +mod test; + +struct MoveCursorToNextLine(u16); + +impl Command for MoveCursorToNextLine { + type AnsiType = String; + + fn ansi_code(&self) -> Self::AnsiType { + format!("{}", anes::MoveCursorToNextLine(self.0)) + } + + fn execute_winapi(&self) -> Result<()> { + unimplemented!() + } +} + +struct MoveCursorToPreviousLine(u16); + +impl Command for MoveCursorToPreviousLine { + type AnsiType = String; + + fn ansi_code(&self) -> Self::AnsiType { + format!("{}", anes::MoveCursorToPreviousLine(self.0)) + } + + fn execute_winapi(&self) -> Result<()> { + unimplemented!() + } +} + +struct MoveCursorToColumn(u16); + +impl Command for MoveCursorToColumn { + type AnsiType = String; + + fn ansi_code(&self) -> Self::AnsiType { + format!("{}", anes::MoveCursorToColumn(self.0)) + } + + fn execute_winapi(&self) -> Result<()> { + unimplemented!() + } +} + +const MENU: &str = r#"Crossterm interactive test + +Controls: + + - 'q' - quit interactive test (or return to this menu) + - any other key - continue with next step + +Available tests: + +1. cursor +2. color (foreground, background) +3. attributes (bold, italic, ...) +4. input + +Select test to run ('1', '2', ...) or hit 'q' to quit. +"#; + +fn run(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, screen::EnterAlternateScreen)?; + + let _raw = screen::RawScreen::into_raw_mode()?; + + loop { + queue!( + w, + style::ResetColor, + terminal::Clear(ClearType::All), + cursor::Hide, + cursor::MoveTo(1, 1) + ); + + for line in MENU.split('\n') { + queue!(w, Output(line), MoveCursorToNextLine(1))?; + } + + w.flush()?; + + match read_char()? { + '1' => test::cursor::run(w)?, + '2' => test::color::run(w)?, + '3' => test::attribute::run(w)?, + '4' => unreachable!("input not implemented"), + 'q' => break, + _ => {} + }; + } + + execute!( + w, + style::ResetColor, + cursor::Show, + screen::LeaveAlternateScreen + )?; + Ok(()) +} + +pub fn read_char() -> Result { + input::input().read_char() +} + +pub fn buffer_size() -> Result<(u16, u16)> { + terminal::size() +} + +fn main() -> Result<()> { + let mut stderr = io::stdout(); + run(&mut stderr) +} diff --git a/interactive-test/src/test.rs b/interactive-test/src/test.rs new file mode 100644 index 0000000..b4cac4e --- /dev/null +++ b/interactive-test/src/test.rs @@ -0,0 +1,4 @@ +pub mod attribute; +pub mod color; +pub mod cursor; +mod input; diff --git a/interactive-test/src/test/attribute.rs b/interactive-test/src/test/attribute.rs new file mode 100644 index 0000000..f90b343 --- /dev/null +++ b/interactive-test/src/test/attribute.rs @@ -0,0 +1,47 @@ +use crate::{MoveCursorToNextLine, Result}; +use crossterm::{queue, style, Output}; +use std::io::Write; + +const ATTRIBUTES: [(style::Attribute, style::Attribute); 6] = [ + (style::Attribute::Bold, style::Attribute::NoBold), + (style::Attribute::Italic, style::Attribute::NoItalic), + (style::Attribute::Underlined, style::Attribute::NoUnderline), + (style::Attribute::Reverse, style::Attribute::NoReverse), + ( + style::Attribute::CrossedOut, + style::Attribute::NotCrossedOut, + ), + (style::Attribute::SlowBlink, style::Attribute::NoBlink), +]; + +fn test_set_display_attributes(w: &mut W) -> Result<()> +where + W: Write, +{ + queue!(w, Output("Display attributes"), MoveCursorToNextLine(2))?; + + for (on, off) in &ATTRIBUTES { + queue!( + w, + style::SetAttribute(*on), + Output(format!("{:>width$} ", format!("{:?}", on), width = 35)), + style::SetAttribute(*off), + Output(format!("{:>width$}", format!("{:?}", off), width = 35)), + style::ResetColor, + MoveCursorToNextLine(1) + )?; + } + + w.flush()?; + + Ok(()) +} + +#[allow(clippy::cognitive_complexity)] +pub fn run(w: &mut W) -> Result<()> +where + W: Write, +{ + run_tests!(w, test_set_display_attributes,); + Ok(()) +} diff --git a/interactive-test/src/test/color.rs b/interactive-test/src/test/color.rs new file mode 100644 index 0000000..de59a31 --- /dev/null +++ b/interactive-test/src/test/color.rs @@ -0,0 +1,194 @@ +use crate::{MoveCursorToNextLine, Result}; +use crossterm::{cursor, queue, style, style::Color, Output}; +use std::io::Write; + +const COLORS: [Color; 21] = [ + Color::Black, + Color::DarkGrey, + Color::Grey, + Color::White, + Color::DarkRed, + Color::Red, + Color::DarkGreen, + Color::Green, + Color::DarkYellow, + Color::Yellow, + Color::DarkBlue, + Color::Blue, + Color::DarkMagenta, + Color::Magenta, + Color::DarkCyan, + Color::Cyan, + Color::AnsiValue(0), + Color::AnsiValue(15), + Color::Rgb { r: 255, g: 0, b: 0 }, + Color::Rgb { r: 0, g: 255, b: 0 }, + Color::Rgb { r: 0, g: 0, b: 255 }, +]; + +fn test_set_foreground_color(w: &mut W) -> Result<()> +where + W: Write, +{ + queue!( + w, + Output("Foreground colors on the black & white background"), + MoveCursorToNextLine(2) + )?; + + for color in &COLORS { + queue!( + w, + style::SetForegroundColor(*color), + style::SetBackgroundColor(Color::Black), + Output(format!( + "{:>width$} ", + format!("{:?} ████████████", color), + width = 40 + )), + style::SetBackgroundColor(Color::White), + Output(format!( + "{:>width$}", + format!("{:?} ████████████", color), + width = 40 + )), + MoveCursorToNextLine(1) + )?; + } + + w.flush()?; + + Ok(()) +} + +fn test_set_background_color(w: &mut W) -> Result<()> +where + W: Write, +{ + queue!( + w, + Output("Background colors with black & white foreground"), + MoveCursorToNextLine(2) + )?; + + for color in &COLORS { + queue!( + w, + style::SetBackgroundColor(*color), + style::SetForegroundColor(Color::Black), + Output(format!( + "{:>width$} ", + format!("{:?} ▒▒▒▒▒▒▒▒▒▒▒▒", color), + width = 40 + )), + style::SetForegroundColor(Color::White), + Output(format!( + "{:>width$}", + format!("{:?} ▒▒▒▒▒▒▒▒▒▒▒▒", color), + width = 40 + )), + MoveCursorToNextLine(1) + )?; + } + + w.flush()?; + + Ok(()) +} + +fn test_color_values_matrix_16x16(w: &mut W, title: &str, color: F) -> Result<()> +where + W: Write, + F: Fn(u16, u16) -> Color, +{ + queue!(w, Output(title))?; + + for idx in 0..=15 { + queue!( + w, + cursor::MoveTo(1, idx + 4), + Output(format!("{:>width$}", idx, width = 2)) + )?; + queue!( + w, + cursor::MoveTo(idx * 3 + 3, 3), + Output(format!("{:>width$}", idx, width = 3)) + )?; + } + + for row in 0..=15u16 { + queue!(w, cursor::MoveTo(4, row + 4))?; + for col in 0..=15u16 { + queue!(w, style::SetForegroundColor(color(col, row)), Output("███"))?; + } + queue!( + w, + style::SetForegroundColor(Color::White), + Output(format!("{:>width$} ..= ", row * 16, width = 3)), + Output(format!("{:>width$}", row * 16 + 15, width = 3)) + )?; + } + + w.flush()?; + + Ok(()) +} + +fn test_color_ansi_values(w: &mut W) -> Result<()> +where + W: Write, +{ + test_color_values_matrix_16x16(w, "Color::Ansi values", |col, row| { + Color::AnsiValue((row * 16 + col) as u8) + }) +} + +fn test_rgb_red_values(w: &mut W) -> Result<()> +where + W: Write, +{ + test_color_values_matrix_16x16(w, "Color::Rgb red values", |col, row| Color::Rgb { + r: (row * 16 + col) as u8, + g: 0 as u8, + b: 0, + }) +} + +fn test_rgb_green_values(w: &mut W) -> Result<()> +where + W: Write, +{ + test_color_values_matrix_16x16(w, "Color::Rgb green values", |col, row| Color::Rgb { + r: 0, + g: (row * 16 + col) as u8, + b: 0, + }) +} + +fn test_rgb_blue_values(w: &mut W) -> Result<()> +where + W: Write, +{ + test_color_values_matrix_16x16(w, "Color::Rgb blue values", |col, row| Color::Rgb { + r: 0, + g: 0, + b: (row * 16 + col) as u8, + }) +} + +#[allow(clippy::cognitive_complexity)] +pub fn run(w: &mut W) -> Result<()> +where + W: Write, +{ + run_tests!( + w, + test_set_foreground_color, + test_set_background_color, + test_color_ansi_values, + test_rgb_red_values, + test_rgb_green_values, + test_rgb_blue_values, + ); + Ok(()) +} diff --git a/interactive-test/src/test/cursor.rs b/interactive-test/src/test/cursor.rs new file mode 100644 index 0000000..ca81470 --- /dev/null +++ b/interactive-test/src/test/cursor.rs @@ -0,0 +1,201 @@ +use std::io::Write; + +use crate::{MoveCursorToColumn, MoveCursorToNextLine, MoveCursorToPreviousLine, Result}; +use crossterm::cursor::MoveTo; +use crossterm::{cursor, execute, queue, style, style::Colorize, Command, Output}; +use std::thread; +use std::time::Duration; + +fn test_move_cursor_up(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "Move Up (2)", |_, _| cursor::MoveUp(2)) +} + +fn test_move_cursor_down(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "Move Down (2)", |_, _| cursor::MoveDown(2)) +} + +fn test_move_cursor_left(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "Move Left (2)", |_, _| cursor::MoveLeft(2)) +} + +fn test_move_cursor_right(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "Move Right (2)", |_, _| cursor::MoveRight(2)) +} + +fn test_move_cursor_to_previous_line(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "MoveCursorToPreviousLine (2)", |_, _| { + MoveCursorToPreviousLine(2) + }) +} + +fn test_move_cursor_to_next_line(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "MoveCursorToNextLine (2)", |_, _| { + MoveCursorToNextLine(2) + }) +} + +fn test_move_cursor_to_column(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box(w, "MoveCursorToColumn (2)", |center_x, _| { + MoveCursorToColumn(center_x + 2) + }) +} + +fn test_hide_cursor(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, Output("HideCursor"), cursor::Hide) +} + +fn test_show_cursor(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, Output("ShowCursor"), cursor::Show) +} + +fn test_enable_cursor_blinking(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, Output("EnableCursorBlinking"), cursor::EnableBlinking) +} + +fn test_disable_cursor_blinking(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, Output("DisableCursorBlinking"), cursor::DisableBlinking) +} + +fn test_move_cursor_to(w: &mut W) -> Result<()> +where + W: Write, +{ + draw_cursor_box( + w, + "MoveTo (x: 1, y: 1) removed from center", + |center_x, center_y| MoveTo(center_x + 1, center_y + 1), + ) +} + +fn test_save_restore_cursor_position(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, + cursor::MoveTo(0, 0), + Output("Save position, print character else were, after three seconds restore to old position."), + MoveCursorToNextLine(2), + Output("Save ->[ ]<- Position"), + cursor::MoveTo(8, 2), + cursor::SavePosition, + cursor::MoveTo(10,10), + Output("Move To ->[√]<- Position") + )?; + + thread::sleep(Duration::from_secs(3)); + + execute!(w, cursor::RestorePosition, Output("√")) +} + +/// Draws a box with an colored center, this center can be taken as a reference point after running the given cursor command. +fn draw_cursor_box(w: &mut W, description: &str, cursor_command: F) -> Result<()> +where + W: Write, + F: Fn(u16, u16) -> T, + T: Command, +{ + execute!( + w, + cursor::Hide, + cursor::MoveTo(0, 0), + style::SetForegroundColor(style::Color::Red), + Output(format!( + "Red box is the center. After the action: '{}' another box is drawn.", + description + )) + )?; + + let start_y = 2; + let width = 21; + let height = 11 + start_y; + let center_x = width / 2; + let center_y = (height + start_y) / 2; + + for row in start_y..=10 + start_y { + for column in 0..=width { + if (row == start_y || row == height - 1) || (column == 0 || column == width) { + queue!( + w, + cursor::MoveTo(column, row), + style::PrintStyledContent("▓".red()) + )?; + } else { + queue!( + w, + cursor::MoveTo(column, row), + style::PrintStyledContent("_".red().on_white()) + )?; + } + } + } + + queue!( + w, + cursor::MoveTo(center_x, center_y), + style::PrintStyledContent("▀".red().on_white()) + )?; + queue!( + w, + cursor_command(center_x, center_y), + style::PrintStyledContent("√".magenta().on_white()) + )?; + w.flush()?; + Ok(()) +} + +#[allow(clippy::cognitive_complexity)] +pub fn run(w: &mut W) -> Result<()> +where + W: Write, +{ + run_tests!( + w, + test_hide_cursor, + test_show_cursor, + test_enable_cursor_blinking, + test_disable_cursor_blinking, + test_move_cursor_left, + test_move_cursor_right, + test_move_cursor_up, + test_move_cursor_down, + test_move_cursor_to, + test_move_cursor_to_next_line, + test_move_cursor_to_previous_line, + test_move_cursor_to_column, + test_save_restore_cursor_position + ); + Ok(()) +} diff --git a/interactive-test/src/test/input.rs b/interactive-test/src/test/input.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/interactive-test/src/test/input.rs @@ -0,0 +1 @@ + From c611c68778473281fa2b33d7aebe66b8f068a31d Mon Sep 17 00:00:00 2001 From: Timon Post Date: Sat, 16 Nov 2019 19:41:30 +0100 Subject: [PATCH 2/5] Cleaned up cargo.toml --- Cargo.lock | 34 +++++++++++++++++++++++++++++++++ Cargo.toml | 3 ++- README.md | 4 ++-- examples/Cargo.toml | 2 +- examples/src/bin/command_bar.rs | 2 +- examples/src/bin/foo.rs | 1 + examples/src/bin/input.rs | 2 +- examples/src/bin/key_events.rs | 2 +- examples/src/bin/stderr.rs | 2 +- interactive-test/Cargo.toml | 13 ++++--------- 10 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c56d975..27ed7b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "anes" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "1.2.1" @@ -22,10 +27,29 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossterm" +version = "0.13.3" +dependencies = [ + "crossterm_winapi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossterm-examples" version = "0.0.1" dependencies = [ + "crossterm 0.13.3", +] + +[[package]] +name = "crossterm-interactive-test" +version = "0.0.1" +dependencies = [ + "anes 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossterm 0.12.1 (git+https://github.com/crossterm-rs/crossterm)", ] @@ -37,6 +61,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossterm_winapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "first-depth-search" version = "0.0.1" @@ -222,10 +254,12 @@ dependencies = [ ] [metadata] +"checksum anes 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e5e04b263cb24d859f06563beb27213c7bbfff2c61513763578eba297f4314e4" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum crossterm 0.12.1 (git+https://github.com/crossterm-rs/crossterm)" = "" "checksum crossterm_winapi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df25e92a352488d9b3e0215e4e99402945993026159f98b477047719f16a6530" +"checksum crossterm_winapi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02de3a35bcabb5bb6dc7d4449abb546d23f123b06f074e2cf1c50db516da6ac8" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" diff --git a/Cargo.toml b/Cargo.toml index 4cdcb16..d713964 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,6 @@ members = [ "examples", "first-depth-search", - "snake" + "snake", + "interactive-test" ] diff --git a/README.md b/README.md index d3d6469..73cae13 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ $ cargo run --bin alternate_screen ## License -This project is licensed under the MIT License - see the [LICENSE.md](./LICENSE) file for details. +This project is licensed under the MIT License - see the [LICENSE.md](LICENSE) file for details. [s2]: https://img.shields.io/badge/license-MIT-blue.svg -[l2]: ./LICENSE +[l2]: LICENSE [s5]: https://img.shields.io/discord/560857607196377088.svg?logo=discord [l5]: https://discord.gg/K4nyTDB diff --git a/examples/Cargo.toml b/examples/Cargo.toml index a610bfa..cca6ea9 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -12,4 +12,4 @@ readme = "README.md" edition = "2018" [dependencies] -crossterm = { git = "https://github.com/crossterm-rs/crossterm" } +crossterm = { path = "../../crossterm" } diff --git a/examples/src/bin/command_bar.rs b/examples/src/bin/command_bar.rs index df85488..fecc822 100644 --- a/examples/src/bin/command_bar.rs +++ b/examples/src/bin/command_bar.rs @@ -5,7 +5,7 @@ use std::{thread, time}; use crossterm::cursor::{Hide, Show}; use crossterm::{ cursor::MoveTo, - input::{input, InputEvent, KeyEvent}, + event::{input, InputEvent, KeyEvent}, screen::RawScreen, terminal::{self, Clear, ClearType}, ExecutableCommand, Output, Result, diff --git a/examples/src/bin/foo.rs b/examples/src/bin/foo.rs index e69de29..8b13789 100644 --- a/examples/src/bin/foo.rs +++ b/examples/src/bin/foo.rs @@ -0,0 +1 @@ + diff --git a/examples/src/bin/input.rs b/examples/src/bin/input.rs index b99b2c4..bc91c60 100644 --- a/examples/src/bin/input.rs +++ b/examples/src/bin/input.rs @@ -1,4 +1,4 @@ -use crossterm::input::input; +use crossterm::event::input; fn read_char() { let input = input(); diff --git a/examples/src/bin/key_events.rs b/examples/src/bin/key_events.rs index 4ba366d..4674f7b 100644 --- a/examples/src/bin/key_events.rs +++ b/examples/src/bin/key_events.rs @@ -3,7 +3,7 @@ use std::{thread, time::Duration}; use crossterm::{ - input::{input, InputEvent, KeyEvent, MouseButton, MouseEvent}, + event::{input, InputEvent, KeyEvent, MouseButton, MouseEvent}, screen::RawScreen, Result, }; diff --git a/examples/src/bin/stderr.rs b/examples/src/bin/stderr.rs index ba37835..8e35071 100644 --- a/examples/src/bin/stderr.rs +++ b/examples/src/bin/stderr.rs @@ -10,7 +10,7 @@ use std::io::{stderr, Write}; use crossterm::{ cursor::{Hide, MoveTo, Show}, - input::input, + event::input, queue, screen::{EnterAlternateScreen, LeaveAlternateScreen, RawScreen}, Output, Result, diff --git a/interactive-test/Cargo.toml b/interactive-test/Cargo.toml index c794c0c..1446bc3 100644 --- a/interactive-test/Cargo.toml +++ b/interactive-test/Cargo.toml @@ -1,19 +1,14 @@ [package] -name = "interactive-test" +name = "crossterm-interactive-test" version = "0.0.1" -authors = ["Robert Vojta "] +authors = ["T. Post", "Robert Vojta "] edition = "2018" -description = "Interactive test for the anes." -repository = "https://github.com/zrzka/anes-rs" -documentation = "https://docs.rs/anes/" -license = "MIT OR Apache-2.0" +description = "Interactive test for crossterm." +license = "MIT" exclude = ["target", "Cargo.lock"] readme = "README.md" publish = false -[badges] -maintenance = { status = "experimental" } - [dependencies] crossterm = {git="https://github.com/crossterm-rs/crossterm"} anes = "0.1.4" \ No newline at end of file From 66acafa203e1cafde579129fe759ff517cacffad Mon Sep 17 00:00:00 2001 From: Timon Post Date: Fri, 22 Nov 2019 08:56:19 +0100 Subject: [PATCH 3/5] input --- interactive-test/Cargo.toml | 2 +- interactive-test/src/macros.rs | 2 +- interactive-test/src/main.rs | 26 +++++++++++++---- interactive-test/src/test.rs | 2 +- interactive-test/src/test/attribute.rs | 15 ++++++---- interactive-test/src/test/color.rs | 33 ++++++++++++--------- interactive-test/src/test/cursor.rs | 31 +++++++++++++------- interactive-test/src/test/event.rs | 40 ++++++++++++++++++++++++++ interactive-test/src/test/input.rs | 1 - 9 files changed, 112 insertions(+), 40 deletions(-) create mode 100644 interactive-test/src/test/event.rs delete mode 100644 interactive-test/src/test/input.rs diff --git a/interactive-test/Cargo.toml b/interactive-test/Cargo.toml index 1446bc3..b7b4ccc 100644 --- a/interactive-test/Cargo.toml +++ b/interactive-test/Cargo.toml @@ -10,5 +10,5 @@ readme = "README.md" publish = false [dependencies] -crossterm = {git="https://github.com/crossterm-rs/crossterm"} +crossterm = { path="../../crossterm" } anes = "0.1.4" \ No newline at end of file diff --git a/interactive-test/src/macros.rs b/interactive-test/src/macros.rs index 973a2bc..02ce9e2 100644 --- a/interactive-test/src/macros.rs +++ b/interactive-test/src/macros.rs @@ -22,7 +22,7 @@ macro_rules! run_tests { match $crate::read_char() { Ok('q') => return Ok(()), Err(e) => return Err(e), - _ => {}, + _ => { }, }; )* } diff --git a/interactive-test/src/main.rs b/interactive-test/src/main.rs index 64b3e88..4da4d37 100644 --- a/interactive-test/src/main.rs +++ b/interactive-test/src/main.rs @@ -1,9 +1,15 @@ +#![allow(clippy::cognitive_complexity)] + use std::io::{self, Write}; +use crate::event::KeyEvent; +use crossterm::event::KeyCode; pub use crossterm::{ - cursor, execute, input, queue, screen, style, + cursor, + event::{self, Event}, + execute, queue, screen, style, terminal::{self, ClearType}, - Command, Output, Result, + Command, Result, }; #[macro_use] @@ -84,10 +90,10 @@ where terminal::Clear(ClearType::All), cursor::Hide, cursor::MoveTo(1, 1) - ); + )?; for line in MENU.split('\n') { - queue!(w, Output(line), MoveCursorToNextLine(1))?; + queue!(w, style::Print(line), MoveCursorToNextLine(1))?; } w.flush()?; @@ -96,7 +102,7 @@ where '1' => test::cursor::run(w)?, '2' => test::color::run(w)?, '3' => test::attribute::run(w)?, - '4' => unreachable!("input not implemented"), + '4' => test::event::run(w)?, 'q' => break, _ => {} }; @@ -112,7 +118,15 @@ where } pub fn read_char() -> Result { - input::input().read_char() + loop { + if let Ok(Event::Key(KeyEvent { + code: KeyCode::Char(c), + .. + })) = event::read() + { + return Ok(c); + } + } } pub fn buffer_size() -> Result<(u16, u16)> { diff --git a/interactive-test/src/test.rs b/interactive-test/src/test.rs index b4cac4e..89f1140 100644 --- a/interactive-test/src/test.rs +++ b/interactive-test/src/test.rs @@ -1,4 +1,4 @@ pub mod attribute; pub mod color; pub mod cursor; -mod input; +pub mod event; diff --git a/interactive-test/src/test/attribute.rs b/interactive-test/src/test/attribute.rs index f90b343..5cc8e49 100644 --- a/interactive-test/src/test/attribute.rs +++ b/interactive-test/src/test/attribute.rs @@ -1,5 +1,7 @@ +#![allow(clippy::cognitive_complexity)] + use crate::{MoveCursorToNextLine, Result}; -use crossterm::{queue, style, Output}; +use crossterm::{queue, style}; use std::io::Write; const ATTRIBUTES: [(style::Attribute, style::Attribute); 6] = [ @@ -18,15 +20,19 @@ fn test_set_display_attributes(w: &mut W) -> Result<()> where W: Write, { - queue!(w, Output("Display attributes"), MoveCursorToNextLine(2))?; + queue!( + w, + style::Print("Display attributes"), + MoveCursorToNextLine(2) + )?; for (on, off) in &ATTRIBUTES { queue!( w, style::SetAttribute(*on), - Output(format!("{:>width$} ", format!("{:?}", on), width = 35)), + style::Print(format!("{:>width$} ", format!("{:?}", on), width = 35)), style::SetAttribute(*off), - Output(format!("{:>width$}", format!("{:?}", off), width = 35)), + style::Print(format!("{:>width$}", format!("{:?}", off), width = 35)), style::ResetColor, MoveCursorToNextLine(1) )?; @@ -37,7 +43,6 @@ where Ok(()) } -#[allow(clippy::cognitive_complexity)] pub fn run(w: &mut W) -> Result<()> where W: Write, diff --git a/interactive-test/src/test/color.rs b/interactive-test/src/test/color.rs index de59a31..4052222 100644 --- a/interactive-test/src/test/color.rs +++ b/interactive-test/src/test/color.rs @@ -1,5 +1,7 @@ +#![allow(clippy::cognitive_complexity)] + use crate::{MoveCursorToNextLine, Result}; -use crossterm::{cursor, queue, style, style::Color, Output}; +use crossterm::{cursor, queue, style, style::Color}; use std::io::Write; const COLORS: [Color; 21] = [ @@ -32,7 +34,7 @@ where { queue!( w, - Output("Foreground colors on the black & white background"), + style::Print("Foreground colors on the black & white background"), MoveCursorToNextLine(2) )?; @@ -41,13 +43,13 @@ where w, style::SetForegroundColor(*color), style::SetBackgroundColor(Color::Black), - Output(format!( + style::Print(format!( "{:>width$} ", format!("{:?} ████████████", color), width = 40 )), style::SetBackgroundColor(Color::White), - Output(format!( + style::Print(format!( "{:>width$}", format!("{:?} ████████████", color), width = 40 @@ -67,7 +69,7 @@ where { queue!( w, - Output("Background colors with black & white foreground"), + style::Print("Background colors with black & white foreground"), MoveCursorToNextLine(2) )?; @@ -76,13 +78,13 @@ where w, style::SetBackgroundColor(*color), style::SetForegroundColor(Color::Black), - Output(format!( + style::Print(format!( "{:>width$} ", format!("{:?} ▒▒▒▒▒▒▒▒▒▒▒▒", color), width = 40 )), style::SetForegroundColor(Color::White), - Output(format!( + style::Print(format!( "{:>width$}", format!("{:?} ▒▒▒▒▒▒▒▒▒▒▒▒", color), width = 40 @@ -101,31 +103,35 @@ where W: Write, F: Fn(u16, u16) -> Color, { - queue!(w, Output(title))?; + queue!(w, style::Print(title))?; for idx in 0..=15 { queue!( w, cursor::MoveTo(1, idx + 4), - Output(format!("{:>width$}", idx, width = 2)) + style::Print(format!("{:>width$}", idx, width = 2)) )?; queue!( w, cursor::MoveTo(idx * 3 + 3, 3), - Output(format!("{:>width$}", idx, width = 3)) + style::Print(format!("{:>width$}", idx, width = 3)) )?; } for row in 0..=15u16 { queue!(w, cursor::MoveTo(4, row + 4))?; for col in 0..=15u16 { - queue!(w, style::SetForegroundColor(color(col, row)), Output("███"))?; + queue!( + w, + style::SetForegroundColor(color(col, row)), + style::Print("███") + )?; } queue!( w, style::SetForegroundColor(Color::White), - Output(format!("{:>width$} ..= ", row * 16, width = 3)), - Output(format!("{:>width$}", row * 16 + 15, width = 3)) + style::Print(format!("{:>width$} ..= ", row * 16, width = 3)), + style::Print(format!("{:>width$}", row * 16 + 15, width = 3)) )?; } @@ -176,7 +182,6 @@ where }) } -#[allow(clippy::cognitive_complexity)] pub fn run(w: &mut W) -> Result<()> where W: Write, diff --git a/interactive-test/src/test/cursor.rs b/interactive-test/src/test/cursor.rs index ca81470..7c44c6c 100644 --- a/interactive-test/src/test/cursor.rs +++ b/interactive-test/src/test/cursor.rs @@ -1,8 +1,10 @@ +#![allow(clippy::cognitive_complexity)] + use std::io::Write; use crate::{MoveCursorToColumn, MoveCursorToNextLine, MoveCursorToPreviousLine, Result}; use crossterm::cursor::MoveTo; -use crossterm::{cursor, execute, queue, style, style::Colorize, Command, Output}; +use crossterm::{cursor, execute, queue, style, style::Colorize, Command}; use std::thread; use std::time::Duration; @@ -65,28 +67,36 @@ fn test_hide_cursor(w: &mut W) -> Result<()> where W: Write, { - execute!(w, Output("HideCursor"), cursor::Hide) + execute!(w, style::Print("HideCursor"), cursor::Hide) } fn test_show_cursor(w: &mut W) -> Result<()> where W: Write, { - execute!(w, Output("ShowCursor"), cursor::Show) + execute!(w, style::Print("ShowCursor"), cursor::Show) } fn test_enable_cursor_blinking(w: &mut W) -> Result<()> where W: Write, { - execute!(w, Output("EnableCursorBlinking"), cursor::EnableBlinking) + execute!( + w, + style::Print("EnableCursorBlinking"), + cursor::EnableBlinking + ) } fn test_disable_cursor_blinking(w: &mut W) -> Result<()> where W: Write, { - execute!(w, Output("DisableCursorBlinking"), cursor::DisableBlinking) + execute!( + w, + style::Print("DisableCursorBlinking"), + cursor::DisableBlinking + ) } fn test_move_cursor_to(w: &mut W) -> Result<()> @@ -106,18 +116,18 @@ where { execute!(w, cursor::MoveTo(0, 0), - Output("Save position, print character else were, after three seconds restore to old position."), + style::Print("Save position, print character else were, after three seconds restore to old position."), MoveCursorToNextLine(2), - Output("Save ->[ ]<- Position"), + style::Print("Save ->[ ]<- Position"), cursor::MoveTo(8, 2), cursor::SavePosition, cursor::MoveTo(10,10), - Output("Move To ->[√]<- Position") + style::Print("Move To ->[√]<- Position") )?; thread::sleep(Duration::from_secs(3)); - execute!(w, cursor::RestorePosition, Output("√")) + execute!(w, cursor::RestorePosition, style::Print("√")) } /// Draws a box with an colored center, this center can be taken as a reference point after running the given cursor command. @@ -132,7 +142,7 @@ where cursor::Hide, cursor::MoveTo(0, 0), style::SetForegroundColor(style::Color::Red), - Output(format!( + style::Print(format!( "Red box is the center. After the action: '{}' another box is drawn.", description )) @@ -176,7 +186,6 @@ where Ok(()) } -#[allow(clippy::cognitive_complexity)] pub fn run(w: &mut W) -> Result<()> where W: Write, diff --git a/interactive-test/src/test/event.rs b/interactive-test/src/test/event.rs new file mode 100644 index 0000000..9cf7b71 --- /dev/null +++ b/interactive-test/src/test/event.rs @@ -0,0 +1,40 @@ +#![allow(clippy::cognitive_complexity)] + +use crossterm::{ + cursor::position, + event::{read, EnableMouseCapture, Event, KeyCode}, + execute, Result, +}; +use std::io::Write; + +fn test_event(w: &mut W) -> Result<()> +where + W: Write, +{ + execute!(w, EnableMouseCapture)?; + + loop { + // Blocking read + let event = read()?; + + println!("Event::{:?}\r", event); + + if event == Event::Key(KeyCode::Char('c').into()) { + println!("Cursor position: {:?}\r", position()); + } + + if event == Event::Key(KeyCode::Char('q').into()) { + break; + } + } + + Ok(()) +} + +pub fn run(w: &mut W) -> Result<()> +where + W: Write, +{ + run_tests!(w, test_event); + Ok(()) +} diff --git a/interactive-test/src/test/input.rs b/interactive-test/src/test/input.rs deleted file mode 100644 index 8b13789..0000000 --- a/interactive-test/src/test/input.rs +++ /dev/null @@ -1 +0,0 @@ - From a55aec2b25eebc7a9b2b39e9d608dc3afac6e43c Mon Sep 17 00:00:00 2001 From: Timon Post Date: Fri, 22 Nov 2019 09:00:11 +0100 Subject: [PATCH 4/5] added cargo comment --- interactive-test/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interactive-test/Cargo.toml b/interactive-test/Cargo.toml index b7b4ccc..e03e5a9 100644 --- a/interactive-test/Cargo.toml +++ b/interactive-test/Cargo.toml @@ -10,5 +10,5 @@ readme = "README.md" publish = false [dependencies] -crossterm = { path="../../crossterm" } -anes = "0.1.4" \ No newline at end of file +crossterm = { git = "https://github.com/crossterm-rs/crossterm" } +anes = "0.1.4" # needed till `MoveCursorToNextLine`, `MoveCursorToColumn`, `MoveCursorToPreviousLine` are implemented for crossterm. \ No newline at end of file From 4bcb45295053da7c00ee526513353c13be9aabc0 Mon Sep 17 00:00:00 2001 From: Timon Post Date: Fri, 22 Nov 2019 09:56:21 +0100 Subject: [PATCH 5/5] Updated toml --- Cargo.lock | 22 +--------------------- examples/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27ed7b6..03215f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,22 +27,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossterm" -version = "0.13.3" -dependencies = [ - "crossterm_winapi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossterm-examples" version = "0.0.1" dependencies = [ - "crossterm 0.13.3", + "crossterm 0.12.1 (git+https://github.com/crossterm-rs/crossterm)", ] [[package]] @@ -61,14 +50,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossterm_winapi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "first-depth-search" version = "0.0.1" @@ -259,7 +240,6 @@ dependencies = [ "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum crossterm 0.12.1 (git+https://github.com/crossterm-rs/crossterm)" = "" "checksum crossterm_winapi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df25e92a352488d9b3e0215e4e99402945993026159f98b477047719f16a6530" -"checksum crossterm_winapi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02de3a35bcabb5bb6dc7d4449abb546d23f123b06f074e2cf1c50db516da6ac8" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index cca6ea9..a610bfa 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -12,4 +12,4 @@ readme = "README.md" edition = "2018" [dependencies] -crossterm = { path = "../../crossterm" } +crossterm = { git = "https://github.com/crossterm-rs/crossterm" }