Tested all windows logic also fixed bug with resetting terminal color.

This commit is contained in:
TimonPost 2018-08-12 14:51:08 +02:00
parent 74ef83bb3f
commit 23dc4f661e
25 changed files with 391 additions and 610 deletions

View File

@ -28,8 +28,8 @@ path = "src/lib.rs"
# path = "./examples/Crossterm 0.3.1/bin.rs"
[[example]]
name = "simple"
path = "examples/simple.rs"
name = "examples"
path = "examples/examples.rs"
[[example]]
name = "logging"

10
changes.md Normal file
View File

@ -0,0 +1,10 @@
1. improved performance: removed mutexes, removed state manager, removed unceasingly RC types.
2. This create supports multithreading by implementing `Send`
2. nicer looking coloring module.
4. Added input functionality.
4. Able to have different screens to write to.
2. cursor, color, terminal functions have other parameters.
3. bug fix resetting console color
6. Added Screen type
8. removed paint from Crossterm type.

View File

@ -7,5 +7,3 @@ It has 4 modules:
- input (this is about all input actions you can perform on with terminal)
- crossterm_type (this is about the struct `Crossterm`)
- program examples (this folder will contain some real life examples)
To run any example where there is a `main()` you could run `cargo run --example simple`.

View File

@ -1,206 +1,130 @@
//!
//! Examples of coloring the terminal.
//!
extern crate crossterm;
use self::crossterm::style::Color;
use self::crossterm::terminal;
use self::crossterm::Context;
use self::crossterm::style::{Color, style, color};
use self::crossterm::{terminal, Screen};
/// print some red font | demonstration.
pub fn paint_foreground() {
let context = Context::new();
let terminal = terminal::terminal(&context);
let screen = Screen::default();
// Pass an string to the `paint()` method with you want to paint.
// This will give you an object back wits can be styled and displayed.
let mut styledobject = terminal.paint("Red font");
// Call the method `with()` on the object given by `paint()` and pass in any Color from the Color enum.
styledobject = styledobject.with(Color::Red);
// Print the object to the console and see the result.
println!("{}", styledobject);
// Call the method `with()` on the object given by `style()` and pass in any Color from the Color enum.
let mut styledobject = style("Red foreground").with(Color::Red);
// Crossterm provides method chaining so that the above points can be inlined.
println!("{}", terminal.paint("Red font").with(Color::Red));
// Print the object to the given screen and.
styledobject.paint(&screen);
style("Some colored text").with(Color::Blue).on(Color::Black).paint(&screen);
// Crossterm provides method chaining for coloring so that the above points can be inlined.
style(format!("Red foreground color : \t {}", "")).with(Color::Red).paint(&screen);
}
/// print some font on red background | demonstration.
pub fn paint_background() {
let context = Context::new();
let terminal = terminal::terminal(&context);
let screen = Screen::default();
// Pass an string to the `paint()` method with you want to paint.
// This will give you an object back wits can be styled and displayed.
let mut styledobject = terminal.paint("Red background color");
// Call the method `on()` on the object given by `paint()` and pass in an Color from the Color enum.
styledobject = styledobject.on(Color::Red);
// Print the object to the console and check see the result
println!("{}", styledobject);
// Call the method `on()` on the object given by `style()` and pass in any Color from the Color enum.
let mut styledobject = style("Red background color").on(Color::Red);
// Crossterm provides method chaining so that the above points can be inlined.
println!("{}", terminal.paint("Red background color").on(Color::Red));
}
// Print the object to the given screen and.
styledobject.paint(&screen);
/// print font with fore- background color | demonstration.
pub fn paint_foreground_and_background() {
let context = Context::new();
let terminal = terminal::terminal(&context);
// Pass an string to the `paint()` method with you want to paint.
// This will give you an object back wits can be styled and displayed.
let mut styledobject = terminal.paint("Red font on blue background color");
/* Foreground color:
Call the method `with()` on the object given by `paint()`
Pass in an Color from the Color enum.
*/
styledobject = styledobject.with(Color::Red);
/* Background color:
Call the method `on()` on the object given by `paint()`
Pass in an Color from the Color enum.
*/
styledobject = styledobject.on(Color::Blue);
// Print the object to the console and see the result.
println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined.
println!(
"{}",
terminal
.paint("Red font on blue background color")
.with(Color::Red)
.on(Color::Blue)
);
// Crossterm provides method chaining for coloring so that the above points can be inlined.
style(format!("Red background color : \t {}", "")).with(Color::Red).paint(&screen);
}
/// Print all available foreground colors | demonstration.
pub fn print_all_foreground_colors() {
let context = Context::new();
let terminal = terminal::terminal(&context);
let screen = Screen::default();
println!("Black : \t {}", terminal.paint("").with(Color::Black));
println!("Red : \t\t {}", terminal.paint("").with(Color::Red));
println!(
"Dark Red: \t {}",
terminal.paint("").with(Color::DarkRed)
);
println!("Green : \t {}", terminal.paint("").with(Color::Green));
println!(
"Dark Green : \t {}",
terminal.paint("").with(Color::DarkGreen)
);
println!("Yellow : \t {}", terminal.paint("").with(Color::Yellow));
println!(
"Dark Yellow : \t {}",
terminal.paint("").with(Color::DarkYellow)
);
println!("Blue : \t\t {}", terminal.paint("").with(Color::Blue));
println!(
"Dark Blue : \t {}",
terminal.paint("").with(Color::DarkBlue)
);
println!(
"Magenta : \t {}",
terminal.paint("").with(Color::Magenta)
);
println!(
"Dark Magenta : \t {}",
terminal.paint("").with(Color::DarkMagenta)
);
println!("Cyan : \t\t {}", terminal.paint("").with(Color::Cyan));
println!(
"Dark Cyan : \t {}",
terminal.paint("").with(Color::DarkCyan)
);
println!("Grey : \t\t {}", terminal.paint("").with(Color::Grey));
println!("White : \t {}", terminal.paint("").with(Color::White));
style(format!("Black : \t\t {} \n", "")).with(Color::Black).paint(&screen);
style(format!("Red : \t\t {} \n", "")).with(Color::Red).paint(&screen);
style(format!("Cyan : \t\t {} \n", "")).with(Color::Cyan).paint(&screen);
style(format!("DarkCyan : \t {} \n", "")).with(Color::DarkCyan).paint(&screen);
style(format!("DarkRed : \t {} \n", "")).with(Color::DarkRed).paint(&screen);
style(format!("Green : \t {} \n", "")).with(Color::Green).paint(&screen);
style(format!("DarkGreen : \t {} \n", "")).with(Color::DarkGreen).paint(&screen);
style(format!("Blue : \t\t {} \n", "")).with(Color::Blue).paint(&screen);
style(format!("DarkBlue : \t {} \n", "")).with(Color::DarkBlue).paint(&screen);
style(format!("Magenta : \t {} \n", "")).with(Color::Magenta).paint(&screen);
style(format!("DarkMagenta : \t {} \n", "")).with(Color::DarkMagenta).paint(&screen);
style(format!("Yellow : \t {} \n", "")).with(Color::Yellow).paint(&screen);
style(format!("DarkYellow : \t {} \n", "")).with(Color::DarkYellow).paint(&screen);
style(format!("Grey : \t\t {} \n", "")).with(Color::Grey).paint(&screen);
style(format!("White : \t {} \n", "")).with(Color::White).paint(&screen);
#[cfg(unix)]
style("RGB color (10,10,10) ").with(Color::Rgb {
r: 10,
g: 10,
b: 10
}).paint(&screen);
#[cfg(unix)]
style("RGB color (10,10,10) ").with(Color::AnsiValue(50)).paint(&screen);
}
/// Print all available foreground colors | demonstration.
pub fn print_all_background_colors() {
let context = Context::new();
let terminal = terminal::terminal(&context);
let screen = Screen::default();
style(format!("Black : \t {} \n", "")).on(Color::Black).paint(&screen);
style(format!("Red : \t\t {} \n", "")).on(Color::Red).paint(&screen);
style(format!("Cyan : \t\t {} \n", "")).on(Color::Cyan).paint(&screen);
style(format!("DarkCyan : \t {} \n", "")).on(Color::DarkCyan).paint(&screen);
style(format!("DarkRed : \t {} \n", "")).on(Color::DarkRed).paint(&screen);
style(format!("Green : \t {} \n", "")).on(Color::Green).paint(&screen);
style(format!("DarkGreen : \t {} \n", "")).on(Color::DarkGreen).paint(&screen);
style(format!("Blue : \t\t {} \n", "")).on(Color::Blue).paint(&screen);
style(format!("DarkBlue : \t {} \n", "")).on(Color::DarkBlue).paint(&screen);
style(format!("Magenta : \t {} \n", "")).on(Color::Magenta).paint(&screen);
style(format!("DarkMagenta : \t {} \n", "")).on(Color::DarkMagenta).paint(&screen);
style(format!("Yellow : \t {} \n", "")).on(Color::Yellow).paint(&screen);
style(format!("DarkYellow : \t {} \n", "")).on(Color::DarkYellow).paint(&screen);
style(format!("Grey : \t\t {} \n", "")).on(Color::Grey).paint(&screen);
style(format!("White : \t {} \n", "")).on(Color::White).paint(&screen);
println!("Black : \t {}", terminal.paint(" ").on(Color::Black));
println!("Red : \t\t {}", terminal.paint(" ").on(Color::Red));
println!("Dark Red: \t {}", terminal.paint(" ").on(Color::DarkRed));
println!("Green : \t {}", terminal.paint(" ").on(Color::Green));
println!(
"Dark Green : \t {}",
terminal.paint(" ").on(Color::DarkGreen)
);
println!("Yellow : \t {}", terminal.paint(" ").on(Color::Yellow));
println!(
"Dark Yellow : \t {}",
terminal.paint(" ").on(Color::DarkYellow)
);
println!("Blue : \t\t {}", terminal.paint(" ").on(Color::Blue));
println!(
"Dark Blue : \t {}",
terminal.paint(" ").on(Color::DarkBlue)
);
println!("Magenta : \t {}", terminal.paint(" ").on(Color::Magenta));
println!(
"Dark Magenta : \t {}",
terminal.paint(" ").on(Color::DarkMagenta)
);
println!("Cyan : \t\t {}", terminal.paint(" ").on(Color::Cyan));
println!(
"Dark Cyan : \t {}",
terminal.paint(" ").on(Color::DarkCyan)
);
println!("Grey : \t\t {}", terminal.paint(" ").on(Color::Grey));
println!("White : \t {}", terminal.paint(" ").on(Color::White));
#[cfg(unix)]
println!(
"RGB (10,10,10): \t {}",
terminal.paint(" ").on(Color::Rgb {
style("RGB color (10,10,10) ").on(Color::Rgb {
r: 10,
g: 10,
b: 10
})
);
}).paint(&screen);
#[cfg(unix)]
println!(
"RGB (10,10,10): \t {}",
terminal.paint(" ").on(Color::AnsiValue(50))
);
style("RGB color (10,10,10) ").on(Color::AnsiValue(50)).paint(&screen);
}
/// Print font with all available attributes. Note that this can only be used at unix systems and that some are not supported widely | demonstration..
#[cfg(unix)]
pub fn print_font_with_attributes() {
let context = Context::new();
let terminal = terminal::terminal(&context);
println!("{}", terminal.paint("Normal text"));
println!("{}", terminal.paint("Bold text").bold());
println!("{}", terminal.paint("Italic text").italic());
println!("{}", terminal.paint("Slow blinking text").slow_blink());
println!("{}", terminal.paint("Rapid blinking text").rapid_blink());
println!("{}", terminal.paint("Hidden text").hidden());
println!("{}", terminal.paint("Underlined text").underlined());
println!("{}", terminal.paint("Reversed color").reverse());
println!("{}", terminal.paint("Dim text color").dim());
println!("{}", terminal.paint("Crossed out font").crossed_out());
let screen = Screen::default();
style("Normal text").paint(&screen);
style("Bold text").bold().paint(&screen);
style("Italic text").italic().paint(&screen);
style("Slow blinking text").slow().paint(&screen);
style("Rapid blinking text").rapid().paint(&screen);
style("Hidden text").hidden().paint(&screen);
style("Underlined text").underlined().paint(&screen);
style("Reversed text").reverse().paint(&screen);
style("Dim text").dim().paint(&screen);
style("Crossed out font").crossed_out().paint(&screen);
}
/// Print all supported rgb colors | demonstration.
/// Print all supported RGB colors | demonstration.
#[cfg(unix)]
pub fn print_supported_colors() {
let context = Context::new();
let terminal = terminal::terminal(&context);
let count = crossterm::style::color(&context)
let screen = Screen::default();
let count = color(&screen)
.get_available_color_count()
.unwrap();
for i in 0..count {
println!(
"{}",
terminal
.paint(format!("Color: {}", i))
.with(Color::AnsiValue(i as u8))
);
style(format!("White : \t {}", i)).on(Color::AnsiValue(i as u8)).paint(&screen);
}
}

