Updated all examples and comments tested unix logic

This commit is contained in:
= 2018-08-13 21:04:07 +02:00
parent f31bb1a656
commit d23ef22a58
24 changed files with 395 additions and 229 deletions

View File

@ -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();
}

View File

@ -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());

View File

@ -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 {

View File

@ -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();

View File

@ -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<D>(&self, val: D) -> style::StyledObject<D>
where
D: Display, {
style::ObjectStyle::new().apply_to(val)
}
}
//impl Write for Crossterm {M
// fn write(&mut self, buf: &[u8]) -> Result<usize> {
// 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();
// }
// }
//}
}

View File

@ -49,16 +49,19 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
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 {

View File

@ -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<IAlternateScreenCommand + Send>,
@ -37,11 +22,19 @@ pub struct AlternateScreen
impl AlternateScreen {
/// Create new instance of alternate screen.
pub fn new(command: Box<IAlternateScreenCommand + Send>, 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<AlternateScreen> {
#[cfg(target_os = "windows")]
let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Send>>(
@ -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();
}
}

View File

@ -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(())
}
}

View File

@ -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<u8>,
@ -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<AlternateScreen> {
let mut stdout = Stdout::new(raw_mode);
@ -55,8 +110,25 @@ impl Screen
}
}
impl From<Stdout> 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<Arc<Stdout>> for Screen
{
/// Create an screen with the given 'Arc<Stdout>'
fn from(stdout: Arc<Stdout>) -> 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<usize> {
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()

View File

@ -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<Stdout>,
@ -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)
}

View File

@ -45,6 +45,6 @@ pub trait ITerminalCursor {
fn hide(&self, screen_manager: &Arc<Stdout>);
/// Show the terminal cursor
fn show(&self, screen_manager: &Arc<Stdout>);
/// enable or disable the blinking of the cursor.
/// Enable or disable the blinking of the cursor.
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>);
}

View File

@ -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<char> {
@ -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);
}

View File

@ -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.")),
}
}

View File

@ -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)
}

View File

@ -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<D>(val: D) -> StyledObject<D>
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<String> 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<String> for Color {
impl FromStr for Color {
type Err = ();
/// Convert a string to an Color value
fn from_str(src: &str) -> Result<Self, Self::Err> {
let src = src.to_lowercase();

View File

@ -24,19 +24,21 @@ impl<D: Display> StyledObject<D> {
/// #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<D> {
@ -49,19 +51,21 @@ impl<D: Display> StyledObject<D> {
/// #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<D> {
@ -76,9 +80,9 @@ impl<D: Display> StyledObject<D> {
/// ```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<D: Display> StyledObject<D> {
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);

View File

@ -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<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(screen_manager.clone());
drop(screen);
functions::exit_terminal();
}
}

View File

@ -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<Stdout>);
/// Close the current terminal
fn exit(&self);
fn exit(&self,screen_manager: &Arc<Stdout>);
}

View File

@ -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)
}

View File

@ -152,7 +152,10 @@ impl ITerminal for WinApiTerminal {
}
}
fn exit(&self) {
fn exit(&self, screen_manager: &Arc<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(screen_manager.clone());
drop(screen);
functions::exit_terminal();
}
}

View File

@ -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(())
}

View File

@ -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<usize>;
/// Write [u8] buffer to console.
fn write(&self, buf: &[u8]) -> io::Result<usize>;
@ -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;
}

View File

@ -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<IStdout + Send>,
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<usize> {
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<IStdout + Send>>(
Box::from(WinApiStdout::new()),
Box::from(AnsiStdout::new()),
).unwrap();
#[cfg(not(target_os = "windows"))]
let screen_manager = Box::from(AnsiStdout::new()) as Box<IStdout + Send>;
Stdout { screen_manager , is_in_raw_mode: false}
}
}

View File

@ -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,
}