diff --git a/examples/examples.rs b/examples/examples.rs index 61ebbd7..de7673b 100644 --- a/examples/examples.rs +++ b/examples/examples.rs @@ -15,12 +15,13 @@ extern crate crossterm; mod some_types; mod input; + fn main() { // call some test module function - terminal::terminal::resize_terminal(); - - use crossterm::screen::RawScreen; +// terminal::terminal::resize_terminal(); + input::keyboard::async_input::read_async_demo(); +// use crossterm::screen::RawScreen; // RawScreen::into_raw_mode(); // RawScreen::disable_raw_modes(); } diff --git a/examples/input/keyboard/async_input.rs b/examples/input/keyboard/async_input.rs index 9d00495..ffbe1d1 100644 --- a/examples/input/keyboard/async_input.rs +++ b/examples/input/keyboard/async_input.rs @@ -42,7 +42,7 @@ pub fn read_async_until() { } } -/// this will read pressed characters async until `x` is typed . +/// this will read pressed characters async until `x` is typed. pub fn read_async() { let input = input(&Screen::default()); diff --git a/examples/program_examples/first_depth_search/src/algorithm.rs b/examples/program_examples/first_depth_search/src/algorithm.rs index 608d1a6..9ed7edf 100644 --- a/examples/program_examples/first_depth_search/src/algorithm.rs +++ b/examples/program_examples/first_depth_search/src/algorithm.rs @@ -127,10 +127,10 @@ impl<'screen> FirstDepthSearch<'screen> fn find_first_possible_direction(&mut self) { // if there are no elements left in the stack that means we have visited all cell and we van terminate the program. - if let Some(previous_cell) = &self.stack.pop() + if let &Some(previous_cell) = &self.stack.pop() { // update root pos to previous cell and continue searching for new neighbours - self.root_pos = *previous_cell; + self.root_pos = previous_cell; self.choose_random_neighbor(); } else { diff --git a/examples/terminal/alternate_screen.rs b/examples/terminal/alternate_screen.rs index 1a6132a..fbbb1b1 100644 --- a/examples/terminal/alternate_screen.rs +++ b/examples/terminal/alternate_screen.rs @@ -33,7 +33,7 @@ fn print_wait_screen(screen: &Screen) { } } -/// print wait screen on alternate screen, then swich back. +/// print wait screen on alternate screen, then switch back. pub fn print_wait_screen_on_alternate_window() { let screen = Screen::default(); diff --git a/src/common/crossterm.rs b/src/common/crossterm.rs index 463ce75..ccef03c 100644 --- a/src/common/crossterm.rs +++ b/src/common/crossterm.rs @@ -22,56 +22,139 @@ use common::commands::win_commands; use write::Stdout; +/// This type could be used to access the `cursor, terminal, color, input, styling` module more easily. +/// You need to pass a reference to the screen where on you want to perform the actions. +/// +/// +/// #Example +/// If you want to use the default screen you could do it like this: +/// +/// ```rust +/// +/// extern crate crossterm; +/// use crossterm::{Crossterm, Screen}; +/// +/// let crossterm = Crossterm::new(); +/// let cursor = crossterm.cursor(&Screen::default()); +/// +/// ``` +/// +/// If you want to perform actions on the `AlternateScreen` make sure to pass a refrence to the screen of the `AlternateScreen`. +/// +/// ``` +/// /// extern crate crossterm; +/// use crossterm::{Crossterm, Screen}; +/// +/// let main_screen = Screen::default(); +/// +/// if let Ok(alternate_srceen) = main_screen.enable_alternate_modes(false) +/// { +/// let crossterm = Crossterm::new(); +/// let cursor = crossterm.cursor(&alternate_screen.screen); +/// } +/// +/// ``` pub struct Crossterm { } impl<'crossterm> Crossterm { + + /// Create a new instance of `Crossterm` pub fn new() -> Crossterm { Crossterm {} } + /// Get an TerminalCursor implementation whereon cursor related actions can be performed. + /// + /// #Example + /// + /// ```rust + /// + /// extern crate crossterm; + /// use crossterm::{Crossterm, Screen}; + /// + /// let crossterm = Crossterm::new(); + /// let cursor = crossterm.cursor(&Screen::default()); + /// + /// ``` pub fn cursor(&self, screen: &'crossterm Screen) -> cursor::TerminalCursor { cursor::TerminalCursor::new(&screen.stdout.clone()) } + /// Get an TerminalInput implementation whereon terminal related actions can be performed. + /// + /// #Example + /// + /// ```rust + /// + /// extern crate crossterm; + /// use crossterm::{Crossterm, Screen}; + /// use crossterm::terminal; + /// + /// let crossterm = Crossterm::new(); + /// let input = crossterm.input(&Screen::default()); + /// + /// ``` pub fn input(&self, screen: &'crossterm Screen) -> input::TerminalInput { return input::TerminalInput::new(&screen.stdout); } + /// Get an Terminal implementation whereon terminal related actions can be performed. + /// + /// #Example + /// + /// ```rust + /// + /// extern crate crossterm; + /// use crossterm::{Crossterm, Screen}; + /// + /// let crossterm = Crossterm::new(); + /// let mut terminal = crossterm.terminal(&Screen::default()); + /// + /// ``` pub fn terminal(&self, screen: &'crossterm Screen) -> terminal::Terminal { return terminal::Terminal::new(&screen.stdout); } + /// Get an TerminalColor implementation whereon color related actions can be performed. + /// + /// #Example + /// + /// ```rust + /// + /// extern crate crossterm; + /// use crossterm::{Crossterm, Screen}; + /// + /// let crossterm = Crossterm::new(); + /// let mut terminal = crossterm.terminal(&Screen::default()); + /// + /// ``` pub fn color(&self, screen: &'crossterm Screen) -> style::TerminalColor { return style::TerminalColor::new(&screen.stdout); } -// Wraps an displayable object so it can be formatted with colors and attributes. -// -// Check `/examples/color` in the libary for more spesific examples. + /// This could be used to style an Displayable with colors and attributes. + /// + /// #Example + /// + /// ```rust + /// + /// use crossterm::{ Screen }; + /// + /// // 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(); + /// + /// // print the styled font * times to the current screen. + /// for i in 1..10 + /// { + /// styled_object.paint(&screen); + /// } + /// ``` pub fn style(&self, val: D) -> style::StyledObject where D: Display, { style::ObjectStyle::new().apply_to(val) } -} - -//impl Write for Crossterm {M -// fn write(&mut self, buf: &[u8]) -> Result { -// self.active_screen.write_buf(buf) -// } -// -// fn flush(&mut self) -> Result<()> { -// self.active_screen.flush() -// } -//} -// -//impl Drop for Crossterm { -// fn drop(&mut self) { -// if let Some(ref mut screen) = self.alternate_screen { -// screen.disable(&mut self.active_screen); -// } -// if let Some(ref mut raw_terminal) = self.raw_terminal { -// raw_terminal.disable(); -// } -// } -//} +} \ No newline at end of file diff --git a/src/common/functions.rs b/src/common/functions.rs index 1198be9..87349df 100644 --- a/src/common/functions.rs +++ b/src/common/functions.rs @@ -49,16 +49,19 @@ pub fn get_module(winapi_impl: T, unix_impl: T) -> Option { if cfg!(target_os = "windows") { #[cfg(windows)] - use kernel::windows_kernel::ansi_support::try_enable_ansi_support; + use kernel::windows_kernel::ansi_support::{try_enable_ansi_support, windows_supportable}; - // Try to enable ansi on windows if not than use WINAPI. - does_support = try_enable_ansi_support(); + if !windows_supportable() + { + // Try to enable ansi on windows if not than use WINAPI. + does_support = try_enable_ansi_support(); - // uncomment this line when you want to use the winapi implementation. - does_support = false; - if !does_support { - term = Some(winapi_impl); - } + // uncomment this line when you want to use the winapi implementation. +// does_support = false; + if !does_support { + term = Some(winapi_impl); + } + } } if does_support { diff --git a/src/common/screen/alternate.rs b/src/common/screen/alternate.rs index 8bad19e..0dc77e0 100644 --- a/src/common/screen/alternate.rs +++ b/src/common/screen/alternate.rs @@ -5,22 +5,6 @@ //! The alternate buffer is exactly the dimensions of the window, without any scrollback region. //! For an example of this behavior, consider when vim is launched from bash. //! Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged. -//! -//! -//! When using alternate screen there is one thing to keep in mind. -//! To get the functionalities of `cursor, color, terminal` also working on alternate screen. -//! You need to pass it the same `Context` as you have passed to the previous three functions, -//! If you don't use the same `Context` the `cursor(), color(), terminal()` these modules will be using main screen to write to. -//! So you will see nothing on alternate screen. -//! -//! -//! When you want to switch to alternate screen there are a couple of things to keep in mind for it to work correctly. -//! First off some code of how to switch to Alternate screen, for more info check the example folder at github -//! Create alternate screen from `Crossterm`: -//! -//! -//! Todo: example -//! use super::commands::{self, IAlternateScreenCommand}; use super::{functions, Screen, Stdout, RawScreen}; @@ -29,6 +13,7 @@ use std::convert::From; use std::io::{self, Write}; use std::sync::Mutex; +/// With this type you will be able to switch to alternate screen and back to main screen. pub struct AlternateScreen { command: Box, @@ -37,11 +22,19 @@ pub struct AlternateScreen impl AlternateScreen { + /// Create new instance of alternate screen. pub fn new(command: Box, screen: Screen) -> Self { return AlternateScreen { command, screen } } + /// Switch to alternate screen. This function will return an `AlternateScreen` instance if everything went well this type will give you control over the `AlternateScreen`. + /// + /// # What is Alternate screen? + /// *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. + /// The alternate buffer is exactly the dimensions of the window, without any scrollback region. + /// For an example of this behavior, consider when vim is launched from bash. + /// Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged. pub fn to_alternate_screen(screen_manager: Stdout) -> io::Result { #[cfg(target_os = "windows")] let command = functions::get_module::>( @@ -57,6 +50,7 @@ impl AlternateScreen { return Ok(AlternateScreen::new(command, Screen::from(stdout))); } + /// Switch the alternate screen back to main screen. pub fn to_main_screen(&self) -> io::Result<()> { self.command.disable(&self.screen.stdout)?; Ok(()) @@ -65,8 +59,8 @@ impl AlternateScreen { impl Drop for AlternateScreen { + /// This will switch back to main screen on drop. fn drop(&mut self) { self.to_main_screen(); - } } diff --git a/src/common/screen/raw.rs b/src/common/screen/raw.rs index 5e68a86..79c3495 100644 --- a/src/common/screen/raw.rs +++ b/src/common/screen/raw.rs @@ -9,6 +9,8 @@ //! - Characters //! The characters are not processed by the terminal driver, but are sent straight through. //! Special character have no meaning, like backspace will not be interpret as backspace but instead will be directly send to the terminal. +//! - Escape characters +//! Note that in raw modes `\n` 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. //! //! With these modes you can easier design the terminal screen. @@ -18,16 +20,10 @@ use super::{functions, Screen, Stdout}; use std::io::{self, Write}; /// A wrapper for the raw terminal state. Which can be used to write to. -pub struct RawScreen -{ -// #[cfg(not(target_os = "windows"))] -// command: unix_command::RawModeCommand, -// #[cfg(not(target_os = "windows"))] -// command: win_commands::RawModeCommand, - -} +pub struct RawScreen; impl RawScreen { + /// Put terminal in raw mode. pub fn into_raw_mode() -> io::Result<()> { #[cfg(not(target_os = "windows"))] @@ -35,12 +31,11 @@ impl RawScreen { #[cfg(target_os = "windows")] let mut command = win_commands::RawModeCommand::new(); -// command::new(); command.enable()?; - Ok(()) } + /// Put terminal back in original modes. pub fn disable_raw_modes() -> io::Result<()> { #[cfg(not(target_os = "windows"))] @@ -48,9 +43,7 @@ impl RawScreen { #[cfg(target_os = "windows")] let mut command = win_commands::RawModeCommand::new(); - let a = command.disable(); - - + command.disable()?; return Ok(()) } } diff --git a/src/common/screen/screen.rs b/src/common/screen/screen.rs index 1580609..fbf5b7b 100644 --- a/src/common/screen/screen.rs +++ b/src/common/screen/screen.rs @@ -13,6 +13,42 @@ use std::io::Write; use std::io::Result; use std::sync::Arc; +/// This type represents an screen. +/// This screen has an stdout which is used by the program to write to or to execute commands with. +/// +/// 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()`. +/// +/// 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. +/// +/// #Example +/// +/// ```rust +/// // create default screen. +/// 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 raw alternate screen from normal screen. +/// let screen = Screen::new(); +/// +/// if let Ok(alternate_screen) = screen.enable_alternate_modes(true) +/// { +/// let crossterm = Crossterm::new(); +/// +/// // make sure to pass in the screen of the AlternateScreen. +/// crossterm.cursor(&alternate_screen.screen); +/// } +/// ``` +/// pub struct Screen { buffer: Vec, @@ -21,6 +57,8 @@ pub struct Screen impl Screen { + /// Create new instance of the Screen also specify if the current screen should be in raw mode or normal mode. Check out `RawScreen` type for more info. + /// If you are not sure what raw mode is then pass false or use the `Screen::default()` to create an instance. pub fn new(raw_mode: bool) -> Screen { if raw_mode @@ -32,16 +70,33 @@ impl Screen return Screen::default(); } - pub fn from(stdout: Stdout) -> Screen - { - return Screen { stdout: Arc::new(stdout), buffer: Vec::new() }; - } - + /// This method could be used for enabling raw mode for the terminal. + /// + /// What exactly is raw state: + /// - No line buffering. + /// Normally the terminals uses line buffering. This means that the input will be send to the terminal line by line. + /// With raw mode the input will be send one byte at a time. + /// - Input + /// All input has to be written manually by the programmer. + /// - Characters + /// The characters are not processed by the terminal driver, but are sent straight through. + /// Special character have no meaning, like backspace will not be interpret as backspace but instead will be directly send to the terminal. + /// - Escape characters + /// Note that in raw modes `\n` 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. + /// + /// With these modes you can easier design the terminal screen. pub fn enable_raw_modes(&self) -> Result<()> { RawScreen::into_raw_mode()?; return Ok(()) } + /// Switch to alternate screen. This function will return an `AlternateScreen` instance if everything went well this type will give you control over the `AlternateScreen`. + /// + /// # What is Alternate screen? + /// *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. + /// The alternate buffer is exactly the dimensions of the window, without any scrollback region. + /// For an example of this behavior, consider when vim is launched from bash. + /// Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged. pub fn enable_alternate_modes(&self, raw_mode: bool) -> Result { let mut stdout = Stdout::new(raw_mode); @@ -55,8 +110,25 @@ impl Screen } } +impl From for Screen +{ + /// Create an screen with the given `Stdout` + fn from(stdout: Stdout) -> Self { + return Screen { stdout: Arc::new(stdout), buffer: Vec::new() }; + } +} + +impl From> for Screen +{ + /// Create an screen with the given 'Arc' + fn from(stdout: Arc) -> Self { + return Screen { stdout: stdout, buffer: Vec::new() }; + } +} + impl Default for Screen { + /// Create an new screen which will not be in raw mode or alternate mode. fn default() -> Self { return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() }; } @@ -64,6 +136,7 @@ impl Default for Screen impl Drop for Screen { + /// If the current screen is in raw mode whe need to disable it when the instance goes out of scope. fn drop(&mut self) { if self.stdout.is_in_raw_mode { @@ -74,11 +147,15 @@ impl Drop for Screen impl Write for 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. fn write(&mut self, buf: &[u8]) -> Result { self.buffer.write(buf); Ok(buf.len()) } + /// Flush the internal buffer to the screen. fn flush(&mut self) -> Result<()> { self.stdout.write_buf(&self.buffer); self.stdout.flush() diff --git a/src/modules/cursor/cursor.rs b/src/modules/cursor/cursor.rs index ecb01b3..24e1c23 100644 --- a/src/modules/cursor/cursor.rs +++ b/src/modules/cursor/cursor.rs @@ -9,6 +9,7 @@ use std::fmt::Display; use std::io::Write; use std::sync::Arc; + /// Struct that stores an specific platform implementation for cursor related actions. /// /// Check `/examples/version/cursor` in the library for more specific examples. @@ -17,22 +18,19 @@ use std::sync::Arc; /// /// ```rust /// -/// extern crate crossterm; -/// use self::crossterm::Crossterm; +/// extern crate crossterm; +/// use self::crossterm::cursor::cursor; /// -/// let term = Crossterm::new(); -/// let mut cursor = term.cursor(); +/// 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); -/// -/// // or in one line -/// cursor.goto(5,5).move_left(2).move_right(2).print("10"); +/// /// ``` pub struct TerminalCursor { screen: Arc, @@ -62,11 +60,10 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); + /// let cursor = cursor(&Screen::default()); /// - /// // change the cursor to position, x: 4 and y: 5 - /// cursor.goto(4,5); + /// // change the cursor to position, x: 4 and y: 5 + /// cursor.goto(4,5); /// /// ``` pub fn goto(&self, x: u16, y: u16) { @@ -78,12 +75,11 @@ impl TerminalCursor { /// #Example /// /// ```rust + /// + /// let cursor = cursor(&Screen::default()); /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// - /// // get the current cursor pos - /// let (x,y) = cursor.pos(); + /// // get the current cursor pos + /// let (x,y) = cursor.pos(); /// /// ``` pub fn pos(&self) -> (u16, u16) { @@ -95,11 +91,9 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// - /// // Move the cursor to position 3 times to the up in the terminal - /// cursor.move_up(3); + /// let cursor = cursor(&Screen::default()); + /// // 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 { @@ -113,10 +107,10 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// // Move the cursor to position 3 times to the right in the terminal - /// cursor.move_right(3); + /// let cursor = cursor(&Screen::default()); + /// + /// // 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 { @@ -130,11 +124,10 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); + /// let cursor = cursor(&Screen::default()); /// - /// // Move the cursor to position 3 times to the down in the terminal - /// cursor.move_down(3); + /// // 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 { @@ -148,8 +141,7 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); + /// let cursor = cursor(&Screen::default()); /// /// // Move the cursor to position 3 times to the left in the terminal /// cursor.move_left(3); @@ -168,9 +160,7 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// + /// let cursor = cursor(&Screen::default()); /// cursor.safe_position(); /// /// ``` @@ -186,9 +176,7 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// + /// let cursor = cursor(&Screen::default()); /// cursor.reset_position(); /// /// ``` @@ -202,9 +190,7 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// + /// let cursor = cursor(&Screen::default()); /// cursor.hide(); /// /// ``` @@ -218,9 +204,7 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// + /// let cursor = cursor(&Screen::default()); /// cursor.show(); /// /// ``` @@ -236,9 +220,7 @@ impl TerminalCursor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let cursor = crossterm.cursor(); - /// + /// let cursor = cursor(&Screen::default()); /// cursor.blink(true); /// cursor.blink(false); /// @@ -249,6 +231,7 @@ impl TerminalCursor { } /// 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(screen_manager: &Screen) -> TerminalCursor { TerminalCursor::new(&screen_manager.stdout) } diff --git a/src/modules/cursor/mod.rs b/src/modules/cursor/mod.rs index 02e6a3c..8c08aae 100644 --- a/src/modules/cursor/mod.rs +++ b/src/modules/cursor/mod.rs @@ -45,6 +45,6 @@ pub trait ITerminalCursor { fn hide(&self, screen_manager: &Arc); /// Show the terminal cursor fn show(&self, screen_manager: &Arc); - /// enable or disable the blinking of the cursor. + /// Enable or disable the blinking of the cursor. fn blink(&self, blink: bool, screen_manager: &Arc); } diff --git a/src/modules/input/input.rs b/src/modules/input/input.rs index 4c5bd3b..3168669 100644 --- a/src/modules/input/input.rs +++ b/src/modules/input/input.rs @@ -7,18 +7,16 @@ use super::*; /// Struct that stores an specific platform implementation for input related actions. /// -/// Check `/examples/version/input` the examples folder on github for more info. +/// Check `/examples/input` the examples folder on github for more info. /// /// #Example /// /// ```rust /// /// extern crate crossterm; -/// use self::crossterm::Crossterm; -/// -/// let crossterm = Crossterm::new(); -/// let input = crossterm.input(); +/// use self::crossterm::input::input; /// +/// let input = input(&Screen::default()); /// let result = input.read_line(); /// let pressed_char = input.read_char(); /// @@ -48,8 +46,8 @@ impl TerminalInput{ /// #Example /// /// ```rust - /// let crossterm = Crossterm::new(); - /// match crossterm.input().read_line() { + /// + /// match input(&Screen::default()).read_line() { /// Ok(s) => println!("string typed: {}", s), /// Err(e) => println!("error: {}", e), /// } @@ -64,11 +62,11 @@ impl TerminalInput{ /// #Example /// /// ```rust - /// let crossterm = Crossterm::new(); - /// match crossterm.input().read_char() { + /// + /// match crossterm.input(&Screen::default()).read_char() { /// Ok(c) => println!("character pressed: {}", c), /// Err(e) => println!("error: {}", e), - // } + /// } /// /// ``` pub fn read_char(&self) -> io::Result { @@ -80,12 +78,14 @@ impl TerminalInput{ /// #Example /// /// ```rust - /// let crossterm = Crossterm::new(); + /// + /// use crossterm::{Crossterm, Screen} /// /// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them. - /// crossterm.enable_raw_mode(); + /// let screen = Screen::new(true); + /// let crossterm = Crossterm::new(); /// - /// let mut stdin = crossterm.input().read_async().bytes(); + /// let mut stdin = crossterm.input(&screen).read_async().bytes(); /// /// for i in 0..100 { /// @@ -112,13 +112,14 @@ impl TerminalInput{ /// #Example /// /// ```rust - /// let crossterm = Crossterm::new(); - /// let input = crossterm.input(); - /// let terminal = crossterm.terminal(); - /// let mut cursor = crossterm.cursor(); - /// /// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them. - /// crossterm.enable_raw_mode(); + /// let screen = Screen::new(true); + /// + /// let crossterm = Crossterm::new(); + /// let input = crossterm.input(&screen); + /// let terminal = crossterm.terminal(&screen); + /// let mut cursor = crossterm.cursor(&screen); + /// /// /// let mut stdin = input.read_until_async(b'\r').bytes(); /// @@ -149,6 +150,7 @@ impl TerminalInput{ } /// 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: &Screen) -> TerminalInput { return TerminalInput::new(&stdout.stdout); } diff --git a/src/modules/input/mod.rs b/src/modules/input/mod.rs index b026e36..76a5576 100644 --- a/src/modules/input/mod.rs +++ b/src/modules/input/mod.rs @@ -16,7 +16,7 @@ use self::windows_input::WindowsInput; pub use self::input::{input, TerminalInput}; use super::Stdout; -use std::io::{self, Read}; +use std::io::{self, Read, Error, ErrorKind}; use std::sync::{mpsc, Arc}; use Screen; @@ -60,13 +60,13 @@ impl Read for AsyncReader { break; } - match self.recv.try_recv() { - Ok(Ok(b)) => { - buf[total] = b; + match self.recv.try_iter().next() { + Some(Ok(value)) => { + buf[total] = value; total += 1; - } - Ok(Err(e)) => return Err(e), - Err(_) => break, + }, + _ => return Err(Error::new(ErrorKind::Other, "No characters pressed.")), + } } diff --git a/src/modules/style/color.rs b/src/modules/style/color.rs index d62ee3c..2220eb5 100644 --- a/src/modules/style/color.rs +++ b/src/modules/style/color.rs @@ -13,8 +13,8 @@ use Screen; /// /// ```rust /// -/// let crossterm = Crossterm::new(); -/// let colored_terminal = crossterm.color(); +/// use crossterm::{Screen, Crossterm} +/// let colored_terminal = crossterm.color(&Screen::default()); /// /// // set foreground color /// colored_terminal.set_fg(Color::Red); @@ -52,8 +52,7 @@ impl<'terminal> TerminalColor { /// #Example /// /// ```rust - /// let crossterm = Crossterm::new(); - /// let colored_terminal = crossterm.color(); + /// let colored_terminal = crossterm.color(&Screen::default()); /// /// // Set foreground color of the font /// colored_terminal.set_fg(Color::Red); @@ -71,8 +70,7 @@ impl<'terminal> TerminalColor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let colored_terminal = crossterm.color(); + /// let colored_terminal = crossterm.color(&Screen::default()); /// /// // Set background color of the font /// colored_terminal.set_bg(Color::Red); @@ -89,9 +87,7 @@ impl<'terminal> TerminalColor { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let colored_terminal = crossterm.color(); - /// + /// let colored_terminal = crossterm.color(&Screen::default()); /// colored_terminal.reset(); /// /// ``` @@ -117,6 +113,7 @@ impl<'terminal> TerminalColor { } /// 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(screen: &Screen) -> TerminalColor { TerminalColor::new(&screen.stdout) } diff --git a/src/modules/style/mod.rs b/src/modules/style/mod.rs index 9742b0d..f6f63f1 100644 --- a/src/modules/style/mod.rs +++ b/src/modules/style/mod.rs @@ -41,6 +41,26 @@ pub trait ITerminalColor { fn color_value(&self, color: Color, color_type: ColorType) -> String; } +/// This could be used to style an Displayable with colors and attributes. +/// +/// #Example +/// +/// ```rust +/// +/// use crossterm::Screen; +/// +/// // 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(); +/// +/// // print the styled font * times to the current screen. +/// for i in 1..10 +/// { +/// styled_object.paint(&screen); +/// } +/// ``` pub fn style(val: D) -> StyledObject where D: Display, { @@ -105,12 +125,14 @@ pub enum ColorType { } impl<'a> From<&'a str> for Color { + /// Get an color from an &str like `Color::from("blue")` fn from(src: &str) -> Self { src.parse().unwrap_or(Color::White) } } impl From for Color { + /// Get an color from an &str like `Color::from(String::from(blue))` fn from(src: String) -> Self { src.parse().unwrap_or(Color::White) } @@ -119,6 +141,7 @@ impl From for Color { impl FromStr for Color { type Err = (); + /// Convert a string to an Color value fn from_str(src: &str) -> Result { let src = src.to_lowercase(); diff --git a/src/modules/style/styledobject.rs b/src/modules/style/styledobject.rs index 5ef7658..8dfc655 100644 --- a/src/modules/style/styledobject.rs +++ b/src/modules/style/styledobject.rs @@ -24,19 +24,21 @@ impl StyledObject { /// #Example /// /// ```rust - /// extern crate crossterm; - /// use self::crossterm::style::{paint,Color}; + /// use self::crossterm::style::{style,Color}; /// /// // create an styled object with the foreground color red. - /// let styledobject = paint("I am colored red").with(Color::Red); + /// let styledobject = style("Some colored text").with(Color::Blue); /// // create an styled object with the foreground color blue. - /// let styledobject1 = paint("I am colored blue").with(Color::Blue); + /// let styledobject1 = style("Some colored text").with(Color::Blue); + /// + /// let screen = Screen::default(); /// /// // print the styledobject to see the result - /// println!("{}", styledobject); - /// println!("{}", styledobject1); + /// styledobject.paint(&screen); + /// styledobject1.paint(&screen); + /// /// // print an styled object directly. - /// println!("{}", paint("I am colored green").with(Color::Green)); + /// style("Some colored text").with(Color::Blue).paint(&screen); /// /// ``` pub fn with(mut self, foreground_color: Color) -> StyledObject { @@ -49,19 +51,21 @@ impl StyledObject { /// #Example /// /// ```rust - /// extern crate crossterm; - /// use self::crossterm::style::{paint,Color}; + /// use self::crossterm::style::{style,Color}; /// /// // create an styled object with the background color red. - /// let styledobject = paint("I am colored red").on(Color::Red); - /// // create an styled object with the background color blue. - /// let styledobject1 = paint("I am colored blue").on(Color::Blue); + /// let styledobject = style("Some colored text").on(Color::Blue); + /// // 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); /// - /// // print the styledobjects - /// println!("{}", styledobject); - /// println!("{}", styledobject1); /// // print an styled object directly. - /// println!("{}", paint("I am colored green").on(Color::Green)) + /// style("Some colored text").on(Color::Blue).paint(&screen); /// /// ``` pub fn on(mut self, background_color: Color) -> StyledObject { @@ -76,9 +80,9 @@ impl StyledObject { /// ```rust /// /// extern crate crossterm; - /// use self::crossterm::style::{paint,Attribute}; + /// use self::crossterm::style::{style,Attribute}; /// - /// println!("{}", paint("Bold").attr(Attribute::Bold)); + /// style("Some colored text").attr(Attribute::Bold).paint(&screen); /// /// ``` #[cfg(unix)] @@ -142,6 +146,14 @@ impl StyledObject { self.attr(Attribute::CrossedOut) } + /// This could be used to paint the styled object on the screen. Pass a refrence to the screen whereon you want to perform the painting. + /// + /// ``` rust + /// style("Some colored text") + /// .with(Color::Blue) + /// .on(Color::Black) + /// .paint(&screen); + /// ``` pub fn paint(&self, screen: &Screen) { let mut colored_terminal = super::super::super::style::color::color(&screen); diff --git a/src/modules/terminal/ansi_terminal.rs b/src/modules/terminal/ansi_terminal.rs index 556c1bf..51db870 100644 --- a/src/modules/terminal/ansi_terminal.rs +++ b/src/modules/terminal/ansi_terminal.rs @@ -50,7 +50,10 @@ impl ITerminal for AnsiTerminal { screen_manager.write_string(format!(csi!("8;{};{}t"), width, height)); } - fn exit(&self) { + fn exit(&self,screen_manager: &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(screen_manager.clone()); + drop(screen); functions::exit_terminal(); } } diff --git a/src/modules/terminal/mod.rs b/src/modules/terminal/mod.rs index df14431..0d7a0c5 100644 --- a/src/modules/terminal/mod.rs +++ b/src/modules/terminal/mod.rs @@ -44,5 +44,5 @@ pub trait ITerminal { /// Resize terminal to the given width and height. fn set_size(&self, width: i16, height: i16, screen_manager: &Arc); /// Close the current terminal - fn exit(&self); + fn exit(&self,screen_manager: &Arc); } diff --git a/src/modules/terminal/terminal.rs b/src/modules/terminal/terminal.rs index c3423de..68c76e0 100644 --- a/src/modules/terminal/terminal.rs +++ b/src/modules/terminal/terminal.rs @@ -14,8 +14,9 @@ use std::io::Write; /// /// ```rust /// -/// let crossterm = Crossterm::new(); -/// let term = crossterm.terminal(); +/// use crossterm::terminal::terminal; +/// +/// let term = terminal(); /// /// term.scroll_down(5); /// term.scroll_up(4); @@ -51,8 +52,7 @@ impl Terminal { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// // clear all cells in terminal. /// term.clear(terminal::ClearType::All); @@ -76,12 +76,7 @@ impl Terminal { /// /// ```rust /// - /// extern crate crossterm; - /// use crossterm::terminal; - /// use crossterm::Context; - /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// let size = term.terminal_size(); /// println!("{:?}", size); @@ -97,8 +92,7 @@ impl Terminal { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// // scroll up by 5 lines /// let size = term.scroll_up(5); @@ -114,8 +108,7 @@ impl Terminal { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// // scroll down by 5 lines /// let size = term.scroll_down(5); @@ -131,8 +124,7 @@ impl Terminal { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// // Set of the size to X: 10 and Y: 10 /// let size = term.set_size(10,10); @@ -148,14 +140,13 @@ impl Terminal { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// let size = term.exit(); /// /// ``` pub fn exit(&self) { - self.terminal.exit(); + self.terminal.exit(&self.screen); } /// Write any displayable content to the current terminal screen. @@ -164,8 +155,7 @@ impl Terminal { /// /// ```rust /// - /// let crossterm = Crossterm::new(); - /// let term = crossterm.terminal(); + /// let term = terminal(); /// /// let size = term.write("Some text \n Some text on new line"); /// @@ -178,7 +168,8 @@ impl Terminal { } } -/// Get an terminal implementation whereon terminal related actions could performed +/// 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(screen: &Screen) -> Terminal { Terminal::new(&screen.stdout) } diff --git a/src/modules/terminal/winapi_terminal.rs b/src/modules/terminal/winapi_terminal.rs index 8fc073f..714242c 100644 --- a/src/modules/terminal/winapi_terminal.rs +++ b/src/modules/terminal/winapi_terminal.rs @@ -152,7 +152,10 @@ impl ITerminal for WinApiTerminal { } } - fn exit(&self) { + fn exit(&self, screen_manager: &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(screen_manager.clone()); + drop(screen); functions::exit_terminal(); } } diff --git a/src/modules/write/ansi_stdout.rs b/src/modules/write/ansi_stdout.rs index 8d880bf..2a4bb7c 100644 --- a/src/modules/write/ansi_stdout.rs +++ b/src/modules/write/ansi_stdout.rs @@ -10,7 +10,7 @@ use std::sync::{Arc,Mutex}; use std::io::{self, Read, Write,Stdout, stdout}; use std::str::from_utf8; -/// This struct is an ANSI escape code implementation for screen related actions. +/// This struct is a wrapper for `Stdout` pub struct AnsiStdout { pub handle: Stdout, } @@ -35,7 +35,6 @@ impl IStdout for AnsiStdout { let out = &self.handle; let mut handle = out.lock(); handle.flush(); - Ok(()) } diff --git a/src/modules/write/mod.rs b/src/modules/write/mod.rs index 2fe75f3..ce9e9a6 100644 --- a/src/modules/write/mod.rs +++ b/src/modules/write/mod.rs @@ -1,22 +1,4 @@ -//! This module provides one place to work with the screen. -//! -//! In Rust we can call `stdout()` to get an handle to the current default console handle. -//! For example when in unix systems you want to print something to the main screen you can use the following code: -//! -//! ``` -//! write!(std::io::stdout(), "{}", "some text"). -//! ``` -//! -//! But things change when we are in alternate screen modes. -//! We can not simply use `stdout()` to get a handle to the alternate screen, since this call returns the current default console handle (mainscreen). -//! -//! Instead we need to store an handle to the screen output. -//! This handle could be used to put into alternate screen modes and back into main screen modes. -//! Through this stored handle Crossterm can execute its command on the current screen whether it be alternate screen or main screen. -//! -//! For unix systems we store the handle gotten from `stdout()` for windows systems that are not supporting ANSI escape codes we store WinApi `HANDLE` struct witch will provide access to the current screen. -//! -//! This is the reason why this module exits: it is to provide access to the current terminal screen whether it will be the alternate screen and main screen. +//! This module provides a way to work with an handle to an screen on different platforms. mod stdout; @@ -35,8 +17,8 @@ use std::io; use super::{functions}; -/// This trait defines the actions that could be preformed on the current screen. -/// This trait can be implemented so that an concrete implementation of the IScreenManager can forfill +/// This trait defines represents an stdout of an screen. +/// This trait can be implemented so that an concrete implementation of the IStdout can forfill /// the wishes to work on an specific platform. /// /// ## For example: @@ -44,7 +26,7 @@ use super::{functions}; /// This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific), /// so that color related actions can be preformed on both unix and windows systems. pub trait IStdout { - /// Write a &str to the current stdout. + /// Write an &str to the current stdout and flush the screen. fn write_str(&self, string: &str ) -> io::Result; /// Write [u8] buffer to console. fn write(&self, buf: &[u8]) -> io::Result; @@ -52,6 +34,5 @@ pub trait IStdout { fn flush(&self) -> io::Result<()>; fn as_any(&self) -> &Any; - fn as_any_mut(&mut self) -> &mut Any; } diff --git a/src/modules/write/stdout.rs b/src/modules/write/stdout.rs index 7d6ce30..15fdf53 100644 --- a/src/modules/write/stdout.rs +++ b/src/modules/write/stdout.rs @@ -23,13 +23,17 @@ use super::*; use std::any::Any; use std::fmt::Display; use std::io::{self, Write}; +use std::default::Default; #[cfg(target_os = "windows")] use winapi::um::winnt::HANDLE; use std::sync::Arc; -/// Struct that stores an specific platform implementation for screen related actions. +/// Struct that is an handle to an terminal screen. +/// This handle could be used to write to the current screen +/// +/// For unix and windows 10 `stdout()` will be used for handle when on windows systems with versions lower than 10 WinApi `HANDLE` will be used. pub struct Stdout { screen_manager: Box, pub is_in_raw_mode:bool, @@ -67,6 +71,7 @@ impl Stdout { self.screen_manager.write_str(string) } + /// Write buffer to the screen pub fn write_buf(&self, buf: &[u8]) -> io::Result { self.screen_manager.write(buf) } @@ -74,8 +79,24 @@ impl Stdout { pub fn as_any(&self) -> &Any { self.screen_manager.as_any() } - pub fn as_any_mut(&mut self) -> &mut Any { self.screen_manager.as_any_mut() } } + +impl Default for Stdout +{ + /// Get the default handle to the current screen. + fn default() -> Self { + #[cfg(target_os = "windows")] + let screen_manager = functions::get_module::>( + Box::from(WinApiStdout::new()), + Box::from(AnsiStdout::new()), + ).unwrap(); + + #[cfg(not(target_os = "windows"))] + let screen_manager = Box::from(AnsiStdout::new()) as Box; + + Stdout { screen_manager , is_in_raw_mode: false} + } +} diff --git a/src/modules/write/winapi_stdout.rs b/src/modules/write/winapi_stdout.rs index 7f521bc..40966f3 100644 --- a/src/modules/write/winapi_stdout.rs +++ b/src/modules/write/winapi_stdout.rs @@ -8,7 +8,7 @@ use std::any::Any; use std::io::{self, Write}; use std::sync::Arc; -/// This struct is an WINAPI implementation for screen related actions. +/// This struct is a wrapper for WINAPI `HANDLE` pub struct WinApiStdout { pub handle: HANDLE, }