View File

@ -1,67 +0,0 @@
extern crate crossterm;
use crossterm::Crossterm;
/// use the `Crossterm` to get an instance to the cursor module | demonstration.
pub fn use_crossterm_cursor()
{
let crossterm = Crossterm::new();
let mut cursor = crossterm.cursor();
cursor.goto(5,5).print("test");
}
use crossterm::style::Color;
/// use the `Crossterm` to get an instance to the color module | demonstration.
pub fn use_crossterm_color()
{
let crossterm = Crossterm::new();
let mut color = crossterm.color();
color.set_bg(Color::Red);
color.set_fg(Color::Green);
}
use crossterm::terminal::ClearType;
/// use the `Crossterm` to get an instance to the terminal module | demonstration.
pub fn use_crossterm_terminal()
{
let crossterm = Crossterm::new();
let mut terminal = crossterm.terminal();
terminal.clear(ClearType::All);
terminal.set_size(40,40);
}
/// paint text with colors using `Crossterm` | demonstration.
pub fn use_crossterm_paint()
{
let crossterm = Crossterm::new();
crossterm.paint("Black on BLUE").with(Color::Black).on(Color::Blue);
}
/// write text to terminal using `Crossterm` | demonstration.
pub fn use_crossterm_write()
{
let crossterm = Crossterm::new();
crossterm.write("some text \nsome text on new line");
}
/// Switch to alternate screen using the `Context` of `Crossterm` | demonstration.
pub fn create_alternate_screen_from_crossterm()
{
use crossterm::screen::*;
use std::convert::From;
let crossterm = Crossterm::new();
{
// move into alternate screen
let alternate_screen = AlternateScreen::from(crossterm.context());
// this will move the cursor and print `some text` on the alternate screen.
crossterm.cursor().goto(10, 10).print("Some text");
} // <- alternate screen ends here an will be switched back to main screen.
// print "Some other text" on the mainscreen at x: 0, y: 10
crossterm.cursor().goto(0,10).print("Some other text");
}

