Doc updates and MdBook (#50)

* Updated readme and docs, and created an MdBook
This commit is contained in:
Timon 2018-11-25 14:17:11 +01:00 committed by GitHub
parent fe551c3e44
commit 4d2fba2c0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 623 additions and 104 deletions

166
README.md
View File

@ -1,46 +1,55 @@
# Crossterm | cross-platform terminal manipulating library written in rust. # Crossterm | cross-platform terminal manipulating library written in rust.
![Lines of Code][s7] [![Latest Version][s1]][l1] [![MIT][s2]][l2] [![docs][s3]][l3] ![Lines of Code][s6]
[![Latest Version](https://img.shields.io/crates/v/crossterm.svg)](https://crates.io/crates/crossterm) | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) | [![docs.rs](https://docs.rs/crossterm/badge.svg)](https://docs.rs/crossterm/) | [Examples](https://github.com/TimonPost/crossterm/tree/master/examples) | [Changelog](https://github.com/TimonPost/crossterm/blob/master/docs/UpgradeManual.md) | [Release Nodes](https://github.com/TimonPost/crossterm/blob/master/docs/ReleaseNotes.md) [s1]: https://img.shields.io/crates/v/crossterm.svg
|----|----|----|----|----|---- [l1]: https://crates.io/crates/crossterm
Ever got disappointed when a terminal library for rust was only written for unix systems? [s2]: https://img.shields.io/badge/license-MIT-blue.svg
Crossterm provides the same core functionalities for both windows and unix systems. [l2]: ./LICENSE
[s3]: https://docs.rs/crossterm/badge.svg
[l3]: https://docs.rs/crossterm/
[s3]: https://docs.rs/crossterm/badge.svg
[l3]: https://docs.rs/crossterm/
[s6]: https://tokei.rs/b1/github/TimonPost/crossterm?category=code
[s7]: https://travis-ci.org/TimonPost/crossterm.svg?branch=master
Ever got disappointed when a terminal library for rust was only written for UNIX systems?
Crossterm provides the same core functionalities for both Windows and UNIX systems.
Crossterm aims to be simple and easy to call in code. Crossterm aims to be simple and easy to call in code.
Though the simplicity of Crossterm, you do not have to worry about the platform you are working with. Through the simplicity of Crossterm, you do not have to worry about the platform you are working with.
You can just call whatever action you want and behind the scenes it will check what to do based on the current platform.
This crate supports all unix and windows terminals down to windows 7 (not all terminals are tested see [Tested Terminals](https://github.com/TimonPost/crossterm#tested-terminals) for more info) This crate supports all UNIX and windows terminals down to windows 7 (not all terminals are tested see [Tested Terminals](#tested-terminals) for more info)
## Table of contents: ## Table of contents:
- [Getting started](https://github.com/TimonPost/crossterm#getting-started) - [Getting started](#getting-started)
- [Useful links](https://github.com/TimonPost/crossterm#useful-links) - [Useful links](#useful-links)
- [Features](https://github.com/TimonPost/crossterm#features) - [Features](#features)
- [Examples](https://github.com/TimonPost/crossterm#examples) - [Examples](#examples)
- [Crossterm Wrapper](https://github.com/TimonPost/crossterm#crossterm-type--see-more) - [Crossterm Wrapper](#crossterm-type--see-more)
- [Styling](https://github.com/TimonPost/crossterm#crossterm-type--see-more) - [Styling](#crossterm-type--see-more)
- [Cursor](https://github.com/TimonPost/crossterm#cursor--see-more) - [Cursor](#cursor--see-more)
- [Input](https://github.com/TimonPost/crossterm#input--see-more) - [Input](#input--see-more)
- [Terminal](https://github.com/TimonPost/crossterm#terminal--see-more) - [Terminal](#terminal--see-more)
- [Tested Terminals](https://github.com/TimonPost/crossterm#tested-terminals) - [Tested Terminals](#tested-terminals)
- [How it works](https://github.com/TimonPost/crossterm#how-it-works) - [Notice](#notice)
- [Notice](https://github.com/TimonPost/crossterm#notice) - [Todo](#todo)
- [Todo](https://github.com/TimonPost/crossterm#todo) - [Contributing](#contributing)
- [Contributing](https://github.com/TimonPost/crossterm#contributing) - [Authors](#authors)
- [Authors](https://github.com/TimonPost/crossterm#authors) - [License](#license)
- [License](https://github.com/TimonPost/crossterm#license)
## Getting Started ## Getting Started
This documentation is only for Crossterm version `0.4.*` if you have an older version of Crossterm I suggest you check the [Upgrade Manual](https://github.com/TimonPost/crossterm/blob/master/docs/UpgradeManual.md) for more information about how to upgrade to a newer version. This documentation is only for Crossterm version `0.5` if you have an older version of Crossterm I suggest you check the [Upgrade Manual](https://github.com/TimonPost/crossterm/blob/master/docs/UpgradeManual.md). Also, check out the [examples](https://github.com/TimonPost/crossterm/tree/master/examples) folders which detailed examples for all functionality of this crate.
Also check out the [examples](https://github.com/TimonPost/crossterm/tree/master/examples) folders which detailed examples for all functionality of this crate.
Add the Crossterm package to your `Cargo.toml` file. Add the Crossterm package to your `Cargo.toml` file.
``` ```
[dependencies] [dependencies]
crossterm = "0.4.0" crossterm = "0.5.0"
``` ```
And import the Crossterm modules you want to use. And import the Crossterm modules you want to use.
@ -49,55 +58,57 @@ And import the Crossterm modules you want to use.
extern crate crossterm; extern crate crossterm;
// this module is used for styling the terminal // this module is used for styling the terminal
use self::crossterm::style::*; use crossterm::style::*;
// this module is used for cursor related actions // this module is used for cursor related actions
use self::crossterm::cursor::*; use crossterm::cursor::*;
// this mudule is used for terminal related actions // this mudule is used for terminal related actions
use self::crossterm::terminal::*; use crossterm::terminal::*;
// this mudule is used for input related actions // this mudule is used for input related actions
use self::crossterm::input::*; use crossterm::input::*;
``` ```
## Useful Links ### Useful Links
- Code [documentation](https://docs.rs/crossterm/). - [Book](http://atcentra.com/crossterm/)
- The [Cargo Page](https://crates.io/crates/crossterm) - [Documentation](https://docs.rs/crossterm/)
- More real live [examples](https://github.com/TimonPost/crossterm/tree/master/examples/program_examples) - [Crates.io](https://crates.io/crates/crossterm)
- Detailed [examples](https://github.com/TimonPost/crossterm/tree/master/examples) - [Program Examples](https://github.com/TimonPost/crossterm/tree/master/examples/program_examples)
- [Examples](https://github.com/TimonPost/crossterm/tree/master/examples)
## Features ## Features
These are the features from this crate: These are the features from this crate:
- Cross-platform
- Everything is multithreaded (Send, Sync)
- Detailed documentation on every item
- Cursor. - Cursor.
- Moving _n_ times Up, Down, Left, Right. - Moving _n_ times Up, Down, Left, Right
- Goto a certain position. - Goto a certain position
- Get cursor position - Get cursor position
- Storing the current cursor position and resetting to that stored cursor position later. - Storing the current cursor position and resetting to that stored cursor position later
- Hiding an showing the cursor. - Hiding an showing the cursor
- Control over blinking of the terminal cursor (only some terminals are supporting this). - Control over blinking of the terminal cursor (only some terminals are supporting this)
- Styled output - Styled output
- Foreground color (16 base colors) - Foreground color (16 base colors)
- Background color (16 base colors) - Background color (16 base colors)
- 256 color support (unix only). - 256 color support (unix only)
- Text Attributes like: bold, italic, underscore and crossed word ect (unix only). - Text Attributes like: bold, italic, underscore and crossed word ect (unix only)
- Custom ANSI color code input to set fore- and background color (unix only). - Custom ANSI color code input to set fore- and background color (unix only)
- Terminal - Terminal
- Clearing (all lines, current line, from cursor down and up, until new line) - Clearing (all lines, current line, from cursor down and up, until new line)
- Scrolling (Up, down) - Scrolling (Up, down)
- Get the size of the terminal - Get the size of the terminal
- Set the size of the terminal. - Set the size of the terminal
- Alternate screen - Alternate screen
- Raw screen - Raw screen
- Exit the current process
- Input - Input
- Read character - Read character
- Read line - Read line
- Read async - Read async
- Read async until - Read async until
- Exit the current process. - Wait for key event (terminal pause)
- Everything is multithreaded (Send, Sync)
- Detailed documentation on every item.
- Crossplatform
## Examples ## Examples
These are some basic examples demonstrating how to use this crate. See [examples](https://github.com/TimonPost/crossterm/blob/master/examples/) for more. These are some basic examples demonstrating how to use this crate. See [examples](https://github.com/TimonPost/crossterm/blob/master/examples/) for more.
@ -107,8 +118,7 @@ This is a wrapper for all the modules crossterm provides like terminal, cursor,
```rust ```rust
// screen wheron the `Crossterm` methods will be executed. // screen wheron the `Crossterm` methods will be executed.
let screen = Screen::default(); let crossterm = Crossterm::new();
let crossterm = Crossterm::new(&screen);
// get instance of the modules, whereafter you can use the methods the particulary module provides. // get instance of the modules, whereafter you can use the methods the particulary module provides.
let color = crossterm.color(); let color = crossterm.color();
@ -116,22 +126,18 @@ let cursor = crossterm.cursor();
let terminal = crossterm.terminal(); let terminal = crossterm.terminal();
// styling // styling
let style = crossterm.style("Black font on Green background color").with(Color::Black).on(Color::Green); println!("{}", crossterm.style("Black font on Green background color").with(Color::Black).on(Color::Green));
style.paint(&screen);
``` ```
### Styled Font | [see more](https://github.com/TimonPost/crossterm/blob/master/examples/color/mod.rs) ### Styled Font | [see more](http://atcentra.com/crossterm/styling.html)
This module provides the functionalities to style the terminal cursor. This module provides the functionalities to style the terminal.
```rust ```rust
use crossterm::style::{Color, style}; use crossterm::style::{Color, style};
use crossterm::Screen;
// store objcets so it could be painted later to the screen. // store objcets so it could be painted later to the screen.
let style1 = style("Some Blue font on Black background").with(Color::Blue).on(Color::Black); let style1 = style("Some Blue font on Black background").with(Color::Blue).on(Color::Black);
let style2 = style("Some Red font on Yellow background").with(Color::Red).on(Color::Yellow); let style2 = style("Some Red font on Yellow background").with(Color::Red).on(Color::Yellow);
let screen = Screen::default();
/// !! The following code only works for unix based systems !! /// !! The following code only works for unix based systems !!
// some attributes // some attributes
let normal = style("Normal text"); let normal = style("Normal text");
@ -146,33 +152,30 @@ let dimmed = style("Dim text").dim();
let crossed_out = style("Crossed out font").crossed_out(); let crossed_out = style("Crossed out font").crossed_out();
// paint styled text to screen (this could also be called inline) // paint styled text to screen (this could also be called inline)
style1.paint(&screen); println!("{}", style1);
style2.paint(&screen); println!("{}", style2);
bold.paint(&screen); println!("{}", bold);
hidden.paint(&screen); println!("{}", hidden);
...
// cursom rgb value // cursom rgb value
style("RGB color (10,10,10) ").with(Color::Rgb { style("RGB color (10,10,10) ").with(Color::Rgb {
r: 10, r: 10,
g: 10, g: 10,
b: 10 b: 10
}).paint(&screen); }));
// custom ansi color value // custom ansi color value
style("ANSI color value (50) ").with(Color::AnsiValue(50)).paint(&screen); style("ANSI color value (50) ").with(Color::AnsiValue(50));
``` ```
### Cursor | [see more](https://github.com/TimonPost/crossterm/blob/master/examples/cursor/mod.rs) ### Cursor | [see more](https://github.com/TimonPost/crossterm/blob/master/examples/cursor/mod.rs)
This module provides the functionalities to work with the terminal cursor. This module provides the functionalities to work with the terminal cursor.
```rust ```rust
use crossterm::Screen;
use crossterm::cursor; use crossterm::cursor;
// create Screen to wheron the `cursor()` should function. let mut cursor = cursor();
let screen = Screen::default();
let mut cursor = cursor(&screen);
/// Moving the cursor /// Moving the cursor
// Set the cursor to position X: 10, Y: 5 in the terminal // Set the cursor to position X: 10, Y: 5 in the terminal
@ -207,19 +210,14 @@ cursor.blink(true)
``` ```
### Input | [see more](https://github.com/TimonPost/crossterm/tree/master/examples/input) ### Input | [see more](http://atcentra.com/crossterm/input.html)
This module provides the functionalities to work with terminal input. This module provides the functionalities to work with terminal input.
Check [this](https://github.com/TimonPost/crossterm/blob/master/examples/input/keyboard/async_input.rs) for handling async input.
```rust ```rust
use crossterm::Screen;
use crossterm::input; use crossterm::input;
// create Screen to wheron the `cursor()` should function. // create Screen to wheron the `cursor()` should function.
let screen = Screen::default(); let mut input = input();
let mut input = input(&screen);
match input.read_char() { match input.read_char() {
Ok(s) => println!("char typed: {}", s), Ok(s) => println!("char typed: {}", s),
@ -238,11 +236,9 @@ This module provides the functionalities to work with the terminal in general.
```rust ```rust
use crossterm::terminal::{terminal,ClearType}; use crossterm::terminal::{terminal,ClearType};
use crossterm::Screen;
// create Screen to wheron the `terminal()` should function. // create Screen to wheron the `terminal()` should function.
let screen = Screen::default(); let mut terminal = terminal();
let mut terminal = terminal(&screen);
// Clear all lines in terminal; // Clear all lines in terminal;
terminal.clear(ClearType::All); terminal.clear(ClearType::All);
@ -273,7 +269,8 @@ terminal.exit();
terminal.write("Some text\n Some text on new line"); terminal.write("Some text\n Some text on new line");
``` ```
Check these links: [AlternateScreen](https://github.com/TimonPost/crossterm/blob/master/examples/terminal/alternate_screen.rs) and [RawScreen](https://github.com/TimonPost/crossterm/blob/master/examples/terminal/raw_mode.rs) for information about how to work with these features. ### Alternate and Raw Screen
These concepts are a little more complex, please checkout the [book](http://atcentra.com/crossterm/screen.html) topics about these subjects.
## Tested terminals ## Tested terminals
@ -284,14 +281,15 @@ Check these links: [AlternateScreen](https://github.com/TimonPost/crossterm/blob
- Windows 8.1 (N) - Windows 8.1 (N)
- Ubuntu Desktop Terminal - Ubuntu Desktop Terminal
- Ubuntu 17.10 - Ubuntu 17.10
- Arch linux Konsole - (Arch, Manjaro) KDE Konsole
- Linux Mint
This crate supports all Unix terminals and windows terminals down to Windows 7 but not all of them have been tested. This crate supports all Unix terminals and windows terminals down to Windows 7 but not all of them have been tested.
If you have used this library for a terminal other than the above list without issues feel free to add it to the above list, I really would appreciate it. If you have used this library for a terminal other than the above list without issues feel free to add it to the above list, I really would appreciate it.
## Notice ## Notice
This library is not stable yet but I expect it to not to change that much anymore. This library is average stable now but I don't expect it to not to change that much.
And if there are any changes that affect previous versions I will [describe](https://github.com/TimonPost/crossterm/blob/master/docs/UpgradeManual.md) what to change when upgrading Crossterm to a newer version. If there are any changes that will affect previous versions I will [describe](https://github.com/TimonPost/crossterm/blob/master/docs/UpgradeManual.md) what to change to upgrade.
## Todo ## Todo
I still have some things in mind to implement. I still have some things in mind to implement.

1
docs/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
book

View File

@ -1,12 +1,12 @@
# Changes crossterm 0.5.0 # Changes crossterm 0.5.0
- Implemented Display for styled object. - 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 convenient API, no need to care about `Screen` unless working with when working with alternate or raw screen [PR](https://github.com/TimonPost/crossterm/pull/44)
- more to come ... - Added ability to pause the terminal [issue](https://github.com/TimonPost/crossterm/issues/39)
# Changes crossterm to 0.4.3 # Changes crossterm to 0.4.3
- Fixed bug [issue 41](https://github.com/TimonPost/crossterm/issues/41) - Fixed bug [issue 41](https://github.com/TimonPost/crossterm/issues/41)
# Changes crossterm to 0.4.2 # Changes crossterm to 0.4.2
- Added functionality to make a styled object writable to screen [issue 33](https://github.com/TimonPost/crossterm/issues/33) - Added functionality to make a styled object writable to screen [issue 33](https://github.com/TimonPost/crossterm/issues/33)
- Added unit tests. - Added unit tests.
- Bugfix with getting terminal size unix. - Bugfix with getting terminal size unix.

View File

@ -1,3 +1,68 @@
## Upgrade crossterm to 0.5.0
***WARNING***
I workded on making the user API more conviniant therefore I had to make some chages to the user API. The problem with `0.4` is that you need to pass a `Screen` to the modules: `cursor(), color(), terminal()`.
In the new situation you only have to do this when working with raw or alternate screen. When you just want to perform actions like styling on the main screen you don't have to to pass in the `Screen` any more. This will look like the following:
#### 1. Remove `Screen` from the function calls: `cursor(), color(), terminal(), input()`
_**old**_
```
let screen = Screen::default();
let color = color(&screen);
let cursor = cursor(&screen);
let input = input(&screen);
let terminal = terminal(&screen);
let crossterm = Crossterm::new(&screen);
let terminal = Terminal::new(&screen.stdout);
let cursor = TerminalCursor::new(&screen.stdout);
let color = TerminalColor::new(&screen.stdout);
let input = TerminalInput::new(&screen.stdout);
```
_**new**_
```
let color = color();
let cursor = cursor();
let input = input();
let terminal = terminal();
let crossterm = Crossterm::new();
let terminal = Terminal::new();
let cursor = TerminalCursor::new();
let color = TerminalColor::new();
let input = TerminalInput::new();
```
#### 2. When working with alternate or raw screen.
When working with alternate and or raw screen you still have to provide a `Screen` instance since information of the alternate and raw screen is stored in it. When doing this, the actions of the module will be perfomed on the alternate screen. If you don't do this your actions will executed at the main screen.
```
use crossterm::cursor;
use crossterm::color;
use crossterm::input;
use crossterm::terminal;
let screen = Screen::default();
if let Ok(alternate) = screen.enable_alternate_modes(false) {
let screen = alternate.screen;
let color = color::from_screen(&screen);
let cursor = cursor::from_screen(&screen);
let input = input::from_screen(&screen);
let terminal = terminal::from_screen(&screen);
let crossterm = Crossterm::from_screen(&screen);
let terminal = Terminal::from_output(&screen.stdout);
let cursor = TerminalCursor::from_output(&screen.stdout);
let color = TerminalColor::from_output(&screen.stdout);
let input = TerminalInput::from_output(&screen.stdout);
}
```
## Upgrade crossterm to 0.4.0 ## Upgrade crossterm to 0.4.0
***WARNING*** ***WARNING***
@ -7,12 +72,12 @@ I really did not want to do this but it had to be done for some reasons.
#### 1. You need to pass a reference to an `Screen` to the modules: `cursor(), color(), terminal()` #### 1. You need to pass a reference to an `Screen` to the modules: `cursor(), color(), terminal()`
_**old**_
``` ```
use crossterm::terminal::terminal; use crossterm::terminal::terminal;
use crossterm::cursor::cursor; use crossterm::cursor::cursor;
use crossterm::style::color; use crossterm::style::color;
/// Old situation
use crossterm::Context; use crossterm::Context;
let context: Rc<Context> = Context::new(); let context: Rc<Context> = Context::new();
@ -20,8 +85,9 @@ let context: Rc<Context> = Context::new();
let cursor = cursor(&context); let cursor = cursor(&context);
let terminal = terminal(&context); let terminal = terminal(&context);
let color = color(&context); let color = color(&context);
```
/// new situation _**new**_
```
use crossterm::Screen; use crossterm::Screen;
let screen: Screen = Screen::default(); let screen: Screen = Screen::default();
@ -95,8 +161,8 @@ I really did not want to do this but it had to be done for some reasons. Check `
First thing that has changed is that you need to pass a reference to an `Rc<Context>` to the modules: `cursor(), color(), terminal()` First thing that has changed is that you need to pass a reference to an `Rc<Context>` to the modules: `cursor(), color(), terminal()`
_**old**_
``` ```
use crossterm::terminal::terminal; use crossterm::terminal::terminal;
use crossterm::cursor::cursor; use crossterm::cursor::cursor;
use crossterm::style::color; use crossterm::style::color;
@ -105,8 +171,9 @@ use crossterm::style::color;
let cursor = cursor(); let cursor = cursor();
let terminal = terminal(); let terminal = terminal();
let color = color(); let color = color();
```
/// new situation _**new**_
```
use crossterm::Context; use crossterm::Context;
let context: Rc<Context> = Context::new(); let context: Rc<Context> = Context::new();

4
docs/mdbook/book.toml Normal file
View File

@ -0,0 +1,4 @@
[book]
authors = ["T. Post"]
multilingual = false
src = "src"

View File

@ -0,0 +1,8 @@
# Summary
This book will cover styling and user input. It will also give a detailed description about working with alternate and raw screen.
- [Styling Output](styling.md)
- [example](styling_example.md)
- [Async Input](input.md)
- [Alternate, Raw Screen](screen.md)
- [example](screen_example.md)

77
docs/mdbook/src/input.md Normal file
View File

@ -0,0 +1,77 @@
Crossterm provides a way to work with the terminal input. We will not cover the basic usage but instead asynchronous reading of input.
Please checkout these [examples](https://github.com/TimonPost/crossterm/blob/master/examples/input/keyboard/input.rs) for reading a line or a character from the user.
So what does 'reading async input' mean?
This means that you can catch user input without your program having to wait for it.
The user input will be read from another thread.
UNIX systems will get input from TTY and Windows will get input with '_getwch' and '_getwche'.
This could be useful in a case where you want to perform some logic with a periodic check if the user entered some character.
# Example
In the following example we will run some loop until the user has pressed 'x'.
So lets start by setting up the basics.
```
use std::io::Read;
use crossterm::{input, Screen};
use std::{thread, time::Duration};
fn main() {
println!("Press 'x' to quit.");
/* next code here */
}
```
Next we need to put the terminal into raw mode. We do this because whe don't want the user input to be printed to the terminal screen.
Once the user pressed 'x' we manually want to process it and stop the loop.
```rust
// enable raw modes by passing in 'true'
let screen = Screen::new(true);
// create a input from our screen.
let input = input::from_screen(&screen);
/* next code here */
```
Take note that whe need to use our 'Screen' to create an `TerminalInput` instance, check [this](screen.md#important-notice) out for more information why that is.
Next we call `input.read_async()`. This will spin up a thread which will poll all input from the user.
This thread send all input via an 'mpsc' channel to the `AsyncReader` we got back from this function.
By calling `bytes()` on the `AsyncReader` we get an iterator back over the characters (bytes).
```
let mut stdin = input.read_async().bytes();
/* next code here */
```
Now we got an iterator back we can call `next()` on it to get the next pressed character (byte).
If an character is pressed we will get `Some(Ok(u8))` back which we compare to see if 'x' is pressed.
If the 'x' is pressed we break the loop.
```
loop {
let pressed_char: Option<Result<u8>> = stdin.next();
// check if the pressed char is equal to 'c'
if let Some(Ok(b'x')) = pressed_char {
println!("The key: `x` was pressed and program is terminated.");
break;
}
thread::sleep(Duration::from_millis(20));
}
```
You should now have a fully functional program waiting for the user to press 'x'.
User input will be recorded on the background so that the main logic of your program can continue.
The code from this tutorial could be found [here](https://github.com/TimonPost/crossterm/blob/master/examples/input/keyboard/async_input.rs#L45).
---------------------------------------------------------------------------------------------------------------------------------------------
More examples could be found at this [link](https://github.com/TimonPost/crossterm/tree/master/examples/input/keyboard).

78
docs/mdbook/src/screen.md Normal file
View File

@ -0,0 +1,78 @@
# Basic Usage of Screen
As you may have seen crossterm has a type called `Screen`. This type should be used when working with the alternate or raw screen.
Before we continue, I'll explain what those concepts are.
## Screen Buffer
A screen buffer is a two-dimensional array of characters and color data to be output in a console window. An terminal can have multiple of those screen buffers, and the active screen buffer is the one that is displayed on the screen.
Crossterm allows you to switch between those buffers; the screen you are working in is called the 'main screen'. We call the other screen the 'alternate screen'.
### Alternate Screen
Normally you are working on the main screen but an alternate screen is somewhat different from a normal screen.
For example, it has the exact dimensions of the terminal window, without any scrollback region. An example of this is vim when it is launched from bash.
Vim uses the entirety of the screen to edit the file, then exits to bash leaving the original buffer unchanged.
Crossterm provides the ability to switch to the alternate screen, make some changes, and then go back to the main screen. The main screen will still have its original data since we made all the edits on the alternate screen.
## Raw screen
To understand the concept of a 'raw screen' let's look at the following points:
**No line buffering.**
Normally the terminals use line buffering. This means that the input will be sent to the terminal line by line. With raw mode, the input will send one byte at a time.
**Input**
All input has to be written to the screen buffer manually by the programmer.
**Characters**
The characters are not processed by the terminal driver. Also, special character have no meaning. For example, backspace will not be interpreted as backspace but instead will be sent directly to the terminal.
**Escape Characters**
Note that in raw mode `\n` `\r` will move the cursor to a new line but it will be at the same position as it was on the previous line.
_example of what I mean_
```
some text
some text
```
To start at the beginning of the next line, use `\n\r`.
# Important Notice
When we want to print some text to the alternate screen we can't just write on it using `print!(), println!(), or write!()`.
The same goes for coloring, cursor movement, input, and terminal actions. Crossterm provides a solution for that by introducing the `Screen` type.
Please checkout this [example](screen_example.md) for more information on how to use it.
```
use crossterm::cursor;
use crossterm::color;
use crossterm::input;
use crossterm::terminal;
let screen = Screen::default();
if let Ok(alternate) = screen.enable_alternate_modes(false) {
let screen = alternate.screen;
let color = color::from_screen(&screen);
let cursor = cursor::from_screen(&screen);
let input = input::from_screen(&screen);
let terminal = terminal::from_screen(&screen);
let crossterm = Crossterm::from_screen(&screen);
let terminal = Terminal::from_output(&screen.stdout);
let cursor = TerminalCursor::from_output(&screen.stdout);
let color = TerminalColor::from_output(&screen.stdout);
let input = TerminalInput::from_output(&screen.stdout);
}
```
The above modules will now all be executed at the 'alternate screen'.
---------------------------------------------------------------------------------------------------------------------------------------------
Next up: [Examples](screen_example.md)

View File

@ -0,0 +1,155 @@
Let's build some basic programs who are using the alternate and raw screen.
# Raw Screen
_setup the basics_
```rust
extern crate crossterm;
use crossterm::Screen;
fn main() {
/* next code here */
}
```
We use the `Screen` type to enable raw mode for the terminal.
When creating a screen you have the option to pass it a boolean, this boolean specifies whether the screen will be in raw or normal mode.
Let's play around a bit to see what raw screen does.
```rust
// Create raw screen by passing in true.
let screen = Screen::new(true);
println!("Some text");
println!("Some text");
```
When you run this program you will directly see that the output is a little strange like:
```
Some text
Some text
```
Another fun thing to do is reading the input. This should not work since the input is not recorded by the terminal when in raw mode.
_Take note this will cause your terminal to freeze.
Since `read_line` expects some line input but it will never be recorded because of raw mode.
You should just restart the terminal when you are stuck_.
```rust
// Create raw screen by passing in true.
let screen = Screen::new(true);
let text = std::io::stdin().read_line(&mut string);
println!("{:?}", text);
```
Note that we spoke about the reason why this [previously](screen.md#raw-screen).
However, if you want to read input in raw mode you should checkout [Async Input](input.md).
# Alternate Screen
_setup the basics_
```rust
extern crate crossterm;
use crossterm::Screen;
use std::{thread, time};
use std::io::Write;
fn main() {
/* next code here */
}
```
As we spoke of [previously](screen.md#alternate-screen), with `Screen` we can manage alternate screen and raw screen.
Let's make some simple program who is switching from the main to alternate screen whereafter it will wait for 2 seconds.
When those seconds are over we will go back to the main screen.
First off, create an instance of `Screen`. We can call `enable_alternate_modes()` on this screen, this will switch the screen buffer to the alternate buffer.
When we call this function we will get an `AlternateScreen` instance back which represents the alternate screen.
We should use this instance when we want to do any writing, styling, cursor, and terminal related things on the alternate screen ([Important Notice](screen.md##important-notice)).
```rust
let screen = Screen::default();
if let Ok(mut alternate) = screen.enable_alternate_modes(false) {
/* next code here */
}
```
Next, we use the instance we got back and write our message to it whereafter we wait for 2 seconds.
We wait 2 seconds to give us some time to see the alternate screen.
If the `AlternateScreen` goes out of scope it will automatically switch back to the main screen.
```rust
write!(alternate.screen, "{}", "Welcome to the wait screen.\n Please wait a 2 seconds until we arrive back at the main screen.");
thread::sleep(time::Duration::from_secs(2));
```
By now you should be able to execute the program, you will see that directly you are being redirected to another screen with no scrollback region.
You will see this screen open whereafter it closes after 2 seconds.
When the program finishes you will notice you are on the main screen again with it's contents unmodified.
# Perform Actions on Alternate Screen.
Now we have covered the basics of alternate screen let's make a program who styles some text on the 'raw' alternate screen.
_setup the basics_
```rust
extern crate crossterm;
use crossterm::Screen;
use std::{thread, time};
use std::io::Write;
fn main() {
// switch to alternate screen and make it raw by passing in true.
if let Ok(mut alternate) = screen.enable_alternate_modes(true) {
/* next code here */
}
}
```
Some basics steps the following code will do:
1. Create [Crossterm]() type to manage the cursor and styling
2. Set the position of the cursor to x: 0 and y: 0
3. Write the styled text, you can use the two described ways
4. Set the position of the cursor to x: 0 and y: 1
5. Write other text and flush it to the screen
6. Sleep two seconds to see the results
```rust
let alternate_screen = &mut alternate.screen;
// could manage styling and cursor movement.
let crossterm = Crossterm::from_screen(alternate_screen);
let cursor = crossterm.cursor();
cursor.goto(0,0);
// 1) print the 'styled object' by converting it into a type that is displayable for alternate screen.
println!("{}", crossterm.style("Welcome to the wait screen.")
.with(Color::Red)
.on(Color::Blue)
.into_displayable(alternate_screen)
);
// 2) use the `paint` method to print it to the alternate screen.
crossterm.style("Welcome to the wait screen.")
.with(Color::Red)
.on(Color::Blue)
.paint(alternate_screen);
cursor.goto(0,1);
write!(alternate_screen, "{}", "Please wait a few seconds until we arrive back at the main screen.");
alternate_screen.flush();
thread::sleep(time::Duration::from_secs(2));
```
As you might have noticed, you need to to manually move the cursor, flush the buffer. This is because the terminal is in raw modes.
Also, by printing with `paint` or calling `into_displayable` you pass in a reference to the alternate screen.
Tip: Take a look at [how](screen.md#important-notice) you should use other modules crossterm provides on the alternate screen.
---------------------------------------------------------------------------------------------------------------------------------------------
More examples could be found at this [link](https://github.com/TimonPost/crossterm/tree/master/examples/terminal).

View File

@ -0,0 +1,44 @@
Crossterm provides options for you to style your font and terminal. Take for example coloring output and applying attributes.
**Color support**
Windows systems with versions less than 10 only have support for 16 colors and don't have any support for attributes.
## Colors
There are 16 base colors which available for almost all terminals even windows 7 and 8.
| Light Variant | Dark Variant |
| :-------------| :------------- |
| Grey | Black |
| Red | DarkRed |
| Green | DarkGreen |
| Yellow | DarkYellow |
| Blue | DarkBlue |
| Magenta | DarkMagenta|
| Cyan | DarkCyan |
| White | DarkWhite |
In addition to 16 colours, most unix terminals also support more colors.
For example, GNOME-terminals are supporting the [True color (24-bit)](https://en.wikipedia.org/wiki/Color_depth#True_color_(24-bit)) coloring scheme which allows you to use [RGB](https://nl.wikipedia.org/wiki/RGB-kleursysteem) for setting the terminal color.
All xterm terminals are at least supporting the [256 (Xterm, 8-bit)](https://jonasjacek.github.io/colors/) colors.
## Attributes
UNIX terminals are supporting attributes on top of text. Crossterm allows you to add attributes to the text.
Not all attributes are widely supported for all terminals, keep that in mind when working with this.
| Attribute | Note |
| :-------------: | :-------------: |
| Bold | |
| Underlined | |
| Dim | |
| SlowBlink | less than 150 per minute |
| CrosseOut | characters legible, but marked for deletion. |
| Italic | not widely supported; Sometimes treated as inverse |
| RapidBlink | not widely supported; MS-DOS ANSI.SYS; 150+ per minute |
| Reverse | not widely supported |
| Hidden | not widely supported |
Now we have covered the basics of styling lets go some [examples](styling_example.md).
---------------------------------------------------------------------------------------------------------------------------------------------
Next up: [Examples](styling_example.md)

View File

@ -0,0 +1,77 @@
# Example
_setup the basics_
```rust
extern crate crossterm;
use crossterm::style::{style, Color, Attribute};
fn main() {
/* your code here */
}
```
Let's dive into styling with crossterm. The easiest way to do this is by making use of the `style()` function.
```rust
let styled_object = style("This is some text converted into a styled object");
```
The function `style()` takes in any type that implement `Display`
and returns a `StyledObject`. A `StyledObject` is just a wrapper crossterm uses to store the text and style together.
The above code will not do any coloring magic yet. Lets play around with some colors to see it in working.
## Coloring
```rust
let styled_object = style("'Red' text on 'White' background")
.with(Color::Red)
.on(Color::White);
println!("{}", styled_object);
```
With the function `with()` you can decide the foreground color and with the function `on()` you can decide the background color of the text.
Because `StyledObject` you got from `style()` implements `Display` you are allowed to print it with: `print!, println!, write` etc.
When running the above code you are supposed to see colored text with foreground color 'red' and with the background color 'white'.
_note: you don't have to color both backround an foreground, if not specified they remain as they are_.
### RGB
Most UNIX terminals are supporting [True color(24-bit)](https://en.wikipedia.org/wiki/Color_depth#True_color_(24-bit)) coloring scheme.
You can set the color of the terminal by using `Color::RGB(r,g,b)`.
```
let styled_object = style("'Light green' text on 'Black' background")
.with(Color::Rgb {r: 0, g: 255, b: 128})
.on(Color::Rgb {r: 0, g: 0, b: 0});
```
This will print some light green text on black background.
### Custom ANSI color value
When working on unix you could also specify a custom ANSI value ranging up from 0 to 256.
See [256 (Xterm, 8-bit) colors](https://jonasjacek.github.io/colors/) for more information.
```
let styled_object = style("'Red' text on 'White' background")
.with(Color::AnsiValue(9))
.on(Color::AnsiValue(15));
println!("{}", styled_object);
```
## Attributes
When working in Linux you could also use attributes to style your font. For example you could cross your text with a line and make it bold.
See [above](styling.md#Attributes) for more information.
```
let styled_object = style("'Red' text on 'White' background")
.attr(Attribute::CrossedOut)
.attr(Attribute::Bold);
println!("{}", styled_object);
```
---------------------------------------------------------------------------------------------------------------------------------------------
More examples could be found at this [link](https://github.com/TimonPost/crossterm/blob/master/examples/color/mod.rs).

View File

@ -8,15 +8,18 @@
extern crate crossterm; extern crate crossterm;
// modules that could be test // modules that could be test
mod color; //mod color;
mod cursor; //mod cursor;
mod input; //mod input;
mod some_types; //mod some_types;
mod terminal; //mod terminal;
use crossterm::input::{TerminalInput, KeyEvent}; use crossterm::style::{style, Color, Attribute};
fn main() { fn main() {
println!("Press 'x' to quit..."); let styled_object = style("'Red' text on 'White' background")
TerminalInput::wait_until(KeyEvent::OnKeyPress(b'x')); .with(Color::AnsiValue(9))
.on(Color::AnsiValue(15));
println!("{}", styled_object);
} }

View File

@ -77,7 +77,7 @@ pub fn write(stdout: &Option<&Arc<TerminalOutput>>, string: String) -> io::Resul
pub fn write_str(stdout: &Option<&Arc<TerminalOutput>>, string: &str) -> io::Result<usize> { pub fn write_str(stdout: &Option<&Arc<TerminalOutput>>, string: &str) -> io::Result<usize> {
match stdout { match stdout {
None => match io::stdout().flush() { None => match io::stdout().flush() {
Ok(_) => Ok(string.len()), Ok(_) => { write!(io::stdout(), "{}", string)?; Ok(string.len()) },
Err(e) => Err(e), Err(e) => Err(e),
}, },
Some(output) => output.write_str(string), Some(output) => output.write_str(string),

View File

@ -13,7 +13,7 @@ use self::unix_input::UnixInput;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::windows_input::WindowsInput; use self::windows_input::WindowsInput;
pub use self::input::{input, TerminalInput}; pub use self::input::{input, from_screen, TerminalInput};
use std::io::{self, Error, ErrorKind, Read}; use std::io::{self, Error, ErrorKind, Read};
use std::sync::{mpsc, Arc}; use std::sync::{mpsc, Arc};

View File

@ -210,13 +210,20 @@ impl<D: Display> Display for StyledObject<D> {
reset = true; reset = true;
} }
#[cfg(unix)]
for attr in self.object_style.attrs.iter() {
write!(f, "{}", format!(csi!("{}m"), *attr as i16));
reset = true;
}
fmt::Display::fmt(&self.content, f)?; fmt::Display::fmt(&self.content, f)?;
std::io::stdout().flush().expect("Flush stdout failed"); std::io::stdout().flush().expect("Flush stdout failed");
if reset { if reset {
// write!(f, "\x1b[0m")?;
colored_terminal.reset(); colored_terminal.reset();
std::io::stdout().flush().expect("Flush stdout failed");
} }
Ok(()) Ok(())
} }
} }