diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index a6faad0..0f9926c 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,3 +1,8 @@ +# Changes crossterm 0.5.0 +- Implemented Display for styled object. +- Removed `Screen` from the following functions: `crossterm::cursor(), crossterm::color(), crossterm::terminal()`, you won't need to care about `Screen` unless you are working with alternate or raw screen. +- more to come ... + # Changes crossterm to 0.4.3 - Fixed bug [issue 41](https://github.com/TimonPost/crossterm/issues/41) diff --git a/examples/color/mod.rs b/examples/color/mod.rs index b05f3a5..f10ff3d 100644 --- a/examples/color/mod.rs +++ b/examples/color/mod.rs @@ -8,125 +8,111 @@ use self::crossterm::{terminal, Screen}; /// print some red font | demonstration. pub fn paint_foreground() { - - - 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. + // Create a styled object. // 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); // Print the object to the given screen and. - styledobject.paint(&screen); + println!("Colored text: {}", styledobject); - 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); + // Or print inline + println!("Colored text: {}", style("Red foreground").with(Color::Blue)); } /// print some font on red background | demonstration. pub fn paint_background() { - 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. - // 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); + // Create a styled object. + // 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").on(Color::Red); // Print the object to the given screen and. - styledobject.paint(&screen); + println!("Colored text: {}", styledobject); - // 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); + // Or print inline + println!("Colored text: {}", style("Red foreground").on(Color::Blue)); } /// Print all available foreground colors | demonstration. pub fn print_all_foreground_colors() { - let screen = Screen::default(); - - 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); + println!("{}", style(format!("Black : \t\t {} \n", "■")).with(Color::Black)); + println!("{}", style(format!("Red : \t\t {} \n", "■")).with(Color::Red)); + println!("{}", style(format!("Cyan : \t\t {} \n", "■")).with(Color::Cyan)); + println!("{}", style(format!("DarkCyan : \t {} \n", "■")).with(Color::DarkCyan)); + println!("{}", style(format!("DarkRed : \t {} \n", "■")).with(Color::DarkRed)); + println!("{}", style(format!("Green : \t {} \n", "■")).with(Color::Green)); + println!("{}", style(format!("DarkGreen : \t {} \n", "■")).with(Color::DarkGreen)); + println!("{}", style(format!("Blue : \t\t {} \n", "■")).with(Color::Blue)); + println!("{}", style(format!("DarkBlue : \t {} \n", "■")).with(Color::DarkBlue)); + println!("{}", style(format!("Magenta : \t {} \n", "■")).with(Color::Magenta)); + println!("{}", style(format!("DarkMagenta : \t {} \n", "■")).with(Color::DarkMagenta)); + println!("{}", style(format!("Yellow : \t {} \n", "■")).with(Color::Yellow)); + println!("{}", style(format!("DarkYellow : \t {} \n", "■")).with(Color::DarkYellow)); + println!("{}", style(format!("Grey : \t\t {} \n", "■")).with(Color::Grey)); + println!("{}", style(format!("White : \t {} \n", "■")).with(Color::White)); #[cfg(unix)] - style("RGB color (10,10,10) ").with(Color::Rgb { + println!("{}", 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); + println!("{}",style("RGB color (10,10,10) ")).with(Color::AnsiValue(50)); } /// Print all available foreground colors | demonstration. pub fn print_all_background_colors() { - 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!("{}", style(format!("Black : \t {} \n", "■")).on(Color::Black)); + println!("{}", style(format!("Red : \t\t {} \n", "■")).on(Color::Red)); + println!("{}", style(format!("Cyan : \t\t {} \n", "■")).on(Color::Cyan)); + println!("{}", style(format!("DarkCyan : \t {} \n", "■")).on(Color::DarkCyan)); + println!("{}", style(format!("DarkRed : \t {} \n", "■")).on(Color::DarkRed)); + println!("{}", style(format!("Green : \t {} \n", "■")).on(Color::Green)); + println!("{}", style(format!("DarkGreen : \t {} \n", "■")).on(Color::DarkGreen)); + println!("{}", style(format!("Blue : \t\t {} \n", "■")).on(Color::Blue)); + println!("{}", style(format!("DarkBlue : \t {} \n", "■")).on(Color::DarkBlue)); + println!("{}", style(format!("Magenta : \t {} \n", "■")).on(Color::Magenta)); + println!("{}", style(format!("DarkMagenta : \t {} \n", "■")).on(Color::DarkMagenta)); + println!("{}", style(format!("Yellow : \t {} \n", "■")).on(Color::Yellow)); + println!("{}", style(format!("DarkYellow : \t {} \n", "■")).on(Color::DarkYellow)); + println!("{}", style(format!("Grey : \t\t {} \n", "■")).on(Color::Grey)); + println!("{}", style(format!("White : \t {} \n", "■")).on(Color::White)); #[cfg(unix)] - style("RGB color (10,10,10) ").on(Color::Rgb { + println!("{}", style("RGB color (10,10,10) ").on(Color::Rgb { r: 10, g: 10, b: 10 - }).paint(&screen); + })); #[cfg(unix)] - style("RGB color (10,10,10) ").on(Color::AnsiValue(50)).paint(&screen); + println!("{}",style("RGB color (10,10,10) ").on(Color::AnsiValue(50))); } /// 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 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_blink().paint(&screen); - style("Rapid blinking text").rapid_blink().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); + println!("{}",style("Normal text")); + println!("{}",style("Bold text").bold()); + println!("{}",style("Italic text").italic()); + println!("{}",style("Slow blinking text").slow_blink()); + println!("{}",style("Rapid blinking text").rapid_blink()); + println!("{}",style("Hidden text").hidden()); + println!("{}",style("Underlined text").underlined()); + println!("{}",style("Reversed text").reverse()); + println!("{}",style("Dim text").dim()); + println!("{}",style("Crossed out font").crossed_out()); } /// Print all supported RGB colors | demonstration. #[cfg(unix)] pub fn print_supported_colors() { - let screen = Screen::default(); - let count = color(&screen) + let count = color() .get_available_color_count() .unwrap(); for i in 0..count { - style(format!("White : \t {}", i)).on(Color::AnsiValue(i as u8)).paint(&screen); + println!("{}", style(format!("White : \t {}", i)).on(Color::AnsiValue(i as u8))); } } diff --git a/examples/cursor/mod.rs b/examples/cursor/mod.rs index 685b89e..c50f3be 100644 --- a/examples/cursor/mod.rs +++ b/examples/cursor/mod.rs @@ -9,8 +9,7 @@ use self::crossterm::Screen; /// Set the cursor to position X: 10, Y: 5 in the terminal. pub fn goto() { // Get the cursor - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // Set the cursor to position X: 10, Y: 5 in the terminal cursor.goto(10, 5); } @@ -18,8 +17,7 @@ pub fn goto() { /// get the cursor position pub fn pos() { // Get the cursor - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // get the cursor position. let (x, y) = cursor.pos(); } @@ -27,8 +25,7 @@ pub fn pos() { /// Move the cursor 3 up | demonstration. pub fn move_up() { // Get the cursor - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // Move the cursor to position 3 times to the up in the terminal cursor.move_up(10); @@ -36,24 +33,21 @@ pub fn move_up() { /// Move the cursor 3 to the right | demonstration. pub fn move_right() { - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // 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 screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // 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 screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // Move the cursor to position 3 times to the left in the terminal cursor.move_left(3); @@ -87,8 +81,7 @@ pub fn move_left() { /// Save and reset cursor position | demonstration.. pub fn safe_and_reset_position() { - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); // Goto X: 5 Y: 5 cursor.goto(5, 5); @@ -108,22 +101,19 @@ pub fn safe_and_reset_position() { /// Hide cursor display | demonstration. pub fn hide_cursor() { - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); cursor.hide(); } /// Show cursor display | demonstration. pub fn show_cursor() { - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); cursor.show(); } /// Show cursor display, only works on certain terminals.| demonstration pub fn blink_cursor() { - let screen = Screen::default(); - let mut cursor = cursor(&screen); + let mut cursor = cursor(); cursor.blink(false); cursor.blink(false); } diff --git a/examples/examples.rs b/examples/examples.rs index 697b06e..c11aff1 100644 --- a/examples/examples.rs +++ b/examples/examples.rs @@ -9,7 +9,7 @@ extern crate crossterm; // modules that could be test -//mod terminal; +mod terminal; mod color; mod cursor; mod some_types; diff --git a/examples/input/keyboard/async_input.rs b/examples/input/keyboard/async_input.rs index 7d83f78..7cd40e3 100644 --- a/examples/input/keyboard/async_input.rs +++ b/examples/input/keyboard/async_input.rs @@ -11,8 +11,7 @@ use std::time::Duration; /// this will capture the input until the given key. pub fn read_async_until() { // create raw screen - let screen = Screen::default(); - let crossterm = Crossterm::new(&screen); + let crossterm = Crossterm::new(); // init some modules we use for this demo let input = crossterm.input(); @@ -44,8 +43,7 @@ pub fn read_async_until() { /// this will read pressed characters async until `x` is typed. pub fn read_async() { - let screen = Screen::default(); - let input = input(&screen); + let input = input(); let mut stdin = input.read_async().bytes(); @@ -65,7 +63,7 @@ pub fn read_async() { pub fn read_async_demo() { let screen = Screen::new(true); - let crossterm = Crossterm::new(&screen); + let crossterm = Crossterm::from_screen(&screen); // init some modules we use for this demo let input = crossterm.input(); @@ -104,7 +102,7 @@ pub fn async_reading_on_alternate_screen() { // switch to alternate screen if let Ok(alternate) = screen.enable_alternate_modes(true) { - let crossterm = Crossterm::new(&alternate.screen); + let crossterm = Crossterm::from_screen(&alternate.screen); // init some modules we use for this demo let input = crossterm.input(); let terminal = crossterm.terminal(); diff --git a/examples/input/keyboard/input.rs b/examples/input/keyboard/input.rs index 9186d7d..fda3670 100644 --- a/examples/input/keyboard/input.rs +++ b/examples/input/keyboard/input.rs @@ -4,8 +4,7 @@ use self::crossterm::input::input; use self::crossterm::Screen; pub fn read_char() { - let screen = Screen::default(); - let input = input(&screen); + let input = input(); match input.read_char() { Ok(s) => println!("char typed: {}", s), @@ -14,8 +13,7 @@ pub fn read_char() { } pub fn read_line() { - let screen = Screen::default(); - let input = input(&screen); + let input = input(); match input.read_line() { Ok(s) => println!("string typed: {}", s), diff --git a/examples/program_examples/command_bar.rs b/examples/program_examples/command_bar.rs index 7f3eaae..e0760a5 100644 --- a/examples/program_examples/command_bar.rs +++ b/examples/program_examples/command_bar.rs @@ -1,7 +1,7 @@ extern crate crossterm; use crossterm::{Screen, Crossterm}; -use crossterm::terminal::{terminal,Terminal, ClearType}; +use crossterm::terminal::{from_screen,Terminal, ClearType}; use crossterm::cursor::{TerminalCursor, cursor}; use crossterm::input::input; use std::sync::{Arc,Mutex}; @@ -12,7 +12,7 @@ fn main() { use crossterm::color; let screen = Screen::new(true); - let crossterm = Crossterm::new(&screen); + let crossterm = Crossterm::from_screen(&screen); let cursor = crossterm.cursor(); cursor.hide(); @@ -23,7 +23,7 @@ fn main() { let mut count = 0; thread::spawn(move || { - let input = input(&screen); + let input = input(); let mut stdin = input.read_async().bytes(); loop @@ -60,7 +60,7 @@ fn log(input_buf: Arc>, screen: &Screen) -> Vec FirstDepthSearch<'screen> // push first position on the stack self.stack.push(self.root_pos); - let crossterm = Crossterm::new(&self.screen); + let crossterm = Crossterm::from_screen(&self.screen); let mut cursor = crossterm.cursor(); cursor.hide(); @@ -75,7 +75,7 @@ impl<'screen> FirstDepthSearch<'screen> cell.paint(&self.screen); self.screen.stdout.flush(); - thread::sleep(time::Duration::from_millis(2)); + thread::sleep(time::Duration::from_millis(1)); } } diff --git a/examples/program_examples/first_depth_search/src/main.rs b/examples/program_examples/first_depth_search/src/main.rs index 2d8c9b4..3d08ca0 100644 --- a/examples/program_examples/first_depth_search/src/main.rs +++ b/examples/program_examples/first_depth_search/src/main.rs @@ -55,7 +55,7 @@ fn print_welcome_screen() { let mut screen = Screen::new(true); - let crossterm = Crossterm::new(&screen); + let crossterm = Crossterm::from_screen(&screen); // create the handle for the cursor and terminal. let terminal = crossterm.terminal(); diff --git a/examples/program_examples/first_depth_search/src/map.rs b/examples/program_examples/first_depth_search/src/map.rs index c9bff13..de8c251 100644 --- a/examples/program_examples/first_depth_search/src/map.rs +++ b/examples/program_examples/first_depth_search/src/map.rs @@ -41,8 +41,7 @@ impl Map // render the map on the screen. pub fn render_map(&mut self, screen: &Screen) { - let crossterm = Crossterm::new(&screen); - let mut cursor = crossterm.cursor(); + let crossterm = Crossterm::from_screen(screen); for row in self.map.iter_mut() { @@ -52,7 +51,7 @@ impl Map if (column.position.y == 0 || column.position.y == self.size.height - 1) || (column.position.x == 0 || column.position.x == self.size.width - 1) { let cell_style = crossterm.style(column.look).on(column.color); - cursor.goto(column.position.x as u16, column.position.y as u16); + cursor().goto(column.position.x as u16, column.position.y as u16); cell_style.paint(&screen); } } diff --git a/examples/program_examples/snake/src/main.rs b/examples/program_examples/snake/src/main.rs index cba1d19..d2b0d43 100644 --- a/examples/program_examples/snake/src/main.rs +++ b/examples/program_examples/snake/src/main.rs @@ -27,7 +27,7 @@ fn main() { { let mut screen = Screen::new(true); - let crossterm = Crossterm::new(&screen); + let crossterm = Crossterm::from_screen(&screen); let cursor = crossterm.cursor(); let mut input = crossterm.input(); @@ -86,7 +86,7 @@ fn main() { fn title_screen() -> Size { - let crossterm = Crossterm::new(&Screen::default()); + let crossterm = Crossterm::new(); let cursor = crossterm.cursor(); let terminal = crossterm.terminal().clear(ClearType::All); @@ -110,7 +110,7 @@ fn title_screen() -> Size fn print_game_stats(map_size: Size, snake_lenght: usize, food_aten: usize, screen: &mut Screen) { - let crossterm = Crossterm::new(&Screen::default()); + let crossterm = Crossterm::new(); let cursor = crossterm.cursor(); let terminal = crossterm.terminal().clear(ClearType::All); @@ -124,7 +124,7 @@ fn print_game_stats(map_size: Size, snake_lenght: usize, food_aten: usize, scree fn game_over_screen() { - let crossterm = Crossterm::new(&Screen::default()); + let crossterm = Crossterm::new(); let cursor = crossterm.cursor(); let terminal = crossterm.terminal(); diff --git a/examples/program_examples/snake/src/map.rs b/examples/program_examples/snake/src/map.rs index 5b5e10b..187032c 100644 --- a/examples/program_examples/snake/src/map.rs +++ b/examples/program_examples/snake/src/map.rs @@ -2,7 +2,7 @@ use super::variables::{Position, Size, Direction }; use super::snake::Snake; use crossterm::{Crossterm, Screen}; -use crossterm::cursor::cursor; +use crossterm::cursor::from_screen; use crossterm::style::{ObjectStyle, StyledObject, Color, style}; use rand::distributions::{IndependentSample, Range}; @@ -30,7 +30,7 @@ impl Map // render the map on the screen. pub fn render_map(&mut self, screen: &Screen, free_positions: &mut HashMap) { - let crossterm = Crossterm::new(screen); + let crossterm = Crossterm::from_screen(screen); let mut cursor = crossterm.cursor(); let mut terminal = crossterm.terminal(); @@ -73,7 +73,7 @@ impl Map fn draw_food(&self, screen: &Screen) { - cursor(screen).goto(self.foot_pos.x as u16, self.foot_pos.y as u16); + from_screen(screen).goto(self.foot_pos.x as u16, self.foot_pos.y as u16); style("$").with(Color::Green).paint(screen); screen.stdout.flush(); } diff --git a/examples/program_examples/snake/src/snake.rs b/examples/program_examples/snake/src/snake.rs index ed89a33..b798161 100644 --- a/examples/program_examples/snake/src/snake.rs +++ b/examples/program_examples/snake/src/snake.rs @@ -33,7 +33,7 @@ impl Snake pub fn move_snake(&mut self, direction: &Direction, screen: &Screen, free_positions: &mut HashMap ) { - let crossterm = Crossterm::new(screen); + let crossterm = Crossterm::from_screen(screen); let cursor = crossterm.cursor(); let terminal = crossterm.terminal(); diff --git a/examples/program_examples/snake/src/variables.rs b/examples/program_examples/snake/src/variables.rs index e4d097e..f227f48 100644 --- a/examples/program_examples/snake/src/variables.rs +++ b/examples/program_examples/snake/src/variables.rs @@ -1,8 +1,8 @@ extern crate crossterm; -use self::crossterm::terminal::{terminal, ClearType}; +use self::crossterm::terminal::{self, ClearType}; use self::crossterm::style::{Color, StyledObject, ObjectStyle, style }; -use self::crossterm::cursor::cursor; +use self::crossterm::cursor; use self::crossterm::Screen; use std::fmt::Debug; @@ -33,15 +33,15 @@ impl Position pub fn draw(&self, val: &str, screen: &Screen) { - cursor(screen).goto(self.x as u16, self.y as u16); + cursor::from_screen(screen).goto(self.x as u16, self.y as u16); style(val).with(Color::Red).paint(&screen); screen.stdout.flush(); } pub fn remove(&self, screen: &Screen) { - cursor(screen).goto(self.x as u16, self.y as u16); - terminal(&screen).write(" "); + cursor::from_screen(screen).goto(self.x as u16, self.y as u16); + terminal::from_screen(&screen).write(" "); } } diff --git a/examples/some_types/mod.rs b/examples/some_types/mod.rs index 4bf7b21..afd218f 100644 --- a/examples/some_types/mod.rs +++ b/examples/some_types/mod.rs @@ -4,12 +4,10 @@ use crossterm::{Crossterm, Screen}; use crossterm::style::Color; /// use the `Crossterm` to get an instance to the cursor module | demonstration. -pub fn use_crossterm_cursor() +pub fn crossterm() { - let screen = Screen::default(); - // Create the crossterm type to access different modules. - let crossterm = Crossterm::new(&screen); + let crossterm = Crossterm::new(); // pass a reference to the current screen. let cursor = crossterm.cursor(); diff --git a/examples/terminal/alternate_screen.rs b/examples/terminal/alternate_screen.rs index 8dcca37..4ba4394 100644 --- a/examples/terminal/alternate_screen.rs +++ b/examples/terminal/alternate_screen.rs @@ -8,7 +8,7 @@ use std::io::{stdout, Write}; use std::{thread, time}; fn print_wait_screen(screen: &Screen) { - let crossterm = Crossterm::new(screen); + let crossterm = Crossterm::from_screen(screen); let terminal = crossterm.terminal(); let cursor = crossterm.cursor(); diff --git a/examples/terminal/raw_mode.rs b/examples/terminal/raw_mode.rs index 926ef6f..9b0ada7 100644 --- a/examples/terminal/raw_mode.rs +++ b/examples/terminal/raw_mode.rs @@ -8,7 +8,7 @@ use std::io::{stdout, Write}; use std::{thread, time}; fn print_wait_screen(screen: &mut Screen) { - let crossterm = Crossterm::new(screen); + let crossterm = Crossterm::from_screen(screen); let terminal = crossterm.terminal(); let cursor = crossterm.cursor(); diff --git a/examples/terminal/terminal.rs b/examples/terminal/terminal.rs index 4072ab8..a9ffce8 100644 --- a/examples/terminal/terminal.rs +++ b/examples/terminal/terminal.rs @@ -5,8 +5,7 @@ extern crate crossterm; use crossterm::terminal::{ClearType, terminal}; -use crossterm::{Crossterm, Screen}; - +use crossterm::cursor; fn print_test_data() { for i in 0..100 { println!("Test data to test terminal: {}", i); @@ -15,8 +14,7 @@ fn print_test_data() { /// Clear all lines in terminal | demonstration pub fn clear_all_lines() { - let crossterm = Crossterm::new(&Screen::default()); - let mut terminal = crossterm.terminal(); + let mut terminal = terminal(); print_test_data(); @@ -26,13 +24,12 @@ pub fn clear_all_lines() { /// Clear all lines from cursor position X:4, Y:4 down | demonstration pub fn clear_from_cursor_down() { - let crossterm = Crossterm::new(&Screen::default()); - let mut terminal = crossterm.terminal(); - + let mut terminal = terminal(); + print_test_data(); // Set terminal cursor position (see example for more info). - crossterm.cursor().goto(4, 8); + cursor().goto(4, 8); // Clear all cells from current cursor position down. terminal.clear(ClearType::FromCursorDown); @@ -40,13 +37,12 @@ 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 crossterm = Crossterm::new(&Screen::default()); - let mut terminal = crossterm.terminal(); + let mut terminal = terminal(); print_test_data(); // Set terminal cursor position (see example for more info). - crossterm.cursor().goto(4, 4); + cursor().goto(4, 4); // Clear all cells from current cursor position down. terminal.clear(ClearType::FromCursorUp); @@ -54,13 +50,12 @@ pub fn clear_from_cursor_up() { /// Clear all lines from cursor position X:4, Y:4 up | demonstration pub fn clear_current_line() { - let crossterm = Crossterm::new(&Screen::default()); - let mut terminal = crossterm.terminal(); + let mut terminal = terminal(); print_test_data(); // Set terminal cursor position (see example for more info). - crossterm.cursor().goto(4, 4); + cursor().goto(4, 4); // Clear current line cells. terminal.clear(ClearType::CurrentLine); @@ -68,13 +63,12 @@ pub fn clear_current_line() { /// Clear all lines from cursor position X:4, Y:7 up | demonstration pub fn clear_until_new_line() { - let crossterm = Crossterm::new(&Screen::default()); - let mut terminal = crossterm.terminal(); + let mut terminal = terminal(); print_test_data(); // Set terminal cursor position (see example for more info). - crossterm.cursor().goto(4, 20); + cursor().goto(4, 20); // Clear all the cells until next line. terminal.clear(ClearType::UntilNewLine); @@ -82,8 +76,7 @@ pub fn clear_until_new_line() { /// Print the the current terminal size | demonstration. pub fn print_terminal_size() { - let screen = Screen::default(); - let mut terminal = terminal(&screen); + let mut terminal = terminal(); // Get terminal size let (width, height) = terminal.terminal_size(); @@ -94,16 +87,16 @@ pub fn print_terminal_size() { /// Set the terminal size to width 10, height: 10 | demonstration. pub fn set_terminal_size() { - let screen = Screen::default(); - let mut terminal = terminal(&screen); + + let mut terminal = terminal(); terminal.set_size(10, 10); } /// Scroll down 10 lines | demonstration. pub fn scroll_down() { - let screen = Screen::default(); - let mut terminal = terminal(&screen); + + let mut terminal = terminal(); print_test_data(); @@ -113,8 +106,8 @@ pub fn scroll_down() { /// Scroll down 10 lines | demonstration. pub fn scroll_up() { - let screen = Screen::default(); - let mut terminal = terminal(&screen); + + let mut terminal = terminal(); print_test_data(); @@ -124,8 +117,8 @@ pub fn scroll_up() { /// Resize the terminal to X: 10, Y: 10 | demonstration. pub fn resize_terminal() { - let screen = Screen::default(); - let mut terminal = terminal(&screen); + + let mut terminal = terminal(); // Get terminal size terminal.set_size(10, 10); @@ -133,7 +126,7 @@ pub fn resize_terminal() { /// exit the current proccess. pub fn exit() { - let screen = Screen::default(); - let mut terminal = terminal(&screen); + + let mut terminal = terminal(); terminal.exit(); } diff --git a/src/common/crossterm.rs b/src/common/crossterm.rs index f496df9..6d9e8f5 100644 --- a/src/common/crossterm.rs +++ b/src/common/crossterm.rs @@ -36,88 +36,101 @@ use std::sync::Arc; /// } /// ``` pub struct Crossterm { - stdout: Arc + stdout: Option> } impl<'crossterm> Crossterm { /// Create a new instance of `Crossterm` - pub fn new(screen: &Screen) -> Crossterm { - Crossterm { stdout: screen.stdout.clone() } + pub fn new() -> Crossterm { + Crossterm { stdout: None } + } + + /// Create a new instance of `Crossterm` + pub fn from_screen(screen: &Screen) -> Crossterm { + Crossterm { stdout: Some(screen.stdout.clone()) } } /// Get an `TerminalCursor` implementation whereon cursor related actions can be performed. /// /// ```rust /// extern crate crossterm; - /// use crossterm::{Crossterm, Screen}; + /// use crossterm::Crossterm; /// - /// let crossterm = Crossterm::new(&Screen::default()); + /// let crossterm = Crossterm::new(); /// let cursor = crossterm.cursor(); /// ``` pub fn cursor(&self) -> cursor::TerminalCursor { - cursor::TerminalCursor::new(&self.stdout) + match &self.stdout { + None => { cursor::TerminalCursor::new()}, + Some(stdout) => { cursor::TerminalCursor::on_screen(&stdout) }, + } } /// Get an `TerminalInput` implementation whereon terminal related actions can be performed. /// /// ```rust /// extern crate crossterm; - /// use crossterm::{Crossterm, Screen}; - /// use crossterm::terminal; + /// use crossterm::Crossterm; /// - /// let crossterm = Crossterm::new(&Screen::default()); + /// let crossterm = Crossterm::new(); /// let input = crossterm.input(); /// ``` pub fn input(&self) -> input::TerminalInput { - return input::TerminalInput::new(&self.stdout); + match &self.stdout { + None => input::TerminalInput::new(), + Some(stdout) => input::TerminalInput::on_screen(&stdout), + } } /// Get an `Terminal` implementation whereon terminal related actions can be performed. /// /// ```rust /// extern crate crossterm; - /// use crossterm::{Crossterm, Screen}; + /// use crossterm::Crossterm; /// - /// let crossterm = Crossterm::new(&Screen::default()); + /// let crossterm = Crossterm::new(); /// let mut terminal = crossterm.terminal(); /// ``` pub fn terminal(&self) -> terminal::Terminal { - return terminal::Terminal::new(&self.stdout); + match &self.stdout { + None => terminal::Terminal::new(), + Some(stdout) => terminal::Terminal::on_screen(&stdout), + } } /// Get an `TerminalColor` implementation whereon color related actions can be performed. /// /// ```rust /// extern crate crossterm; - /// use crossterm::{Crossterm, Screen}; + /// use crossterm::Crossterm; /// - /// let crossterm = Crossterm::new(&Screen::default()); - /// let mut terminal = crossterm.terminal(); + /// let crossterm = Crossterm::new(); + /// let mut terminal = crossterm.color(); /// ``` pub fn color(&self) -> style::TerminalColor { - return style::TerminalColor::new(&self.stdout); + match &self.stdout { + None => style::TerminalColor::new(), + Some(stdout) => style::TerminalColor::on_screen(&stdout), + } } /// This could be used to style an `Displayable` type with colors and attributes. /// /// ```rust - /// extern crate crossterm; - /// use crossterm::{Crossterm, Screen}; + /// extern crate crossterm; + /// use crossterm::Crossterm; /// - /// let crossterm = Crossterm::new(&Screen::default()); + /// let crossterm = Crossterm::new(); /// /// // get an styled object which could be painted to the terminal. /// let styled_object = crossterm.style("Some Blue colored text on black background") /// .with(Color::Blue) /// .on(Color::Black); /// - /// // create an default screen. - /// let screen = Screen::default(); - /// /// // print the styled font * times to the current screen. /// for i in 1..10 /// { - /// styled_object.paint(&screen); + /// println!("{}", styled_object); /// } /// ``` pub fn style(&self, val: D) -> style::StyledObject @@ -130,6 +143,13 @@ impl<'crossterm> Crossterm { impl From> for Crossterm { fn from(stdout: Arc) -> Self { - Crossterm { stdout: stdout } + Crossterm { stdout: Some(stdout) } + } +} + +impl From for Crossterm +{ + fn from(screen: Screen) -> Self { + Crossterm { stdout: Some(screen.stdout.clone()) } } } \ No newline at end of file diff --git a/src/common/functions.rs b/src/common/functions.rs index bca4c9e..a2cb8f1 100644 --- a/src/common/functions.rs +++ b/src/common/functions.rs @@ -2,6 +2,7 @@ use super::TerminalOutput; use std::sync::Arc; +use std::io::{self, Write}; #[cfg(windows)] use kernel::windows_kernel::ansi_support::{try_enable_ansi_support, windows_supportable}; @@ -21,7 +22,7 @@ pub fn get_terminal_size() -> (u16, u16) { } /// Get the cursor position based on the current platform. -pub fn get_cursor_position(_stdout: &Arc) -> (u16, u16) { +pub fn get_cursor_position() -> (u16, u16) { #[cfg(unix)] return pos().expect("Valide position"); // return pos().unwrap_or_else(|x| { return (0,0) }); @@ -60,3 +61,17 @@ pub fn get_module(winapi_impl: T, unix_impl: T) -> Option { term } + +pub fn write(stdout: &Option<&Arc>, string: String) { + match stdout { + None => { print!("{}", string.as_str()); io::stdout().flush(); }, + Some(output) => { output.write_string(string); }, + } +} + +pub fn write_str(stdout: &Option<&Arc>, string: &str) { + match stdout { + None => { print!("{}", string); io::stdout().flush(); }, + Some(output) => { output.write_str(string); }, + } +} diff --git a/src/common/screen/alternate.rs b/src/common/screen/alternate.rs index 5f81905..8a4b5d3 100644 --- a/src/common/screen/alternate.rs +++ b/src/common/screen/alternate.rs @@ -13,6 +13,8 @@ use std::convert::From; /// With this type you will be able to switch to alternate screen and back to main screen. /// Check also the Screen type for swishing to alternate mode. +/// +/// Although this type is available for you to use I would recommend using `Screen` instead. pub struct AlternateScreen { command: Box, diff --git a/src/common/screen/mod.rs b/src/common/screen/mod.rs index 02cc1cb..e98a9b8 100644 --- a/src/common/screen/mod.rs +++ b/src/common/screen/mod.rs @@ -1,4 +1,5 @@ -//! This module provides some modules to work with the terminal screen. Like raw and alternate screen. +//! This module provides some modules to work with the terminal screen. +//! Like allowing you to switch between raw and alternate screen. mod alternate; mod raw; diff --git a/src/common/screen/raw.rs b/src/common/screen/raw.rs index d5b4ea2..3d8dc43 100644 --- a/src/common/screen/raw.rs +++ b/src/common/screen/raw.rs @@ -21,6 +21,9 @@ use std::io; use std::sync::Arc; /// A wrapper for the raw terminal state. Which can be used to write to. +/// +/// Although this type is available for you to use I would recommend using `Screen` instead. +/// Note that when you want to use input and rawmode you should use `Screen`. pub struct RawScreen; impl RawScreen { diff --git a/src/common/screen/screen.rs b/src/common/screen/screen.rs index 87f9c01..5eb2af2 100644 --- a/src/common/screen/screen.rs +++ b/src/common/screen/screen.rs @@ -4,14 +4,12 @@ use TerminalOutput; use std::io::Write; use std::io::Result; use std::sync::Arc; +use std::sync::atomic::AtomicBool; -/// This type represents an screen. -/// This screen has an stdout which is used by the program to write to or to execute commands with. +/// This type represents an screen which could be in normal, raw and alternate modes. /// -/// You have to make sure that you pass the correct `Screen` to the modules `cursor, terminal, color, input, style`. -/// Most of the time you just have one screen so you could get an instance of that screen with: `Screen::default()`. +/// Lets talk about the different modes a bit: /// -/// The screen can be in two modes at first: /// - Alternate modes: /// /// *Nix style applications often utilize an alternate screen buffer, so that they can modify the entire contents of the buffer, without affecting the application that started them. @@ -31,31 +29,34 @@ use std::sync::Arc; /// - Escape characters /// Note that in raw modes `\n` `\r` will move to the new line but the cursor will be at the same position as before on the new line therefor use `\n\r` to start at the new line at the first cell. /// -/// Also this screen has an buffer where you can write to. When you want to write the buffer to the screen you could flush the screen. +/// You have to make sure that you pass the correct `Screen` to the modules `cursor, terminal, color, input, style`. +/// If you switch to alternate screen modes you will get some `Screen` handle back. This `Screen` handle represents the alternate screen. +/// Once you want to do coloring or such you need to pass the `Screen` handle the library so that it could be used for coloring on the right screen. /// +/// # Example /// ```rust -/// // create default screen. +/// // create default screen (not raw). /// let screen = Screen::default(); +/// /// // create raw screen. /// let mut screen = Screen::new(true); /// -/// // write some text to the internal buffer of this type. -/// screen.write(b"Some text"); -/// screen.write(b"Some more text"); -/// screen.write(b"Some more text"); -/// -/// // write the above text by flushing the internal buffer of this type. -/// screen.flush(); -/// +/// // create a `Screen` with raw modes disabled. /// let screen = Screen::new(false); /// -/// // create raw alternate screen from normal screen. +/// // create 'raw alternate screen' from normal screen. /// if let Ok(alternate_screen) = screen.enable_alternate_modes(true) /// { -/// let crossterm = Crossterm::new(&alternate_screen.screen); -/// -/// // make sure to pass in the screen of the AlternateScreen. +/// // 'alternate screen' is an instance which you should use when you want your actions like: coloring and cursor movement happening at the alternate screen. +/// // For that you can use `Crossterm::from_screen(alternate.screen)` so that all modules like: cursor, input, terminal will be executed on alternate screen. +/// let crossterm = Crossterm::from_screen(&alternate_screen.screen); /// crossterm.cursor(); +/// crossterm.terminal(); +/// +/// // If you want access modules directly without the `Crossterm` type. You should do the following: +/// let cursor = crossterm::cursor::from_screen(&alternate_screen.screen); +/// let terminal = crossterm::terminal::from_screen(&alternate_screen.screen); +/// let input = crossterm::input::from_screen(&alternate_screen.screen); /// } /// ``` /// @@ -73,11 +74,11 @@ impl Screen pub fn new(raw_mode: bool) -> Screen { if raw_mode - { - let screen = Screen { stdout: Arc::new(TerminalOutput::new(true)), buffer: Vec::new(), drop: true }; - RawScreen::into_raw_mode().unwrap(); - return screen; - } + { + let screen = Screen { stdout: Arc::new(TerminalOutput::new(true)), buffer: Vec::new(), drop: true }; + RawScreen::into_raw_mode().unwrap(); + return screen; + } return Screen::default(); } @@ -98,9 +99,18 @@ impl Screen return Ok(alternate_screen); } - /// Write buffer to an internal buffer. When you want to write the buffer to screen use `flush()`. - /// - /// This function is useful if you want to build up some output and when you are ready you could flush the output to the screen. + /// Write buffer to an internal buffer. When you want to write the buffer to screen use `flush_buf()`. + /// + /// This function is useful if you want to build up some output and when you are ready you could flush the output to the screen. + /// + /// # Example + /// ``` + /// // write some text to the internal buffer of this type. Note that this will not be printed until you call `flush_buf` + /// let screen = Screen::default(); + /// screen.write_buf(b"Some text"); + /// screen.write_buf(b"Some more text"); + /// screen.write_buf(b"Some more text"); + /// ``` pub fn write_buf(&mut self, buf: &[u8]) -> Result { self.buffer.write(buf)?; Ok(buf.len()) diff --git a/src/modules/cursor/ansi_cursor.rs b/src/modules/cursor/ansi_cursor.rs index 38b8610..1168a3e 100644 --- a/src/modules/cursor/ansi_cursor.rs +++ b/src/modules/cursor/ansi_cursor.rs @@ -3,63 +3,65 @@ //! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect. use super::*; +use std::io::Write; /// This struct is an ansi implementation for cursor related actions. -pub struct AnsiCursor; +pub struct AnsiCursor { } -impl AnsiCursor { +impl AnsiCursor +{ pub fn new() -> Box { - Box::from(AnsiCursor {}) + Box::from(AnsiCursor { }) } } impl ITerminalCursor for AnsiCursor { - fn goto(&self, x: u16, y: u16, stdout: &Arc) { - stdout.write_string(format!(csi!("{};{}H"), y + 1, x + 1)); + fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc>) { + functions::write(stdout, format!(csi!("{};{}H"), y + 1, x + 1)); } - fn pos(&self, stdout: &Arc) -> (u16, u16) { - functions::get_cursor_position(stdout) + fn pos(&self) -> (u16, u16) { + functions::get_cursor_position() } - fn move_up(&self, count: u16, stdout: &Arc) { - stdout.write_string(format!(csi!("{}A"), count)); + fn move_up(&self, count: u16, stdout: &Option<&Arc>) { + functions::write(stdout, format!(csi!("{}A"), count)); } - fn move_right(&self, count: u16, stdout: &Arc) { - stdout.write_string(format!(csi!("{}C"), count)); + fn move_right(&self, count: u16, stdout: &Option<&Arc>) { + functions::write(stdout, format!(csi!("{}C"), count)); } - fn move_down(&self, count: u16, stdout: &Arc) { - stdout.write_string(format!(csi!("{}B"), count)); + fn move_down(&self, count: u16, stdout: &Option<&Arc>) { + functions::write(stdout, format!(csi!("{}B"), count)); } - fn move_left(&self, count: u16, stdout: &Arc) { - stdout.write_string(format!(csi!("{}D"), count)); + fn move_left(&self, count: u16, stdout: &Option<&Arc>) { + functions::write(stdout, format!(csi!("{}D"), count)); } - fn save_position(&self, stdout: &Arc) { - stdout.write_str(csi!("s")); + fn save_position(&self, stdout: &Option<&Arc>) { + functions::write_str(stdout, csi!("s")); } - fn reset_position(&self, stdout: &Arc) { - stdout.write_str(csi!("u")); + fn reset_position(&self, stdout: &Option<&Arc>) { + functions::write_str(stdout, csi!("u")); } - fn hide(&self, stdout: &Arc) { - stdout.write_str(csi!("?25l")); + fn hide(&self, stdout: &Option<&Arc>) { + functions::write_str(stdout, csi!("?25l")); } - fn show(&self, stdout: &Arc) { - stdout.write_str(csi!("?25h")); + fn show(&self, stdout: &Option<&Arc>) { + functions::write_str(stdout, csi!("?25h")); } - fn blink(&self, blink: bool, stdout: &Arc) { + fn blink(&self, blink: bool, stdout: &Option<&Arc>) { if blink { - stdout.write_str(csi!("?12h")); + functions::write_str(stdout, csi!("?12h")); } else { - stdout.write_str(csi!("?12l")); + functions::write_str(stdout, csi!("?12l")); } } } diff --git a/src/modules/cursor/cursor.rs b/src/modules/cursor/cursor.rs index 67588dd..cd24b13 100644 --- a/src/modules/cursor/cursor.rs +++ b/src/modules/cursor/cursor.rs @@ -15,25 +15,27 @@ use Screen; /// use self::crossterm::cursor; /// use self::crossterm::Screen; /// -/// let screen = Screen::default(); -/// let mut cursor = cursor(&screen); +/// let mut cursor = cursor(); /// /// // Get cursor and goto pos X: 5, Y: 10 /// cursor.goto(5,10); -/// +/// /// cursor.show(); /// cursor.hide(); /// cursor.blink(true); /// cursor.move_left(2); /// ``` +/// +/// When you want to use 'cursor' on 'alternate screen' use the `Screen` type instead and pass it to the `cursor::from_screen()` function. +/// By doing that cursor actions will be performed on the alternate screen. pub struct TerminalCursor<'stdout> { - screen: &'stdout Arc, terminal_cursor: Box, + stdout: Option<&'stdout Arc>, } -impl<'stdout> TerminalCursor<'stdout> { +impl<'stdout> TerminalCursor <'stdout>{ /// Create new cursor instance whereon cursor related actions can be performed. - pub fn new(screen: &'stdout Arc) -> TerminalCursor<'stdout> { + pub fn new() -> TerminalCursor<'stdout> { #[cfg(target_os = "windows")] let cursor = functions::get_module::>(WinApiCursor::new(), AnsiCursor::new()) @@ -44,90 +46,99 @@ impl<'stdout> TerminalCursor<'stdout> { TerminalCursor { terminal_cursor: cursor, - screen: screen, + stdout: None, + } + } + + pub fn on_screen(stdout: &'stdout Arc) -> TerminalCursor<'stdout> { + #[cfg(target_os = "windows")] + let cursor = + functions::get_module::>(WinApiCursor::new(), AnsiCursor::new()) + .unwrap(); + + #[cfg(not(target_os = "windows"))] + let cursor = AnsiCursor::new() as Box; + + TerminalCursor { + terminal_cursor: cursor, + stdout: Some(stdout), } } /// Goto some position (x,y) in the terminal. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// // change the cursor to position, x: 4 and y: 5 /// cursor.goto(4,5); /// /// ``` pub fn goto(&self, x: u16, y: u16) { - self.terminal_cursor.goto(x, y, &self.screen); + self.terminal_cursor.goto(x, y, &self.stdout); } /// Get current cursor position (x,y) in the terminal. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// // get the current cursor pos /// let (x,y) = cursor.pos(); /// ``` pub fn pos(&self) -> (u16, u16) { - self.terminal_cursor.pos(&self.screen) + self.terminal_cursor.pos() } /// Move the current cursor position `n` times up. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// // Move the cursor to position 3 times to the up in the terminal /// cursor.move_up(3); /// ``` pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { - self.terminal_cursor.move_up(count, &self.screen); + self.terminal_cursor.move_up(count, &self.stdout); self } /// Move the current cursor position `n` times right. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// // Move the cursor to position 3 times to the right in the terminal /// cursor.move_right(3); /// ``` pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { - self.terminal_cursor.move_right(count, &self.screen); + self.terminal_cursor.move_right(count, &self.stdout); self } /// Move the current cursor position `n` times down. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// // Move the cursor to position 3 times to the down in the terminal /// cursor.move_down(3); /// ``` pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { - self.terminal_cursor.move_down(count, &self.screen); + self.terminal_cursor.move_down(count, &self.stdout); self } /// Move the current cursor position `n` times left. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// // Move the cursor to position 3 times to the left in the terminal /// cursor.move_left(3); /// ``` pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { - self.terminal_cursor.move_left(count, &self.screen); + self.terminal_cursor.move_left(count, &self.stdout); self } @@ -136,13 +147,12 @@ impl<'stdout> TerminalCursor<'stdout> { /// Note that this position is stored program based not per instance of the `Cursor` struct. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// cursor.safe_position(); /// ``` pub fn save_position(&self) { - self.terminal_cursor.save_position(&self.screen); + self.terminal_cursor.save_position(&self.stdout); } /// Return to saved cursor position @@ -150,36 +160,34 @@ impl<'stdout> TerminalCursor<'stdout> { /// Note that this method reset to the position set by `save_position()` and that this position is stored program based not per instance of the `Cursor` struct. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// /// cursor.reset_position(); /// ``` pub fn reset_position(&self) { - self.terminal_cursor.reset_position(&self.screen); + self.terminal_cursor.reset_position(&self.stdout); } /// Hide de cursor in the console. /// /// ```rust - /// let cursor = cursor(&Screen::default()); + /// let cursor = cursor(); /// cursor.hide(); /// ``` pub fn hide(&self) { - self.terminal_cursor.hide(&self.screen); + self.terminal_cursor.hide(&self.stdout); } /// Show the cursor in the console. /// /// ```rust /// - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// cursor.show(); /// /// ``` pub fn show(&self) { - self.terminal_cursor.show(&self.screen); + self.terminal_cursor.show(&self.stdout); } /// Enable or disable blinking of the terminal. @@ -187,18 +195,22 @@ impl<'stdout> TerminalCursor<'stdout> { /// Not all terminals are supporting this functionality. Windows versions lower than windows 10 also are not supporting this version. /// /// ```rust - /// let screen = Screen::default(); - /// let cursor = cursor(&screen); + /// let cursor = cursor(); /// cursor.blink(true); /// cursor.blink(false); /// ``` pub fn blink(&self, blink: bool) { - self.terminal_cursor.blink(blink, &self.screen); + self.terminal_cursor.blink(blink, &self.stdout); } } /// Get an TerminalCursor implementation whereon cursor related actions can be performed. -/// Pass the reference to any screen you want this type to perform actions on. -pub fn cursor<'stdout>(stdout: &'stdout Screen) -> TerminalCursor<'stdout> { - TerminalCursor::new(&stdout.stdout) +pub fn cursor() -> TerminalCursor<'static> { + TerminalCursor::new() +} + +/// Get an TerminalCursor implementation whereon cursor related actions can be performed. +/// Pass the reference to any screen you want this type to perform actions on. +pub fn from_screen<'stdout>(screen: &'stdout Screen) -> TerminalCursor<'stdout> { + TerminalCursor::on_screen(&screen.stdout) } diff --git a/src/modules/cursor/mod.rs b/src/modules/cursor/mod.rs index 8aad5b8..2218291 100644 --- a/src/modules/cursor/mod.rs +++ b/src/modules/cursor/mod.rs @@ -14,7 +14,7 @@ use self::ansi_cursor::AnsiCursor; #[cfg(target_os = "windows")] use self::winapi_cursor::WinApiCursor; -pub use self::cursor::{cursor, TerminalCursor}; +pub use self::cursor::{cursor, from_screen, TerminalCursor}; use super::functions; use TerminalOutput; @@ -30,25 +30,25 @@ use std::sync::Arc; ///! so that cursor related actions can be preformed on both unix and windows systems. trait ITerminalCursor : Sync + Send { /// Goto some location (x,y) in the context. - fn goto(&self, x: u16, y: u16, stdout: &Arc); + fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc>); /// Get the location (x,y) of the current cusror in the context - fn pos(&self, stdout: &Arc) -> (u16, u16); + fn pos(&self) -> (u16, u16); /// Move cursor n times up - fn move_up(&self, count: u16, stdout: &Arc); + fn move_up(&self, count: u16,stdout: &Option<&Arc>); /// Move the cursor `n` times to the right. - fn move_right(&self, count: u16, stdout: &Arc); + fn move_right(&self, count: u16,stdout: &Option<&Arc>); /// Move the cursor `n` times down. - fn move_down(&self, count: u16, stdout: &Arc); + fn move_down(&self, count: u16,stdout: &Option<&Arc>); /// Move the cursor `n` times left. - fn move_left(&self, count: u16, stdout: &Arc); + fn move_left(&self, count: u16,stdout: &Option<&Arc>); /// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct. - fn save_position(&self, stdout: &Arc); + fn save_position(&self,stdout: &Option<&Arc>); /// Return to saved cursor position - fn reset_position(&self, stdout: &Arc); + fn reset_position(&self,stdout: &Option<&Arc>); /// Hide the terminal cursor. - fn hide(&self, stdout: &Arc); + fn hide(&self,stdout: &Option<&Arc>); /// Show the terminal cursor - fn show(&self, stdout: &Arc); + fn show(&self,stdout: &Option<&Arc>); /// Enable or disable the blinking of the cursor. - fn blink(&self, blink: bool, stdout: &Arc); + fn blink(&self, blink: bool,stdout: &Option<&Arc>); } diff --git a/src/modules/cursor/test.rs b/src/modules/cursor/test.rs index 74b0d9a..185a5e0 100644 --- a/src/modules/cursor/test.rs +++ b/src/modules/cursor/test.rs @@ -14,10 +14,11 @@ mod winapi_tests { fn goto_winapi() { let screen = Screen::default(); + let stdout = Some(&screen.stdout); let cursor = WinApiCursor::new(); - cursor.goto(5, 5, &screen.stdout); - let (x, y) = cursor.pos(&screen.stdout); + cursor.goto(5, 5,&stdout); + let (x, y) = cursor.pos(); assert_eq!(x, 5); assert_eq!(y, 5); @@ -27,14 +28,15 @@ mod winapi_tests { fn reset_safe_winapi() { let screen = Screen::default(); + let stdout = Some(&screen.stdout); let cursor = WinApiCursor::new(); - let (x, y) = cursor.pos(&screen.stdout); + let (x, y) = cursor.pos(); - cursor.save_position(&screen.stdout); - cursor.goto(5, 5, &screen.stdout); - cursor.reset_position(&screen.stdout); + cursor.save_position(&stdout); + cursor.goto(5, 5,&stdout); + cursor.reset_position(&stdout); - let (x_saved, y_saved) = cursor.pos(&screen.stdout); + let (x_saved, y_saved) = cursor.pos(); assert_eq!(x, x_saved); assert_eq!(y, y_saved); @@ -47,14 +49,15 @@ fn reset_safe_ansi() { if try_enable_ansi() { let screen = Screen::default(); + let stdout = Some(&screen.stdout); let cursor = AnsiCursor::new(); - let (x, y) = cursor.pos(&screen.stdout); + let (x, y) = cursor.pos(); - cursor.save_position(&screen.stdout); - cursor.goto(5, 5,&screen.stdout); - cursor.reset_position(&screen.stdout); + cursor.save_position(&stdout); + cursor.goto(5, 5,&stdout); + cursor.reset_position(&stdout); - let (x_saved, y_saved) = cursor.pos(&screen.stdout); + let (x_saved, y_saved) = cursor.pos(); assert_eq!(x, x_saved); assert_eq!(y, y_saved); @@ -66,10 +69,11 @@ fn goto_ansi() { if try_enable_ansi() { let screen = Screen::default(); + let stdout = Some(&screen.stdout); let cursor = AnsiCursor::new(); - cursor.goto(5, 5, &screen.stdout); - let (x, y) = cursor.pos(&screen.stdout); + cursor.goto(5, 5,&stdout); + let (x, y) = cursor.pos(); assert_eq!(x, 5); assert_eq!(y, 5); diff --git a/src/modules/cursor/winapi_cursor.rs b/src/modules/cursor/winapi_cursor.rs index 903956c..ad0a509 100644 --- a/src/modules/cursor/winapi_cursor.rs +++ b/src/modules/cursor/winapi_cursor.rs @@ -16,48 +16,49 @@ impl WinApiCursor { } impl ITerminalCursor for WinApiCursor { - fn goto(&self, x: u16, y: u16, stdout: &Arc) { + fn goto(&self, x: u16, y: u16,_stdout: &Option<&Arc>) { cursor::set_console_cursor_position(x as i16, y as i16); } - fn pos(&self, stdout: &Arc) -> (u16, u16) { + fn pos(&self) -> (u16, u16) { cursor::pos() } - fn move_up(&self, count: u16, stdout: &Arc) { - let (xpos, ypos) = self.pos(stdout); - self.goto(xpos, ypos - count, stdout); + fn move_up(&self, count: u16,_stdout: &Option<&Arc>) { + let (xpos, ypos) = self.pos(); + self.goto(xpos, ypos - count, _stdout); } - fn move_right(&self, count: u16, stdout: &Arc) { - let (xpos, ypos) = self.pos(stdout); - self.goto(xpos + count, ypos, stdout); + fn move_right(&self, count: u16,_stdout: &Option<&Arc>) { + let (xpos, ypos) = self.pos(); + self.goto(xpos + count, ypos, _stdout); } - fn move_down(&self, count: u16, stdout: &Arc) { - let (xpos, ypos) = self.pos(stdout); - self.goto(xpos, ypos + count, stdout); + fn move_down(&self, count: u16,_stdout: &Option<&Arc>) { + let (xpos, ypos) = self.pos(); + self.goto(xpos, ypos + count, _stdout); } - fn move_left(&self, count: u16, stdout: &Arc) { - let (xpos, ypos) = self.pos(stdout); - self.goto(xpos - count, ypos, stdout); + fn move_left(&self, count: u16,_stdout: &Option<&Arc>) { + let (xpos, ypos) = self.pos(); + self.goto(xpos - count, ypos, _stdout); } - fn save_position(&self, stdout: &Arc) { + fn save_position(&self,_stdout: &Option<&Arc>) { cursor::save_cursor_pos(); } - fn reset_position(&self, stdout: &Arc) { + fn reset_position(&self,_stdout: &Option<&Arc>) { cursor::reset_to_saved_position(); } - fn hide(&self, stdout: &Arc) { + fn hide(&self,_stdout: &Option<&Arc>) { cursor::cursor_visibility(false); } - fn show(&self, stdout: &Arc) { + fn show(&self,_stdout: &Option<&Arc>) { cursor::cursor_visibility(true); } - fn blink(&self, blink: bool, stdout: &Arc) {} + + fn blink(&self, blink: bool,_stdout: &Option<&Arc>) {} } diff --git a/src/modules/input/input.rs b/src/modules/input/input.rs index 345bfa4..fed00bb 100644 --- a/src/modules/input/input.rs +++ b/src/modules/input/input.rs @@ -13,20 +13,26 @@ use Screen; /// use self::crossterm::Screen; /// use self::crossterm::input; /// -/// let screen = Screen::default(); -/// let input = input(&screen); +/// let input = input(); /// let result = input.read_line(); /// let pressed_char = input.read_char(); /// /// ``` +/// +/// **!! Take note when using input with raw mode you should use the `Screen` type. !!** +/// +/// ``` +/// let screen = Screen::new(true); +/// let input = crossterm::input::from_screen(&screen);/// +/// ``` pub struct TerminalInput<'stdout> { terminal_input: Box, - stdout: &'stdout Arc, + stdout: Option<&'stdout Arc>, } impl<'stdout> TerminalInput<'stdout> { /// Create new instance of TerminalInput whereon input related actions could be preformed. - pub fn new(stdout: &'stdout Arc) -> TerminalInput<'stdout> { + pub fn new() -> TerminalInput<'stdout> { #[cfg(target_os = "windows")] let input = Box::from(WindowsInput::new()); @@ -35,15 +41,28 @@ impl<'stdout> TerminalInput<'stdout> { TerminalInput { terminal_input: input, - stdout: stdout, + stdout: None, + } + } + + /// Create new instance of TerminalInput whereon input related actions could be preformed. + pub fn on_screen(stdout: &'stdout Arc) -> TerminalInput<'stdout> { + #[cfg(target_os = "windows")] + let input = Box::from(WindowsInput::new()); + + #[cfg(not(target_os = "windows"))] + let input = Box::from(UnixInput::new()); + + TerminalInput { + terminal_input: input, + stdout: Some(stdout), } } /// Read one line from the user input. /// /// ```rust - /// let screen = Screen::default(); - /// let input = input(&screen); + /// let input = input(); /// match input.read_line() { /// Ok(s) => println!("string typed: {}", s), /// Err(e) => println!("error: {}", e), @@ -56,8 +75,7 @@ impl<'stdout> TerminalInput<'stdout> { /// Read one character from the user input /// /// ```rust - /// let screen = Screen::default(); - /// let input = input(&screen); + /// let input = input(); /// /// match input.read_char() { /// Ok(c) => println!("character pressed: {}", c), @@ -71,12 +89,12 @@ impl<'stdout> TerminalInput<'stdout> { /// Read the input asynchronously from the user. /// /// This call will not block the current thread. - // Under the hood a thread is fired which will read input on unix systems from TTY and on windows systems with '_getwch' and '_getwche' + /// Under the hood a thread is fired which will read input on unix systems from TTY and on windows systems with '_getwch' and '_getwche' /// /// ```rust /// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them. /// let screen = Screen::new(true); - /// let input = input(&screen); + /// let input = crossterm::input::from_screen(&screen); /// /// let mut stdin = input.read_async().bytes(); /// @@ -108,12 +126,12 @@ impl<'stdout> TerminalInput<'stdout> { /// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them. /// let screen = Screen::new(true); /// - /// let crossterm = Crossterm::new(&screen); + /// // create an instance of `Crossterm` which will preform the actions on the raw screen. + /// let crossterm = Crossterm::from_screen(&screen); /// let input = crossterm.input(); /// let terminal = crossterm.terminal(); /// let mut cursor = crossterm.cursor(); /// - /// /// let mut stdin = input.read_until_async(b'\r').bytes(); /// /// for i in 0..100 { @@ -143,7 +161,12 @@ impl<'stdout> TerminalInput<'stdout> { } /// Get an Terminal Input implementation whereon input related actions can be performed. -/// Pass the reference to any screen you want this type to perform actions on. -pub fn input<'stdout>(stdout: &'stdout Screen) -> TerminalInput<'stdout> { - return TerminalInput::new(&stdout.stdout); +pub fn input<'stdout>() -> TerminalInput<'stdout> { + return TerminalInput::new(); +} + +/// Get an Terminal Input implementation whereon input related actions can be performed. +/// Pass the reference to any screen you want this type to perform actions on. +pub fn from_screen<'stdout>(screen: &'stdout Screen) -> TerminalInput<'stdout> { + TerminalInput::on_screen(&screen.stdout) } diff --git a/src/modules/input/mod.rs b/src/modules/input/mod.rs index 5045c30..4277f78 100644 --- a/src/modules/input/mod.rs +++ b/src/modules/input/mod.rs @@ -30,13 +30,13 @@ use TerminalOutput; /// Unix is using the tty and windows is using libc C functions to read the input. trait ITerminalInput { /// Read one line from the user input - fn read_line(&self, screen_manger: &Arc) -> io::Result; + fn read_line(&self, stdout: &Option<&Arc>) -> io::Result; /// Read one character from the user input - fn read_char(&self, screen_manger: &Arc) -> io::Result; + fn read_char(&self, stdout: &Option<&Arc>) -> io::Result; /// Read the input asynchronously from the user. - fn read_async(&self, screen_manger: &Arc) -> AsyncReader; + fn read_async(&self, stdout: &Option<&Arc>) -> AsyncReader; /// Read the input asynchronously until a certain character is hit. - fn read_until_async(&self, delimiter: u8, screen_manger: &Arc) -> AsyncReader; + fn read_until_async(&self, delimiter: u8, stdout: &Option<&Arc>) -> AsyncReader; } /// This is a wrapper for reading from the input asynchronously. diff --git a/src/modules/input/unix_input.rs b/src/modules/input/unix_input.rs index fd61a22..a65b9b1 100644 --- a/src/modules/input/unix_input.rs +++ b/src/modules/input/unix_input.rs @@ -15,7 +15,7 @@ impl UnixInput { } impl ITerminalInput for UnixInput { - fn read_line(&self, _screen_manger: &Arc) -> io::Result { + fn read_line(&self, __stdout: &Option<&Arc>) -> io::Result { let mut rv = String::new(); io::stdin().read_line(&mut rv)?; let len = rv.trim_right_matches(&['\r', '\n'][..]).len(); @@ -23,11 +23,11 @@ impl ITerminalInput for UnixInput { Ok(rv) } - fn read_char(&self, _screen_manger: &Arc) -> io::Result { + fn read_char(&self, __stdout: &Option<&Arc>) -> io::Result { read_char() } - fn read_async(&self, _screen_manger: &Arc) -> AsyncReader { + fn read_async(&self, __stdout: &Option<&Arc>) -> AsyncReader { let (send, recv) = mpsc::channel(); thread::spawn(move || { @@ -41,7 +41,7 @@ impl ITerminalInput for UnixInput { AsyncReader { recv: recv } } - fn read_until_async(&self, delimiter: u8, _screen_manger: &Arc) -> AsyncReader { + fn read_until_async(&self, delimiter: u8, __stdout: &Option<&Arc>) -> AsyncReader { let (send, recv) = mpsc::channel(); thread::spawn(move || { diff --git a/src/modules/input/windows_input.rs b/src/modules/input/windows_input.rs index 36c66fc..83b2405 100644 --- a/src/modules/input/windows_input.rs +++ b/src/modules/input/windows_input.rs @@ -16,11 +16,14 @@ impl WindowsInput { } impl ITerminalInput for WindowsInput { - fn read_line(&self, screen_manger: &Arc) -> io::Result { + fn read_line(&self, stdout: &Option<&Arc>) -> io::Result { let mut chars: Vec = Vec::new(); loop { - let is_raw_screen = screen_manger.is_in_raw_mode; + let is_raw_screen = match stdout { + Some(output) => output.is_in_raw_mode, + None => false + }; // _getwch is without echo and _getwche is with echo let pressed_char = unsafe { @@ -49,8 +52,11 @@ impl ITerminalInput for WindowsInput { return Ok(chars.into_iter().collect()); } - fn read_char(&self, screen_manger: &Arc) -> io::Result { - let is_raw_screen = screen_manger.is_in_raw_mode; + fn read_char(&self, stdout: &Option<&Arc>) -> io::Result { + let is_raw_screen = match stdout { + Some(output) => output.is_in_raw_mode, + None => false + }; // _getwch is without echo and _getwche is with echo let pressed_char = unsafe { @@ -80,10 +86,13 @@ impl ITerminalInput for WindowsInput { } } - fn read_async(&self, screen_manger: &Arc) -> AsyncReader { + fn read_async(&self, stdout: &Option<&Arc>) -> AsyncReader { let (tx, rx) = mpsc::channel(); - let is_raw_screen = screen_manger.is_in_raw_mode; + let is_raw_screen = match stdout { + Some(output) => output.is_in_raw_mode, + None => false + }; thread::spawn(move || { loop { @@ -108,10 +117,13 @@ impl ITerminalInput for WindowsInput { AsyncReader { recv: rx } } - fn read_until_async(&self, delimiter: u8, screen_manger: &Arc) -> AsyncReader { + fn read_until_async(&self, delimiter: u8, stdout: &Option<&Arc>) -> AsyncReader { let (tx, rx) = mpsc::channel(); - let is_raw_screen = screen_manger.is_in_raw_mode; + let is_raw_screen = match stdout { + Some(output) => output.is_in_raw_mode, + None => false + }; thread::spawn(move || { loop { diff --git a/src/modules/output/output.rs b/src/modules/output/output.rs index a839ac3..f2204f4 100644 --- a/src/modules/output/output.rs +++ b/src/modules/output/output.rs @@ -22,6 +22,7 @@ use super::*; use std::any::Any; use std::default::Default; +use std::io::Write; use screen::RawScreen; /// Struct that is an handle to an terminal screen. @@ -69,6 +70,16 @@ impl TerminalOutput { } } +impl Write for TerminalOutput { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_buf(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.flush() + } +} + impl Default for TerminalOutput { /// Get the default handle to the current screen. diff --git a/src/modules/output/winapi_output.rs b/src/modules/output/winapi_output.rs index c0e0ca8..760e115 100644 --- a/src/modules/output/winapi_output.rs +++ b/src/modules/output/winapi_output.rs @@ -15,7 +15,7 @@ impl WinApiOutput { pub fn new() -> WinApiOutput { - WinApiOutput {} + WinApiOutput } } diff --git a/src/modules/style/ansi_color.rs b/src/modules/style/ansi_color.rs index 294bf30..832ca61 100644 --- a/src/modules/style/ansi_color.rs +++ b/src/modules/style/ansi_color.rs @@ -13,22 +13,22 @@ impl AnsiColor { } impl ITerminalColor for AnsiColor { - fn set_fg(&self, fg_color: Color, stdout: &Arc) { - stdout.write_string(format!( + fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc>) { + functions::write(stdout,format!( csi!("{}m"), self.color_value(fg_color, ColorType::Foreground) )); } - fn set_bg(&self, bg_color: Color, stdout: &Arc) { - stdout.write_string(format!( + fn set_bg(&self, bg_color: Color, stdout: &Option<&Arc>) { + functions::write(stdout,format!( csi!("{}m"), self.color_value(bg_color, ColorType::Background) )); } - fn reset(&self, stdout: &Arc) { - stdout.write_str(csi!("0m")); + fn reset(&self, stdout: &Option<&Arc>) { + functions::write_str(stdout, csi!("0m")); } fn color_value(&self, color: Color, color_type: ColorType) -> String { diff --git a/src/modules/style/color.rs b/src/modules/style/color.rs index 505c07f..38fd301 100644 --- a/src/modules/style/color.rs +++ b/src/modules/style/color.rs @@ -13,11 +13,9 @@ use Screen; /// /// /// ```rust -/// use crossterm::{Screen} /// use crossterm::style::color; /// -/// let screen = Screen::default(); -/// let colored_terminal = color(&screen); +/// let colored_terminal = color(); /// /// // set foreground color /// colored_terminal.set_fg(Color::Red); @@ -25,15 +23,18 @@ use Screen; /// colored_terminal.set_bg(Color::Red); /// // reset color to default /// colored_terminal.reset(); +/// +/// When you want to use 'color' on 'alternate screen' use the `Screen` type instead and pass it to the `color::from_screen()` function. +/// By doing that styling actions will be performed on the alternate screen. /// ``` pub struct TerminalColor<'stdout> { color: Box, - stdout: &'stdout Arc, + stdout: Option<&'stdout Arc>, } impl<'stdout> TerminalColor<'stdout> { /// Create new instance whereon color related actions can be performed. - pub fn new(stdout: &'stdout Arc) -> TerminalColor<'stdout> { + pub fn new() -> TerminalColor<'stdout> { #[cfg(target_os = "windows")] let color = functions::get_module::>( Box::from(WinApiColor::new()), @@ -45,21 +46,36 @@ impl<'stdout> TerminalColor<'stdout> { TerminalColor { color, - stdout: stdout, + stdout: None, + } + } + + /// Create new instance of `TerminalInput` whereon input related actions could be preformed. + pub fn on_screen(stdout: &'stdout Arc) -> TerminalColor<'stdout> { + #[cfg(target_os = "windows")] + let color = functions::get_module::>( + Box::from(WinApiColor::new()), + Box::from(AnsiColor::new()), + ).unwrap(); + + #[cfg(not(target_os = "windows"))] + let color = Box::from(AnsiColor::new()) as Box; + + TerminalColor { + color, + stdout: Some(stdout) } } /// Set the foreground color to the given color. /// /// ```rust - /// let screen = Screen::default(); - /// let colored_terminal = color(&screen); + /// let colored_terminal = color(); /// /// // Set foreground color of the font /// colored_terminal.set_fg(Color::Red); /// // crossterm provides to set the background from &str or String /// colored_terminal.set_fg(Color::from("Red")); - /// /// ``` pub fn set_fg(&self, color: Color) { self.color.set_fg(color, &self.stdout); @@ -68,14 +84,12 @@ impl<'stdout> TerminalColor<'stdout> { /// Set the background color to the given color. /// /// ```rust - /// let screen = Screen::default(); - /// let colored_terminal = color(&screen); + /// let colored_terminal = color(); /// /// // Set background color of the font /// colored_terminal.set_bg(Color::Red); /// // crossterm provides to set the background from &str or String /// colored_terminal.set_bg(Color::from("Red")); - /// /// ``` pub fn set_bg(&self, color: Color) { self.color.set_bg(color, &self.stdout); @@ -84,8 +98,7 @@ impl<'stdout> TerminalColor<'stdout> { /// Reset the terminal colors and attributes to default. /// /// ```rust - /// let screen = Screen::default(); - /// let colored_terminal = color(&screen); + /// let colored_terminal = color(); /// colored_terminal.reset(); /// ``` pub fn reset(&self) { @@ -111,6 +124,13 @@ impl<'stdout> TerminalColor<'stdout> { /// Get an Terminal Color implementation whereon color related actions can be performed. /// Pass the reference to any screen you want this type to perform actions on. -pub fn color<'stdout>(screen: &'stdout Screen) -> TerminalColor<'stdout> { - TerminalColor::new(&screen.stdout) +pub fn color<'stdout>() -> TerminalColor<'stdout> { + TerminalColor::new() +} + + +/// Get an Terminal Color implementation whereon color related actions can be performed. +/// Pass the reference to any screen you want this type to perform actions on. +pub fn from_screen<'stdout>(screen: &'stdout Screen) -> TerminalColor<'stdout> { + TerminalColor::on_screen(&screen.stdout) } diff --git a/src/modules/style/mod.rs b/src/modules/style/mod.rs index 877baca..4b89b6b 100644 --- a/src/modules/style/mod.rs +++ b/src/modules/style/mod.rs @@ -17,7 +17,7 @@ use std::str::FromStr; use std::sync::Arc; use std::fmt::Display; -pub use self::color::{TerminalColor, color}; +pub use self::color::{TerminalColor, color, from_screen}; pub use self::objectstyle::ObjectStyle; pub use self::styledobject::StyledObject; pub use self::styledobject::DisplayableObject; @@ -35,31 +35,32 @@ use TerminalOutput; /// so that color related actions can be preformed on both unix and windows systems. trait ITerminalColor { /// Set the foreground color to the given color. - fn set_fg(&self, fg_color: Color, stdout: &Arc); + fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc>); /// Set the background color to the given color. - fn set_bg(&self, fg_color: Color, stdout: &Arc); + fn set_bg(&self, fg_color: Color, stdout: &Option<&Arc>); /// Reset the terminal color to default. - fn reset(&self, stdout: &Arc); + fn reset(&self, stdout: &Option<&Arc>); /// Gets an value that represents an color from the given `Color` and `ColorType`. fn color_value(&self, color: Color, color_type: ColorType) -> String; } -/// This could be used to style an Displayable with colors and attributes. +/// This could be used to style an `Displayable` type with colors and attributes. /// /// ```rust +/// extern crate crossterm; +/// use crossterm::Crossterm; /// -/// use crossterm::Screen; +/// let crossterm = Crossterm::new(); /// /// // get an styled object which could be painted to the terminal. -/// let styled_object = style("Some Blue colored text on black background").with(Color::Blue).on(Color::Black); -/// -/// // create an default screen. -/// let screen = Screen::default(); +/// let styled_object = crossterm.style("Some Blue colored text on black background") +/// .with(Color::Blue) +/// .on(Color::Black); /// /// // print the styled font * times to the current screen. /// for i in 1..10 /// { -/// styled_object.paint(&screen); +/// println!("{}", styled_object); /// } /// ``` pub fn style<'a,D: 'a>(val: D) -> StyledObject diff --git a/src/modules/style/styledobject.rs b/src/modules/style/styledobject.rs index 3d99215..3d07d9b 100644 --- a/src/modules/style/styledobject.rs +++ b/src/modules/style/styledobject.rs @@ -1,9 +1,10 @@ //! This module contains the logic to style an object that contains some state witch can be styled. -use super::{Color, ObjectStyle}; +use super::{color, from_screen, Color, ObjectStyle}; use Screen; -use std::fmt::Display; +use std::fmt::{self, Display, Formatter}; +use std::io::Write; #[cfg(unix)] use super::Attribute; @@ -15,32 +16,29 @@ pub struct StyledObject { } impl<'a, D: Display + 'a> StyledObject { - /// Set the foreground of the styled object to the passed `Color` + /// Set the foreground of the styled object to the passed `Color`. /// /// ```rust /// use self::crossterm::style::{style,Color}; /// /// // create an styled object with the foreground color red. - /// let styledobject = style("Some colored text").with(Color::Blue); + /// let styledobject = style("Some colored text").with(Color::Red); /// // create an styled object with the foreground color blue. /// let styledobject1 = style("Some colored text").with(Color::Blue); /// - /// let screen = Screen::default(); - /// /// // print the styledobject to see the result - /// styledobject.paint(&screen); - /// styledobject1.paint(&screen); + /// println!("{}", styledobject); + /// println!("{}", styledobject1); /// /// // print an styled object directly. - /// style("Some colored text").with(Color::Blue).paint(&screen); - /// + /// println!("{}", style("Some colored text").on(Color::Blue)); /// ``` pub fn with(mut self, foreground_color: Color) -> StyledObject { self.object_style = self.object_style.fg(foreground_color); self } - /// Set the background of the styled object to the passed `Color` + /// Set the background of the styled object to the passed `Color`. /// /// #Example /// @@ -48,26 +46,23 @@ impl<'a, D: Display + 'a> StyledObject { /// use self::crossterm::style::{style,Color}; /// /// // create an styled object with the background color red. - /// let styledobject = style("Some colored text").on(Color::Blue); + /// let styledobject = style("Some colored text").on(Color::Red); /// // create an styled object with the foreground color blue. /// let styledobject1 = style("Some colored text").on(Color::Blue); /// - /// let screen = Screen::default(); - /// /// // print the styledobject to see the result - /// styledobject.paint(&screen); - /// styledobject1.paint(&screen); + /// println!("{}", styledobject); + /// println!("{}", styledobject1); /// /// // print an styled object directly. - /// style("Some colored text").on(Color::Blue).paint(&screen); - /// + /// println!("{}", style("Some colored text").on(Color::Blue)); /// ``` pub fn on(mut self, background_color: Color) -> StyledObject { self.object_style = self.object_style.bg(background_color); self } - /// Set the attribute of an styled object to the passed `Attribute` + /// Set the attribute of an styled object to the passed `Attribute`. /// /// #Example /// @@ -75,7 +70,7 @@ impl<'a, D: Display + 'a> StyledObject { /// extern crate crossterm; /// use self::crossterm::style::{style,Attribute}; /// - /// style("Some colored text").attr(Attribute::Bold).paint(&screen); + /// println!("{}", style("Some bold text").attr(Attribute::Bold); /// ``` #[cfg(unix)] pub fn attr(mut self, attr: Attribute) -> StyledObject { @@ -138,7 +133,7 @@ impl<'a, D: Display + 'a> StyledObject { self.attr(Attribute::CrossedOut) } - /// This could be used to paint the styled object on the screen. Pass a reference to the screen whereon you want to perform the painting. + /// This could be used to paint the styled object onto the given screen. You have to pass a reference to the screen whereon you want to perform the painting. /// /// ``` rust /// style("Some colored text") @@ -146,9 +141,12 @@ impl<'a, D: Display + 'a> StyledObject { /// .on(Color::Black) /// .paint(&screen); /// ``` + /// + /// You should take not that `StyledObject` implements `Display`. You don't need to call paint unless you are on alternate screen. + /// Checkout `into_displayable()` for more information about this. pub fn paint(&self, screen: &Screen) { - let colored_terminal = ::color(&screen); + let colored_terminal = from_screen(&screen); let mut reset = true; if let Some(bg) = self.object_style.bg_color { @@ -162,7 +160,7 @@ impl<'a, D: Display + 'a> StyledObject { } #[cfg(unix)] - for attr in self.object_style.attrs.iter() { + for attr in self.object_style.attrs.iter() { screen.stdout.write_string(format!(csi!("{}m"), *attr as i16)); reset = true; } @@ -178,13 +176,19 @@ impl<'a, D: Display + 'a> StyledObject { } } - /// this converts an styled object into an `DisplayableObject` witch implements: `Display` and could be used inside the write function of the standard library's. + /// This converts an styled object into an `DisplayableObject` witch implements: `Display` and could be used inside the write function of the standard library. + /// + /// _StyledObject already implements `Display` right?_ + /// + /// This is true, however there are some complex issues why this won't work on alternate screen. + /// That is the reason why this functions exists. + /// You could just pass in the 'screen' from your alternate screen to this method and your `StyledObject` will be printed to the alternate screen just fine. /// /// ``` - /// let screen = Screen::default(); - // let styled_object = style("test").with(Color::Yellow); - // let display_object = styled_object.into_displayable(&screen); - // println!("Colored text: {}. Default color", display_object); + /// let screen = Screen::default(); /* represents the alternate screen */ + /// let styled_object = style("test").with(Color::Yellow); + /// let display_object = styled_object.into_displayable(&screen); + /// println!("Colored text: {}. Default color", display_object); /// ``` pub fn into_displayable(self, screen: &'a Screen) -> DisplayableObject<'a, D> { @@ -192,13 +196,37 @@ impl<'a, D: Display + 'a> StyledObject { } } -use std::fmt::{Formatter, Error}; +impl Display for StyledObject { + fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { + let mut colored_terminal = color(); + let mut reset = true; -/// This is a wrapper for a styled object so that the styled object could be printed with the standard write functions in rust. + if let Some(bg) = self.object_style.bg_color { + colored_terminal.set_bg(bg); + reset = true; + } + if let Some(fg) = self.object_style.fg_color { + colored_terminal.set_fg(fg); + reset = true; + } + + fmt::Display::fmt(&self.content, f)?; + std::io::stdout().flush().expect("Flush stdout failed"); + + if reset { + colored_terminal.reset(); + } + + Ok(()) + } +} + + +/// This is a wrapper for a styled object on alternate screen so that the styled object could be printed on the alternate screen with the standard write functions in rust. /// /// ``` /// write! ("some normal text, {} <- some colored text", DisplayableObject::new(&screen, styled_object)); -/// println! ("some normal text, {} <- some colored text", DisplayableObject::new(&screen, styled_object)) +/// println! ("some normal text, {} <- some colored text", DisplayableObject::new(&screen, styled_object)); /// ``` pub struct DisplayableObject<'a, D:Display + 'a> { @@ -216,7 +244,7 @@ impl <'a, D: Display + 'a> DisplayableObject<'a, D> impl<'a, D: Display + 'a> Display for DisplayableObject<'a, D> { - fn fmt(&self, _f: &mut Formatter) -> Result<(), Error> { + fn fmt(&self, _f: &mut Formatter) -> Result<(), fmt::Error> { self.styled_object.paint(&self.screen); return Ok(()) } diff --git a/src/modules/style/winapi_color.rs b/src/modules/style/winapi_color.rs index 17eb0c5..0f7ceb7 100644 --- a/src/modules/style/winapi_color.rs +++ b/src/modules/style/winapi_color.rs @@ -20,7 +20,7 @@ impl WinApiColor { } impl ITerminalColor for WinApiColor { - fn set_fg(&self, fg_color: Color, stdout: &Arc) { + fn set_fg(&self, fg_color: Color, _stdout: &Option<&Arc>) { let color_value = &self.color_value(fg_color, ColorType::Foreground); let csbi = csbi::get_csbi().unwrap(); @@ -41,7 +41,7 @@ impl ITerminalColor for WinApiColor { kernel::set_console_text_attribute(color); } - fn set_bg(&self, bg_color: Color, stdout: &Arc) { + fn set_bg(&self, bg_color: Color, _stdout: &Option<&Arc>) { let color_value = &self.color_value(bg_color, ColorType::Background); let (csbi, handle) = csbi::get_csbi_and_handle().unwrap(); @@ -62,7 +62,7 @@ impl ITerminalColor for WinApiColor { kernel::set_console_text_attribute(color); } - fn reset(&self, stdout: &Arc) { + fn reset(&self, _stdout: &Option<&Arc>) { kernel::set_console_text_attribute(self.original_color); } diff --git a/src/modules/terminal/ansi_terminal.rs b/src/modules/terminal/ansi_terminal.rs index ed7b599..c1ee532 100644 --- a/src/modules/terminal/ansi_terminal.rs +++ b/src/modules/terminal/ansi_terminal.rs @@ -15,47 +15,49 @@ impl AnsiTerminal { } impl ITerminal for AnsiTerminal { - fn clear(&self, clear_type: ClearType, stdout: &Arc) { + fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc>) { match clear_type { ClearType::All => { - stdout.write_str(csi!("2J")); - TerminalCursor::new(stdout).goto(0,0); + functions::write_str(&stdout,csi!("2J")); + TerminalCursor::new().goto(0,0); } ClearType::FromCursorDown => { - stdout.write_str(csi!("J")); + functions::write_str(&stdout,csi!("J")); } ClearType::FromCursorUp => { - stdout.write_str(csi!("1J")); + functions::write_str(&stdout,csi!("1J")); } ClearType::CurrentLine => { - stdout.write_str(csi!("2K")); + functions::write_str(&stdout,csi!("2K")); } ClearType::UntilNewLine => { - stdout.write_str(csi!("K")); + functions::write_str(&stdout,csi!("K")); } }; } - fn terminal_size(&self, _stdout: &Arc) -> (u16, u16) { + fn terminal_size(&self, _stdout: &Option<&Arc>) -> (u16, u16) { functions::get_terminal_size() } - fn scroll_up(&self, count: i16, stdout: &Arc) { - stdout.write_string(format!(csi!("{}S"), count)); + fn scroll_up(&self, count: i16, stdout: &Option<&Arc>) { + functions::write(&stdout,format!(csi!("{}S"), count)); } - fn scroll_down(&self, count: i16, stdout: &Arc) { - stdout.write_string(format!(csi!("{}T"), count)); + fn scroll_down(&self, count: i16, stdout: &Option<&Arc>) { + functions::write(&stdout,format!(csi!("{}T"), count)); } - fn set_size(&self, width: i16, height: i16, stdout: &Arc) { - stdout.write_string(format!(csi!("8;{};{}t"), height, width)); + fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc>) { + functions::write(&stdout,format!(csi!("8;{};{}t"), height, width)); } - fn exit(&self,stdout: &Arc) { - // drop the screen with the current stdout. This will make sure when in raw mode this will be disabled first. - let screen = Screen::from(stdout.clone()); - drop(screen); - functions::exit_terminal(); + fn exit(&self,stdout: &Option<&Arc>) { + if let Some(output) = stdout { + // drop the screen with the current stdout. This will make sure when in raw mode this will be disabled first. + let screen = Screen::from(output.to_owned().clone()); + drop(screen); + functions::exit_terminal(); + } } } diff --git a/src/modules/terminal/mod.rs b/src/modules/terminal/mod.rs index 493b5f7..aedd9a9 100644 --- a/src/modules/terminal/mod.rs +++ b/src/modules/terminal/mod.rs @@ -13,7 +13,7 @@ use self::ansi_terminal::AnsiTerminal; #[cfg(target_os = "windows")] use self::winapi_terminal::WinApiTerminal; -pub use self::terminal::{terminal, Terminal}; +pub use self::terminal::{terminal, from_screen, Terminal}; use std::sync::Arc; use super::functions; @@ -38,15 +38,15 @@ pub enum ClearType { /// so that color related actions can be preformed on both unix and windows systems. trait ITerminal { /// Clear the current cursor by specifying the clear type - fn clear(&self, clear_type: ClearType, stdout: &Arc); + fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc>); /// Get the terminal size (x,y) - fn terminal_size(&self, stdout: &Arc) -> (u16, u16); + fn terminal_size(&self, stdout: &Option<&Arc>) -> (u16, u16); /// Scroll `n` lines up in the current terminal. - fn scroll_up(&self, count: i16, stdout: &Arc); + fn scroll_up(&self, count: i16, stdout: &Option<&Arc>); /// Scroll `n` lines down in the current terminal. - fn scroll_down(&self, count: i16, stdout: &Arc); + fn scroll_down(&self, count: i16, stdout: &Option<&Arc>); /// Resize terminal to the given width and height. - fn set_size(&self, width: i16, height: i16, stdout: &Arc); + fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc>); /// Close the current terminal - fn exit(&self,stdout: &Arc); + fn exit(&self,stdout: &Option<&Arc>); } diff --git a/src/modules/terminal/terminal.rs b/src/modules/terminal/terminal.rs index 0f49ea6..e0a35c2 100644 --- a/src/modules/terminal/terminal.rs +++ b/src/modules/terminal/terminal.rs @@ -12,22 +12,23 @@ use std::fmt; /// ```rust /// use crossterm::terminal; /// -/// let screen = Screen::default(); -/// let term = terminal(&screen); +/// let term = terminal(); /// /// term.scroll_down(5); /// term.scroll_up(4); /// let (with, height) = term.terminal_size(); /// +/// When you want to use 'terminal' actions on 'alternate screen' use the `Screen` type instead, and pass it to the `terminal::from_screen()` function. +/// By doing that terminal actions will be performed on the alternate screen. /// ``` pub struct Terminal<'stdout> { terminal: Box, - screen: &'stdout Arc, + screen: Option<&'stdout Arc>, } impl<'stdout> Terminal<'stdout> { /// Create new terminal instance whereon terminal related actions can be performed. - pub fn new(screen: &'stdout Arc) -> Terminal<'stdout> { + pub fn new() -> Terminal<'stdout> { #[cfg(target_os = "windows")] let terminal = functions::get_module::>( Box::new(WinApiTerminal::new()), @@ -39,15 +40,31 @@ impl<'stdout> Terminal<'stdout> { Terminal { terminal, - screen: screen, + screen: None, + } + } + + /// Create new instance of TerminalInput whereon input related actions could be preformed. + pub fn on_screen(stdout: &'stdout Arc) -> Terminal<'stdout> { + #[cfg(target_os = "windows")] + let terminal = functions::get_module::>( + Box::new(WinApiTerminal::new()), + Box::new(AnsiTerminal::new()), + ).unwrap(); + + #[cfg(not(target_os = "windows"))] + let terminal = Box::from(AnsiTerminal::new()) as Box; + + Terminal { + terminal, + screen: Some(stdout), } } /// Clear the current cursor by specifying the clear type. /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// // clear all cells in terminal. /// term.clear(terminal::ClearType::All); @@ -67,12 +84,10 @@ impl<'stdout> Terminal<'stdout> { /// Get the terminal size (x,y). /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// let size = term.terminal_size(); /// println!("{:?}", size); - /// /// ``` pub fn terminal_size(&self) -> (u16, u16) { return self.terminal.terminal_size(&self.screen); @@ -81,12 +96,10 @@ impl<'stdout> Terminal<'stdout> { /// Scroll `n` lines up in the current terminal. /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// // scroll up by 5 lines /// let size = term.scroll_up(5); - /// /// ``` pub fn scroll_up(&self, count: i16) { self.terminal.scroll_up(count, &self.screen); @@ -95,12 +108,10 @@ impl<'stdout> Terminal<'stdout> { /// Scroll `n` lines up in the current terminal. /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// // scroll down by 5 lines /// let size = term.scroll_down(5); - /// /// ``` pub fn scroll_down(&self, count: i16) { self.terminal.scroll_down(count, &self.screen); @@ -109,12 +120,10 @@ impl<'stdout> Terminal<'stdout> { /// Set the terminal size. Note that not all terminals can be set to a very small scale. /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// // Set of the size to X: 10 and Y: 10 /// let size = term.set_size(10,10); - /// /// ``` pub fn set_size(&self, width: i16, height: i16) { self.terminal.set_size(width, height, &self.screen); @@ -123,11 +132,9 @@ impl<'stdout> Terminal<'stdout> { /// Exit the current process. /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// let size = term.exit(); - /// /// ``` pub fn exit(&self) { self.terminal.exit(&self.screen); @@ -136,22 +143,26 @@ impl<'stdout> Terminal<'stdout> { /// Write any displayable content to the current terminal screen. /// /// ```rust - /// let screen = Screen::default(); - /// let mut term = terminal(&screen); + /// let mut term = terminal(); /// /// let size = term.write("Some text \n Some text on new line"); - /// /// ``` pub fn write(&self, value: D) { use std::fmt::Write; let mut string = String::new(); write!(string, "{}", value).unwrap(); - self.screen.write_string(string); + functions::write(&self.screen, string); } } /// Get an terminal implementation whereon terminal related actions could performed. /// Pass the reference to any screen you want this type to perform actions on. -pub fn terminal<'stdout>(screen: &'stdout Screen) -> Terminal<'stdout> { - Terminal::new(&screen.stdout) +pub fn terminal<'stdout>() -> Terminal<'stdout> { + Terminal::new() +} + +/// Get an Terminal Color implementation whereon color related actions can be performed. +/// Pass the reference to any screen you want this type to perform actions on. +pub fn from_screen(screen: &Screen) -> Terminal { + Terminal::on_screen(&screen.stdout) } diff --git a/src/modules/terminal/test.rs b/src/modules/terminal/test.rs index cb6751f..129c119 100644 --- a/src/modules/terminal/test.rs +++ b/src/modules/terminal/test.rs @@ -14,11 +14,12 @@ mod winapi_tests { fn resize_winapi() { let screen = Screen::default(); + let stdout = Some(&screen.stdout); let terminal = WinApiTerminal::new(); - terminal.set_size(10, 10, &screen.stdout); + terminal.set_size(10, 10, &stdout); - let (x, y) = terminal.terminal_size(&screen.stdout); + let (x, y) = terminal.terminal_size(&stdout); assert_eq!(x, 10); assert_eq!(y, 10); @@ -32,14 +33,15 @@ fn resize_ansi() use std::{thread, time}; if try_enable_ansi() { let screen = Screen::default(); + let stdout = Some(&screen.stdout); let terminal = AnsiTerminal::new(); - terminal.set_size(50,50, &screen.stdout); + terminal.set_size(50,50, &stdout); // see issue: https://github.com/eminence/terminal-size/issues/11 thread::sleep(time::Duration::from_millis(30)); - let (x, y) = terminal.terminal_size(&screen.stdout); + let (x, y) = terminal.terminal_size(&stdout); assert_eq!(x, 50); assert_eq!(y, 50); diff --git a/src/modules/terminal/winapi_terminal.rs b/src/modules/terminal/winapi_terminal.rs index 9fe6dff..7d1fdd6 100644 --- a/src/modules/terminal/winapi_terminal.rs +++ b/src/modules/terminal/winapi_terminal.rs @@ -19,9 +19,9 @@ impl WinApiTerminal { } impl ITerminal for WinApiTerminal { - fn clear(&self, clear_type: ClearType, stdout: &Arc) { + fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc>) { let csbi = csbi::get_csbi().unwrap(); - let pos = TerminalCursor::new(stdout).pos(); + let pos = TerminalCursor::new().pos(); match clear_type { ClearType::All => { @@ -34,11 +34,11 @@ impl ITerminal for WinApiTerminal { }; } - fn terminal_size(&self, stdout: &Arc) -> (u16, u16) { + fn terminal_size(&self, stdout: &Option<&Arc>) -> (u16, u16) { terminal::terminal_size() } - fn scroll_up(&self, count: i16, stdout: &Arc) { + fn scroll_up(&self, count: i16, stdout: &Option<&Arc>) { let csbi = csbi::get_csbi().unwrap(); // Set srctWindow to the current window size and location. @@ -56,7 +56,7 @@ impl ITerminal for WinApiTerminal { } } - fn scroll_down(&self, count: i16, stdout: &Arc) { + fn scroll_down(&self, count: i16, stdout: &Option<&Arc>) { let csbi = csbi::get_csbi().unwrap(); // Set srctWindow to the current window size and location. let mut srct_window = csbi.srWindow; @@ -74,7 +74,7 @@ impl ITerminal for WinApiTerminal { } /// Set the current terminal size - fn set_size(&self, width: i16, height: i16, stdout: &Arc) { + fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc>) { if width <= 0 { panic!("Cannot set the terminal width lower than 1"); } @@ -150,18 +150,21 @@ impl ITerminal for WinApiTerminal { } } - fn exit(&self, stdout: &Arc) { - // drop the screen with the current stdout. This will make sure when in raw mode this will be disabled first. - let mut screen = Screen::from(stdout.clone()); - drop(screen); - functions::exit_terminal(); + fn exit(&self, stdout: &Option<&Arc>) { + if let Some(output) = stdout + { + // drop the screen with the current stdout. This will make sure when in raw mode this will be disabled first. + let mut screen = Screen::from(output.to_owned().clone()); + drop(screen); + functions::exit_terminal(); + } } } pub fn clear_after_cursor( pos: (u16, u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, - stdout: &Arc, + stdout: &Option<&Arc>, ) { let (mut x, mut y) = pos; @@ -185,7 +188,7 @@ pub fn clear_after_cursor( pub fn clear_before_cursor( pos: (u16, u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, - stdout: &Arc, + stdout: &Option<&Arc>, ) { let (xpos, ypos) = pos; @@ -205,7 +208,7 @@ pub fn clear_before_cursor( clear(start_location, cells_to_write); } -pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, stdout: &Arc) { +pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, stdout: &Option<&Arc>) { // position x at start let x = 0; // position y at start @@ -222,14 +225,22 @@ pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, stdout: &Arc { + // put the cursor back at (0, 0) + TerminalCursor::on_screen(output).goto(0, 0); + } + None => { + // put the cursor back at (0, 0) + TerminalCursor::new().goto(0, 0); + } + } } pub fn clear_current_line( pos: (u16, u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, - stdout: &Arc, + stdout: &Option<&Arc>, ) { // position x at start let x = 0; @@ -248,13 +259,22 @@ pub fn clear_current_line( clear(start_location, cells_to_write); // put the cursor back at 1 cell on current row - TerminalCursor::new(stdout).goto(0, y); + match stdout { + Some(ref output) => { + // put the cursor back at (0, 0) + TerminalCursor::on_screen(output).goto(0, y); + } + None => { + // put the cursor back at (0, 0) + TerminalCursor::new().goto(0, y); + } + } } pub fn clear_until_line( pos: (u16, u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, - stdout: &Arc, + stdout: &Option<&Arc>, ) { let (x, y) = pos; @@ -269,7 +289,16 @@ pub fn clear_until_line( clear(start_location, cells_to_write); // put the cursor back at original cursor position - TerminalCursor::new(stdout).goto(x, y); + match stdout { + Some(ref output) => { + // put the cursor back at (0, 0) + TerminalCursor::on_screen(output).goto(x, y); + } + None => { + // put the cursor back at (0, 0) + TerminalCursor::new().goto(x, y); + } + } } fn clear(start_loaction: COORD, cells_to_write: u32) {