View File

@ -4,34 +4,28 @@
extern crate crossterm;
use self::crossterm::cursor::{cursor, TerminalCursor};
use self::crossterm::Context;
use self::crossterm::Screen;
/// Set the cursor to position X: 10, Y: 5 in the terminal.
pub fn goto() {
let context = Context::new();
// Get the cursor
let mut cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
// Set the cursor to position X: 10, Y: 5 in the terminal
cursor.goto(10, 5);
}
/// get the cursor position
pub fn pos() {
let context = Context::new();
// Get the cursor
let mut cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
// get the cursor position.
let (x, y) = cursor.pos();
}
/// Move the cursor 3 up | demonstration.
pub fn move_up() {
let context = Context::new();
// Get the cursor
let mut cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
// Move the cursor to position 3 times to the up in the terminal
cursor.move_up(10);
@ -39,66 +33,55 @@ pub fn move_up() {
/// Move the cursor 3 to the right | demonstration.
pub fn move_right() {
let context = Context::new();
// Get the cursor
let mut cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
// Move the cursor to position 3 times to the right in the terminal
cursor.move_right(3);
}
/// Move the cursor 3 down | demonstration.
pub fn move_down() {
let context = Context::new();
// Get the cursor
let mut cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
// Move the cursor to position 3 times to the down in the terminal
cursor.move_down(3);
}
/// Move the cursor 3 to the left | demonstration.
pub fn move_left() {
let context = Context::new();
let mut cursor = cursor(&Screen::default());
// Get the cursor
let mut cursor = cursor(&context);
// Move the cursor to position 3 times to the left in the terminal
cursor.move_left(3);
}
/// Print character at X: 10 Y: 5 | demonstration.
pub fn print() {
let context = Context::new();
// To print an some displayable content on an certain position.
// Get the cursor
let mut cursor = cursor(&context);
// Set the cursor to position X: 10, Y: 5 in the terminal
cursor.goto(10, 5);
// Print the @ symbol at position X: 10, Y: 5 in the terminal
print!("@");
// Rust is line buffered inorder to print at an certain position we need to clear the buffer first.
use std;
use std::io::Write;
std::io::stdout().flush();
/* Because the above method is a little to much code,
you can use the `print()` method for printing an value at an certain position in the terminal.
Crossterm provides method chaining so that the above points can be inlined.
*/
cursor.goto(10, 5).print("@");
}
///// Print character at X: 10 Y: 5 | demonstration.
//pub fn print() {
// let context = Context::new();
//
// // To print an some displayable content on an certain position.
//
// // Get the cursor
// let mut cursor = cursor(&context);
// // Set the cursor to position X: 10, Y: 5 in the terminal
// cursor.goto(10, 5);
// // Print the @ symbol at position X: 10, Y: 5 in the terminal
// print!("@");
// // Rust is line buffered inorder to print at an certain position we need to clear the buffer first.
// use std;
// use std::io::Write;
// std::io::stdout().flush();
//
// /* Because the above method is a little to much code,
// you can use the `print()` method for printing an value at an certain position in the terminal.
//
// Crossterm provides method chaining so that the above points can be inlined.
// */
//
// cursor.goto(10, 5).print("@");
//}
/// Save and reset cursor position | demonstration..
pub fn safe_and_reset_position() {
let context = Context::new();
let mut cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
// Goto X: 5 Y: 5
cursor.goto(5, 5);
// Safe cursor position: X: 5 Y: 5
@ -117,25 +100,19 @@ pub fn safe_and_reset_position() {
/// Hide cursor display | demonstration.
pub fn hide_cursor() {
let context = Context::new();
let cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
cursor.hide();
}
/// Show cursor display | demonstration.
pub fn show_cursor() {
let context = Context::new();
let cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
cursor.show();
}
/// Show cursor display, only works on certain terminals.| demonstration
pub fn blink_cursor() {
let context = Context::new();
let cursor = cursor(&context);
let mut cursor = cursor(&Screen::default());
cursor.blink(false);
cursor.blink(false);
}

20
examples/examples.rs Normal file
View File

@ -0,0 +1,20 @@
//! This bin folder can be used to try the examples out located in the examples directory.
//!
//! All you need to do is:
//!
//! - Download the crossterm source code.
//! - Run program with: `cargo run --example examples`
extern crate crossterm;
// modules that could be test
mod terminal;
mod color;
mod cursor;
mod some_types;
mod input;
fn main() {
// call some test module function
}

View File

@ -10,16 +10,14 @@ use std::time::Duration;
/// this will capture the input until the given key.
pub fn read_async_until() {
let screen = Screen::new();
// create raw screen
let screen = Screen::new(true);
let crossterm = Crossterm::new();
if let Ok(raw) = screen.enable_raw_modes()
{
// init some modules we use for this demo
let input = crossterm.input(&raw.screen);
let terminal = crossterm.terminal(&raw.screen);
let mut cursor = crossterm.cursor(&raw.screen);
let input = crossterm.input(&screen);
let terminal = crossterm.terminal(&screen);
let mut cursor = crossterm.cursor(&screen);
let mut stdin = input.read_until_async(b'\r').bytes();
@ -42,12 +40,11 @@ pub fn read_async_until() {
thread::sleep(time::Duration::from_millis(100));
}
}
}
/// this will read pressed characters async until `x` is typed .
pub fn read_async() {
let input = input(&Screen::new());
let input = input(&Screen::default());
let mut stdin = input.read_async().bytes();
@ -66,16 +63,13 @@ pub fn read_async() {
}
pub fn read_async_demo() {
let screen = Screen::new();
let screen = Screen::new(true);
let crossterm = Crossterm::new();
// put stdout in raw mode so that characters wil not be outputted.
let raw = screen.enable_raw_modes().unwrap();
// init some modules we use for this demo
let input = crossterm.input(&raw.screen);
let terminal = crossterm.terminal(&raw.screen);
let mut cursor = crossterm.cursor(&raw.screen);
let input = crossterm.input(&screen);
let terminal = crossterm.terminal(&screen);
let mut cursor = crossterm.cursor(&screen);
// this will setup the async reading.
let mut stdin = input.read_async().bytes();
@ -106,19 +100,16 @@ pub fn read_async_demo() {
pub fn async_reading_on_alternate_screen() {
use crossterm::screen::AlternateScreen;
let screen = Screen::new();
let screen = Screen::new(false);
let crossterm = Crossterm::new();
// switch to alternate screen
if let Ok(alternate) = screen.enable_alternate_modes()
{
// put alternate screen in raw mode so that characters wil not be outputted.
if let Ok(raw) = alternate.enable_raw_modes()
if let Ok(alternate) = screen.enable_alternate_modes(true)
{
// init some modules we use for this demo
let input = crossterm.input(&raw.screen);
let terminal = crossterm.terminal(&raw.screen);
let mut cursor = crossterm.cursor(&raw.screen);
let input = crossterm.input(&alternate.screen);
let terminal = crossterm.terminal(&alternate.screen);
let mut cursor = crossterm.cursor(&alternate.screen);
// this will setup the async reading.
let mut stdin = input.read_async().bytes();
@ -142,5 +133,4 @@ pub fn async_reading_on_alternate_screen() {
thread::sleep(Duration::from_millis(200));
}
}
}
}

View File

@ -4,7 +4,7 @@ use self::crossterm::input::input;
use self::crossterm::Screen;
pub fn read_char() {
let input = input(&Screen::new());
let input = input(&Screen::default());
match input.read_char() {
Ok(s) => println!("char typed: {}", s),
@ -13,7 +13,7 @@ pub fn read_char() {
}
pub fn read_line() {
let input = input(&Screen::new());
let input = input(&Screen::default());
match input.read_line() {
Ok(s) => println!("string typed: {}", s),

View File

@ -7,3 +7,4 @@ The programs are:
- First depth search:
This is an search algorithm implemented visually. This program uses the following functionalities: cursor movement, coloring, alternate screen and terminal clearing.
- Duplex: This is a terminal application where there is some kind of conterminous output and with async input. So you could type an command while text is being outputted.
- This is an async logging program to demonstrate asynchronous working with crossterm.

View File

@ -26,10 +26,10 @@ fn main()
pub fn run()
{
// This is represents the current screen.
let screen = Screen::new();
let screen = Screen::new(true);
// set size of terminal so the map we are going to draw is fitting the screen.
terminal(&screen).set_size(110,50);
terminal(&screen).set_size(60,110);
print_welcome_screen(&screen);
@ -39,7 +39,7 @@ pub fn run()
fn start_algorithm(screen: &Screen)
{
// we first want to switch to alternate screen. On the alternate screen we are going to run or firstdepthsearch algorithm
if let Ok(ref alternate_screen) = screen.enable_alternate_modes()
if let Ok(ref alternate_screen) = screen.enable_alternate_modes(true)
{
// setup the map size and the position to start searching for a path.
let map_size = Size::new(100, 40);
@ -58,12 +58,10 @@ fn start_algorithm(screen: &Screen)
fn print_welcome_screen(screen: &Screen)
{
// create the handle for the cursor and terminal.
if let Ok(raw) = screen.enable_raw_modes()
{
let crossterm = Crossterm::new();
let terminal = crossterm.terminal(&screen);
let cursor = crossterm.cursor(&raw.screen);
let input = crossterm.input(&raw.screen);
let cursor = crossterm.cursor(&screen);
let input = crossterm.input(&screen);
// clear the screen and print the welcome message.
terminal.clear(ClearType::All);
@ -94,5 +92,4 @@ fn print_welcome_screen(screen: &Screen)
// 1 second delay
thread::sleep(time::Duration::from_secs(1));
}
}
}

View File

@ -1,35 +0,0 @@
//! This bin folder can be used to try the examples out located in the examples directory.
//!
//! All you need to do is:
//!
//! - Download the crossterm source code.
//!
//! - Add this in the Cargo.toml file:
//! ``` [[bin]]
//! name = "example_bin"
//! path = "./examples/bin.rs"
//! ```
//!
//! - Run program with: `cargo run`
extern crate crossterm;
use crossterm::style::Color;
use crossterm::Crossterm;
use crossterm::write::Stdout;
use crossterm::common::screen::Screen;
use std::io::Write;
// mod terminal;
// mod color;
// mod cursor;
// mod crossterm_type;
mod input;
//use input::keyboard::{async_input, input as stdin};
use std::{thread, time, };
use std::sync::mpsc;
fn main() {
input::keyboard::async_input::async_reading_on_alternate_screen();
}

View File

@ -0,0 +1,20 @@
extern crate crossterm;
use crossterm::{Crossterm, Screen};
#[test]
/// use the `Crossterm` to get an instance to the cursor module | demonstration.
pub fn use_crossterm_cursor()
{
let screen = Screen::new();
// Create the crossterm type to access different modules.
let crossterm = Crossterm::new();
// pass a reference to the current screen.
let cursor = crossterm.cursor(&screen);
let color = crossterm.color(&screen);
let terminal = crossterm.terminal(&screen);
// perform some actions with the instances above.
}

View File

@ -1,18 +1,18 @@
extern crate crossterm;
use crossterm::style::Color;
use crossterm::style::{Color, style};
use crossterm::terminal::{self, ClearType};
use crossterm::Crossterm;
use crossterm::{Crossterm, Screen};
use std::io::{stdout, Write};
use std::{thread, time};
fn print_wait_screen(crossterm: &mut Crossterm) {
let mut terminal = crossterm.terminal();
let mut cursor = crossterm.cursor();
fn print_wait_screen(screen: &Screen) {
let crossterm = Crossterm::new();
let terminal = crossterm.terminal(&screen);
let cursor = crossterm.cursor(&screen);
terminal.clear(ClearType::All);
cursor.goto(0, 0);
cursor.hide();
@ -25,49 +25,21 @@ fn print_wait_screen(crossterm: &mut Crossterm) {
// print some progress example.
for i in 1..5 {
// print the current counter at the line of `Seconds to Go: {counter}`
cursor
.goto(10, 2)
.print(crossterm.paint(format!("{} of the 5 items processed", i)).with(Color::Red).on(Color::Blue));
cursor.goto(10, 2);
style(format!("{} of the 5 items processed", i)).with(Color::Red).on(Color::Blue).paint(&screen);
// 1 second delay
thread::sleep(time::Duration::from_secs(1));
}
stdout().flush();
}
/// print wait screen on alternate screen, then swich back.
pub fn print_wait_screen_on_alternate_window() {
let mut term = Crossterm::new();
term.to_alternate_screen();
term.write(b"test");
print_wait_screen(&mut term);
}
/// some stress test switch from and to alternate screen.
pub fn switch_between_main_and_alternate_screen() {
let screen = Screen::default();
if let Ok(alternate) = screen.enable_alternate_modes(false)
{
let mut term = Crossterm::new();
let mut cursor = term.cursor();
// create new alternate screen instance and switch to the alternate screen.
let alternate = term.to_alternate_screen();
{ cursor.goto(0, 0); }
write!(term, "we are at the alternate screen!");
thread::sleep(time::Duration::from_secs(3));
term.to_main_screen();
write!(term, "we are at the alternate screen!");
thread::sleep(time::Duration::from_secs(3));
term.to_alternate_screen();
write!(term, "we are at the alternate screen!");
thread::sleep(time::Duration::from_secs(3));
} // <- Crossterm goes out of scope.
println!("Whe are back at the main screen");
print_wait_screen(&alternate.screen);
}
}

View File

@ -1,31 +1,33 @@
extern crate crossterm;
use crossterm::Crossterm;
use crossterm::{Crossterm, Screen};
use crossterm::terminal::{self, ClearType};
use crossterm::style::{style, Color};
use std::io::{stdout, Write};
use std::{thread, time};
// raw screen is not working correctly currently
fn print_wait_screen(crossterm: &mut Crossterm) {
let terminal = crossterm.terminal();
let mut cursor = crossterm.cursor();
fn print_wait_screen(screen: &Screen) {
let crossterm = Crossterm::new();
let terminal = crossterm.terminal(&screen);
let cursor = crossterm.cursor(&screen);
terminal.clear(ClearType::All);
cursor.goto(0, 0);
cursor.hide();
cursor.goto(0, 0).print("Welcome to the wait screen.");
cursor
.goto(0, 1)
.print("Please wait a few seconds until we arrive back at the main screen.");
cursor.goto(0, 2).print("Progress: ");
terminal.write(
"Welcome to the wait screen.\n\
Please wait a few seconds until we arrive back at the main screen.\n\
Progress: ",
);
// print some progress example.
for i in 1..5 {
// print the current counter at the line of `Seconds to Go: {counter}`
cursor
.goto(10, 2)
.print(format!("{} of the 5 items processed", i));
cursor.goto(10, 2);
style(format!("{} of the 5 items processed", i)).with(Color::Red).on(Color::Blue).paint(&screen);
screen.stdout.flush();
// 1 second delay
thread::sleep(time::Duration::from_secs(1));
@ -33,21 +35,11 @@ fn print_wait_screen(crossterm: &mut Crossterm) {
}
pub fn print_wait_screen_on_alternate_window() {
let mut term = Crossterm::new();
let screen = Screen::default();
// create scope. If this scope ends the screen will be switched back to mainscreen.
// because `AlternateScreen` switches back to main screen when going out of scope.
if let Ok(alternate) = screen.enable_alternate_modes(true)
{
// create new alternate screen instance this call is also switching the screen to alternate screen.
// then convert the output of the program to raw mode.
// then print the wait screen on the alternate screen in raw mode.
term.to_alternate_screen();
term.enable_raw_mode();
// Print the wait screen.
print_wait_screen(&mut term);
term.flush();
print_wait_screen(&alternate.screen);
}
println!("Whe are back at the main screen");

View File

@ -4,8 +4,8 @@
extern crate crossterm;
use crossterm::terminal::ClearType;
use crossterm::Crossterm;
use crossterm::terminal::{ClearType, terminal};
use crossterm::{Crossterm, Screen};
fn print_test_data() {
for i in 0..100 {
@ -15,8 +15,7 @@ fn print_test_data() {
/// Clear all lines in terminal | demonstration
pub fn clear_all_lines() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
print_test_data();
@ -26,13 +25,14 @@ pub fn clear_all_lines() {
/// Clear all lines from cursor position X:4, Y:4 down | demonstration
pub fn clear_from_cursor_down() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let screen = Screen::default();
let crossterm = Crossterm::new();
let mut terminal = crossterm.terminal(&screen);
print_test_data();
// Set terminal cursor position (see example for more info).
term.cursor().goto(4, 8);
crossterm.cursor(&screen).goto(4, 8);
// Clear all cells from current cursor position down.
terminal.clear(ClearType::FromCursorDown);
@ -40,13 +40,14 @@ pub fn clear_from_cursor_down() {
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
pub fn clear_from_cursor_up() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let screen = Screen::default();
let crossterm = Crossterm::new();
let mut terminal = crossterm.terminal(&screen);
print_test_data();
// Set terminal cursor position (see example for more info).
term.cursor().goto(4, 4);
crossterm.cursor(&screen).goto(4, 4);
// Clear all cells from current cursor position down.
terminal.clear(ClearType::FromCursorUp);
@ -54,13 +55,14 @@ pub fn clear_from_cursor_up() {
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
pub fn clear_current_line() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let screen = Screen::default();
let crossterm = Crossterm::new();
let mut terminal = crossterm.terminal(&screen);
print_test_data();
// Set terminal cursor position (see example for more info).
term.cursor().goto(4, 4);
crossterm.cursor(&screen).goto(4, 4);
// Clear current line cells.
terminal.clear(ClearType::CurrentLine);
@ -68,13 +70,14 @@ pub fn clear_current_line() {
/// Clear all lines from cursor position X:4, Y:7 up | demonstration
pub fn clear_until_new_line() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let screen = Screen::default();
let crossterm = Crossterm::new();
let mut terminal = crossterm.terminal(&screen);
print_test_data();
// Set terminal cursor position (see example for more info).
term.cursor().goto(4, 20);
crossterm.cursor(&screen).goto(4, 20);
// Clear all the cells until next line.
terminal.clear(ClearType::UntilNewLine);
@ -82,8 +85,7 @@ pub fn clear_until_new_line() {
/// Print the the current terminal size | demonstration.
pub fn print_terminal_size() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
// Get terminal size
let (width, height) = terminal.terminal_size();
@ -94,16 +96,14 @@ pub fn print_terminal_size() {
/// Set the terminal size to width 10, height: 10 | demonstration.
pub fn set_terminal_size() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
terminal.set_size(10, 10);
}
/// Scroll down 10 lines | demonstration.
pub fn scroll_down() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
print_test_data();
@ -113,8 +113,7 @@ pub fn scroll_down() {
/// Scroll down 10 lines | demonstration.
pub fn scroll_up() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
print_test_data();
@ -124,8 +123,7 @@ pub fn scroll_up() {
/// Resize the terminal to X: 10, Y: 10 | demonstration.
pub fn resize_terminal() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
// Get terminal size
terminal.set_size(10, 10);
@ -133,7 +131,6 @@ pub fn resize_terminal() {
/// exit the current proccess.
pub fn exit() {
let term = Crossterm::new();
let mut terminal = term.terminal();
let mut terminal = terminal(&Screen::default());
terminal.exit();
}

View File

@ -54,7 +54,8 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
// Try to enable ansi on windows if not than use WINAPI.
does_support = try_enable_ansi_support();
// does_support = false;
// uncomment this line when you want to use the winapi implementation.
does_support = false;
if !does_support {
term = Some(winapi_impl);
}

View File

@ -61,11 +61,6 @@ impl AlternateScreen {
self.command.disable(&self.screen.stdout)?;
Ok(())
}
pub fn enable_raw_modes(&self) -> io::Result<RawScreen>
{
return self.screen.enable_raw_modes();
}
}
impl Drop for AlternateScreen

View File

@ -13,48 +13,34 @@
//! With these modes you can easier design the terminal screen.
use super::commands::*;
use super::{functions, Screen};
use super::{functions, Screen, Stdout};
use std::io::{self, Write};
/// A wrapper for the raw terminal state. Which can be used to write to.
pub struct RawScreen
{
#[cfg(not(target_os = "windows"))]
command: unix_command::RawModeCommand,
#[cfg(target_os = "windows")]
command: win_commands::RawModeCommand,
pub screen: Screen,
}
pub struct RawScreen;
impl RawScreen {
pub fn into_raw_mode(screen: Screen) -> io::Result<RawScreen>
pub fn into_raw_mode() -> io::Result<()>
{
#[cfg(not(target_os = "windows"))]
let command = unix_command::RawModeCommand::new();
let mut command = unix_command::RawModeCommand::new();
#[cfg(target_os = "windows")]
let command = win_commands::RawModeCommand::new();
let mut command = win_commands::RawModeCommand::new();
Ok(RawScreen { command: command, screen})
command.enable()?;
Ok(())
}
pub fn disable_raw_modes(&self) -> io::Result<()>
pub fn disable_raw_modes() -> io::Result<()>
{
self.command.disable()?;
#[cfg(not(target_os = "windows"))]
let mut command = unix_command::RawModeCommand::new();
#[cfg(target_os = "windows")]
let mut command = win_commands::RawModeCommand::new();
command.disable()?;
return Ok(())
}
}
impl Drop for RawScreen
{
fn drop(&mut self) {
self.disable_raw_modes();
}
}
//
/////// Trait withs contains a method for switching into raw mode.
////pub trait IntoRawMode: Write + Sized {
//// fn into_raw_mode(&self, context: Rc<Context>) -> io::Result<RawTerminal>;
////}

View File

@ -21,9 +21,15 @@ pub struct Screen
impl Screen
{
pub fn new() -> Screen
pub fn new(raw_mode: bool) -> Screen
{
return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() };
if raw_mode
{
RawScreen::into_raw_mode();;
return Screen { stdout: Arc::new(Stdout::new(true)), buffer: Vec::new() };
}
return Screen::default();
}
pub fn from(stdout: Stdout) -> Screen
@ -31,19 +37,41 @@ impl Screen
return Screen { stdout: Arc::new(stdout), buffer: Vec::new() };
}
pub fn enable_raw_modes(&self) -> Result<RawScreen> {
let mut screen = Screen::from(Stdout::new(true));
let raw_screen = RawScreen::into_raw_mode(screen)?;
return Ok(raw_screen)
pub fn enable_raw_modes(&self) -> Result<()> {
RawScreen::into_raw_mode()?;
return Ok(())
}
pub fn enable_alternate_modes(&self, raw_mode: bool) -> Result<AlternateScreen> {
let mut stdout = Stdout::new(raw_mode);
if raw_mode
{
RawScreen::into_raw_mode();
}
pub fn enable_alternate_modes(&self) -> Result<AlternateScreen> {
let mut stdout = Stdout::new(true);
let alternate_screen = AlternateScreen::to_alternate_screen(stdout)?;
return Ok(alternate_screen);
}
}
impl Default for Screen
{
fn default() -> Self {
return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() };
}
}
impl Drop for Screen
{
fn drop(&mut self) {
if self.stdout.is_in_raw_mode
{
RawScreen::disable_raw_modes();
}
}
}
impl Write for Screen
{
fn write(&mut self, buf: &[u8]) -> Result<usize> {

View File

@ -11,6 +11,8 @@ use winapi::um::winnt::HANDLE;
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
use super::{handle, kernel, Empty, Stdout};
use std::sync::{Once, ONCE_INIT};
use std::io::{self, ErrorKind, Result};
use std::mem::size_of;
use std::sync::Arc;
@ -106,3 +108,15 @@ pub fn set_active_screen_buffer(new_buffer: HANDLE) -> Result<()> {
}
Ok(())
}
static GET_ORIGINAL_CONSOLE_COLOR: Once = ONCE_INIT;
static mut original_console_color: u16 = 0;
pub fn get_original_console_color() -> u16 {
GET_ORIGINAL_CONSOLE_COLOR.call_once(|| {
let handle = handle::get_output_handle().unwrap();
let csbi = get_csbi_by_handle(&handle).unwrap();
unsafe { original_console_color = csbi.wAttributes as u16 };
});
return unsafe { original_console_color };
}

View File

@ -160,53 +160,6 @@ impl TerminalCursor {
self
}
/// Print an value at the current cursor position.
///
/// This method prints an value with `print!()` and clears the buffer afterwards.
/// Rust's standard output is line-buffered. So your text gets sent to the console one line at a time.
/// If you set the curosr position and try to `print!()` at that position and do not clear the buffer, than the character will not be printed at that position.
/// But will be printed when the next `println()` will be done.
///
/// With this method you can print any displayable value at a certain position and the output buffer will be cleared afterwards.
///
/// For more information see the cursor example in /examples/cursor
///
/// #Example
///
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// use std;
/// use std::io::Write;
///
/// let crossterm = Crossterm::new();
/// let cursor = crossterm.cursor();
///
/// // of course we can just do this.
/// cursor.goto(10,10);
/// print!("@");
/// std::io::stdout().flush();
///
/// // but now we can chain the methods so it looks cleaner and it automatically flushes the buffer.
/// cursor::cursor(&context)
/// .goto(10,10)
/// .print("@");
///
/// ```
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor {
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", value).unwrap();
&self.screen.write_string(string);
&self.screen.flush();
self
}
/// Save cursor position for recall later.
///
/// Note that this position is stored program based not per instance of the `Cursor` struct.

View File

@ -15,6 +15,7 @@ use self::winapi_color::WinApiColor;
use std::convert::From;
use std::str::FromStr;
use std::sync::Arc;
use std::fmt::Display;
pub use self::color::TerminalColor;
pub use self::objectstyle::ObjectStyle;
@ -40,6 +41,12 @@ pub trait ITerminalColor {
fn color_value(&self, color: Color, color_type: ColorType) -> String;
}
pub fn style<D>(val: D) -> StyledObject<D>
where
D: Display, {
ObjectStyle::new().apply_to(val)
}
/// Attributes that could be applied on some text.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub enum Attribute {

View File

@ -11,11 +11,14 @@ use winapi::um::wincon;
use std::sync::Arc;
/// This struct is an windows implementation for color related actions.
pub struct WinApiColor;
pub struct WinApiColor
{
original_color: u16
}
impl WinApiColor {
pub fn new() -> WinApiColor {
WinApiColor {}
WinApiColor { original_color: csbi::get_original_console_color()}
}
}
@ -63,8 +66,7 @@ impl ITerminalColor for WinApiColor {
}
fn reset(&self, stdout: &Arc<Stdout>) {
self.set_bg(Color::Black, stdout);
self.set_fg(Color::White, stdout);
kernel::set_console_text_attribute(self.original_color, stdout);
}
/// This will get the winapi color value from the Color and ColorType struct

View File

@ -52,7 +52,6 @@ impl Stdout {
Stdout { screen_manager , is_in_raw_mode}
}
/// Write String to the current screen.
pub fn write_string(&self, string: String) -> io::Result<usize> {
self.screen_manager.write_str(string.as_str())