read line, read char, read async and read async until implemented for windows
This commit is contained in:
parent
fcc4ca31bc
commit
07502c016d
@ -25,4 +25,4 @@ path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "example_bin"
|
||||
path = "./examples/Crossterm 0.3.0/bin.rs"
|
||||
path = "./examples/Crossterm 0.3.1/bin.rs"
|
@ -19,14 +19,53 @@ use crossterm::Context;
|
||||
// mod color;
|
||||
// mod cursor;
|
||||
// mod crossterm_type;
|
||||
use crossterm::raw::IntoRawMode;
|
||||
use std::{thread, time};
|
||||
use std::io::Read;
|
||||
|
||||
fn main()
|
||||
{
|
||||
|
||||
|
||||
// let mut rv = String::new();
|
||||
// {
|
||||
// let alternate = ::crossterm::screen::AlternateScreen::from(context.clone());
|
||||
// alternate.into_raw_mode(context.clone());
|
||||
|
||||
// thread::spawn(|| {
|
||||
// let context = Context::new();
|
||||
// let input = ::crossterm::input::input(&context);
|
||||
// let result = input.read_async().unwrap();
|
||||
// println!("input: {:?}",result);
|
||||
// });
|
||||
|
||||
let context = Context::new();
|
||||
let input = ::crossterm::input::input(&context);
|
||||
let line = input.read_line().unwrap();
|
||||
let mut stdin = input.read_until_async(b'\r' as u8).bytes();
|
||||
|
||||
for i in 0..100
|
||||
{
|
||||
let a = stdin.next();
|
||||
|
||||
println!("input: {:?} exptected: {:?}", a,b'\r');
|
||||
|
||||
if let Some(Ok(b'q')) = a {
|
||||
break;
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(50));
|
||||
// println!("Some data {:?}", b)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ::std::io::stdin().read_line(&mut rv);
|
||||
// let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
// rv.truncate(len);
|
||||
|
||||
|
||||
// }
|
||||
|
||||
println!("input: {}",line);
|
||||
}
|
||||
|
||||
|
||||
|
7
examples/Crossterm 0.3.1/README.md
Normal file
7
examples/Crossterm 0.3.1/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
This folder contains examples for version 0.3.0 Here you will find examples of all the functionalities crossterm offers.
|
||||
|
||||
It has 4 modules:
|
||||
- color (this is about all the styling of the terminal)
|
||||
- cursor (this is about all the actions you can perform with the cursor)
|
||||
- terminal (this is about all the actions you can perform on the terminal)
|
||||
- program examples (this folder will contain some real life examples)
|
33
examples/Crossterm 0.3.1/bin.rs
Normal file
33
examples/Crossterm 0.3.1/bin.rs
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
//! This bin folder can be used to try the examples out located in the examples directory.
|
||||
//!
|
||||
//! All you need to do is:
|
||||
//!
|
||||
//! - Download the crossterm source code.
|
||||
//! - Add this in the Cargo.toml file:
|
||||
//! ``` [[bin]]
|
||||
//! name = "example_bin"
|
||||
//! path = "./examples/bin.rs"
|
||||
//! ```
|
||||
//!
|
||||
//! - Run program with: `cargo run`
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::Context;
|
||||
|
||||
// mod terminal;
|
||||
// mod color;
|
||||
// mod cursor;
|
||||
// mod crossterm_type;
|
||||
mod input;
|
||||
|
||||
use input::keyboard::{async_input, input as stdin};
|
||||
|
||||
fn main()
|
||||
{
|
||||
async_input::read_async();
|
||||
// stdin::read_line();
|
||||
// stdin::read_char();
|
||||
}
|
||||
|
||||
|
206
examples/Crossterm 0.3.1/color/mod.rs
Normal file
206
examples/Crossterm 0.3.1/color/mod.rs
Normal file
@ -0,0 +1,206 @@
|
||||
//!
|
||||
//! Examples of coloring the terminal.
|
||||
//!
|
||||
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::style::Color;
|
||||
use self::crossterm::terminal;
|
||||
use self::crossterm::Context;
|
||||
|
||||
/// print some red font | demonstration.
|
||||
pub fn paint_foreground() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
// Pass an string to the `paint()` method with you want to paint.
|
||||
// This will give you an object back wits can be styled and displayed.
|
||||
let mut styledobject = terminal.paint("Red font");
|
||||
// Call the method `with()` on the object given by `paint()` and pass in any Color from the Color enum.
|
||||
styledobject = styledobject.with(Color::Red);
|
||||
// Print the object to the console and see the result.
|
||||
println!("{}", styledobject);
|
||||
|
||||
// Crossterm provides method chaining so that the above points can be inlined.
|
||||
println!("{}", terminal.paint("Red font").with(Color::Red));
|
||||
}
|
||||
|
||||
/// print some font on red background | demonstration.
|
||||
pub fn paint_background() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
// Pass an string to the `paint()` method with you want to paint.
|
||||
// This will give you an object back wits can be styled and displayed.
|
||||
let mut styledobject = terminal.paint("Red background color");
|
||||
// Call the method `on()` on the object given by `paint()` and pass in an Color from the Color enum.
|
||||
styledobject = styledobject.on(Color::Red);
|
||||
// Print the object to the console and check see the result
|
||||
println!("{}", styledobject);
|
||||
|
||||
// Crossterm provides method chaining so that the above points can be inlined.
|
||||
println!("{}", terminal.paint("Red background color").on(Color::Red));
|
||||
}
|
||||
|
||||
/// print font with fore- background color | demonstration.
|
||||
pub fn paint_foreground_and_background() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
// Pass an string to the `paint()` method with you want to paint.
|
||||
// This will give you an object back wits can be styled and displayed.
|
||||
let mut styledobject = terminal.paint("Red font on blue background color");
|
||||
/* Foreground color:
|
||||
Call the method `with()` on the object given by `paint()`
|
||||
Pass in an Color from the Color enum.
|
||||
*/
|
||||
styledobject = styledobject.with(Color::Red);
|
||||
/* Background color:
|
||||
Call the method `on()` on the object given by `paint()`
|
||||
Pass in an Color from the Color enum.
|
||||
*/
|
||||
styledobject = styledobject.on(Color::Blue);
|
||||
// Print the object to the console and see the result.
|
||||
println!("{}", styledobject);
|
||||
|
||||
// Crossterm provides method chaining so that the above points can be inlined.
|
||||
println!(
|
||||
"{}",
|
||||
terminal
|
||||
.paint("Red font on blue background color")
|
||||
.with(Color::Red)
|
||||
.on(Color::Blue)
|
||||
);
|
||||
}
|
||||
|
||||
/// Print all available foreground colors | demonstration.
|
||||
pub fn print_all_foreground_colors() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
println!("Black : \t {}", terminal.paint("■").with(Color::Black));
|
||||
println!("Red : \t\t {}", terminal.paint("■").with(Color::Red));
|
||||
println!(
|
||||
"Dark Red: \t {}",
|
||||
terminal.paint("■").with(Color::DarkRed)
|
||||
);
|
||||
println!("Green : \t {}", terminal.paint("■").with(Color::Green));
|
||||
println!(
|
||||
"Dark Green : \t {}",
|
||||
terminal.paint("■").with(Color::DarkGreen)
|
||||
);
|
||||
println!("Yellow : \t {}", terminal.paint("■").with(Color::Yellow));
|
||||
println!(
|
||||
"Dark Yellow : \t {}",
|
||||
terminal.paint("■").with(Color::DarkYellow)
|
||||
);
|
||||
println!("Blue : \t\t {}", terminal.paint("■").with(Color::Blue));
|
||||
println!(
|
||||
"Dark Blue : \t {}",
|
||||
terminal.paint("■").with(Color::DarkBlue)
|
||||
);
|
||||
println!(
|
||||
"Magenta : \t {}",
|
||||
terminal.paint("■").with(Color::Magenta)
|
||||
);
|
||||
println!(
|
||||
"Dark Magenta : \t {}",
|
||||
terminal.paint("■").with(Color::DarkMagenta)
|
||||
);
|
||||
println!("Cyan : \t\t {}", terminal.paint("■").with(Color::Cyan));
|
||||
println!(
|
||||
"Dark Cyan : \t {}",
|
||||
terminal.paint("■").with(Color::DarkCyan)
|
||||
);
|
||||
println!("Grey : \t\t {}", terminal.paint("■").with(Color::Grey));
|
||||
println!("White : \t {}", terminal.paint("■").with(Color::White));
|
||||
}
|
||||
|
||||
/// Print all available foreground colors | demonstration.
|
||||
pub fn print_all_background_colors() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
println!("Black : \t {}", terminal.paint(" ").on(Color::Black));
|
||||
println!("Red : \t\t {}", terminal.paint(" ").on(Color::Red));
|
||||
println!("Dark Red: \t {}", terminal.paint(" ").on(Color::DarkRed));
|
||||
println!("Green : \t {}", terminal.paint(" ").on(Color::Green));
|
||||
println!(
|
||||
"Dark Green : \t {}",
|
||||
terminal.paint(" ").on(Color::DarkGreen)
|
||||
);
|
||||
println!("Yellow : \t {}", terminal.paint(" ").on(Color::Yellow));
|
||||
println!(
|
||||
"Dark Yellow : \t {}",
|
||||
terminal.paint(" ").on(Color::DarkYellow)
|
||||
);
|
||||
println!("Blue : \t\t {}", terminal.paint(" ").on(Color::Blue));
|
||||
println!(
|
||||
"Dark Blue : \t {}",
|
||||
terminal.paint(" ").on(Color::DarkBlue)
|
||||
);
|
||||
println!("Magenta : \t {}", terminal.paint(" ").on(Color::Magenta));
|
||||
println!(
|
||||
"Dark Magenta : \t {}",
|
||||
terminal.paint(" ").on(Color::DarkMagenta)
|
||||
);
|
||||
println!("Cyan : \t\t {}", terminal.paint(" ").on(Color::Cyan));
|
||||
println!(
|
||||
"Dark Cyan : \t {}",
|
||||
terminal.paint(" ").on(Color::DarkCyan)
|
||||
);
|
||||
println!("Grey : \t\t {}", terminal.paint(" ").on(Color::Grey));
|
||||
println!("White : \t {}", terminal.paint(" ").on(Color::White));
|
||||
#[cfg(unix)]
|
||||
println!(
|
||||
"RGB (10,10,10): \t {}",
|
||||
terminal.paint(" ").on(Color::Rgb {
|
||||
r: 10,
|
||||
g: 10,
|
||||
b: 10
|
||||
})
|
||||
);
|
||||
#[cfg(unix)]
|
||||
println!(
|
||||
"RGB (10,10,10): \t {}",
|
||||
terminal.paint(" ").on(Color::AnsiValue(50))
|
||||
);
|
||||
}
|
||||
|
||||
/// Print font with all available attributes. Note that this can only be used at unix systems and that some are not supported widely | demonstration..
|
||||
#[cfg(unix)]
|
||||
pub fn print_font_with_attributes() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
println!("{}", terminal.paint("Normal text"));
|
||||
println!("{}", terminal.paint("Bold text").bold());
|
||||
println!("{}", terminal.paint("Italic text").italic());
|
||||
println!("{}", terminal.paint("Slow blinking text").slow_blink());
|
||||
println!("{}", terminal.paint("Rapid blinking text").rapid_blink());
|
||||
println!("{}", terminal.paint("Hidden text").hidden());
|
||||
println!("{}", terminal.paint("Underlined text").underlined());
|
||||
println!("{}", terminal.paint("Reversed color").reverse());
|
||||
println!("{}", terminal.paint("Dim text color").dim());
|
||||
println!("{}", terminal.paint("Crossed out font").crossed_out());
|
||||
}
|
||||
|
||||
/// Print all supported rgb colors | demonstration.
|
||||
#[cfg(unix)]
|
||||
pub fn print_supported_colors() {
|
||||
let context = Context::new();
|
||||
let terminal = terminal::terminal(&context);
|
||||
|
||||
let count = crossterm::style::color(&context)
|
||||
.get_available_color_count()
|
||||
.unwrap();
|
||||
|
||||
for i in 0..count {
|
||||
println!(
|
||||
"{}",
|
||||
terminal
|
||||
.paint(format!("Color: {}", i))
|
||||
.with(Color::AnsiValue(i as u8))
|
||||
);
|
||||
}
|
||||
}
|
67
examples/Crossterm 0.3.1/crossterm_type/mod.rs
Normal file
67
examples/Crossterm 0.3.1/crossterm_type/mod.rs
Normal file
@ -0,0 +1,67 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::Crossterm;
|
||||
|
||||
/// use the `Crossterm` to get an instance to the cursor module | demonstration.
|
||||
pub fn use_crossterm_cursor()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
let mut cursor = crossterm.cursor();
|
||||
cursor.goto(5,5).print("test");
|
||||
}
|
||||
|
||||
use crossterm::style::Color;
|
||||
|
||||
/// use the `Crossterm` to get an instance to the color module | demonstration.
|
||||
pub fn use_crossterm_color()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
let mut color = crossterm.color();
|
||||
color.set_bg(Color::Red);
|
||||
color.set_fg(Color::Green);
|
||||
}
|
||||
|
||||
use crossterm::terminal::ClearType;
|
||||
|
||||
/// use the `Crossterm` to get an instance to the terminal module | demonstration.
|
||||
pub fn use_crossterm_terminal()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
let mut terminal = crossterm.terminal();
|
||||
terminal.clear(ClearType::All);
|
||||
terminal.set_size(40,40);
|
||||
}
|
||||
|
||||
/// paint text with colors using `Crossterm` | demonstration.
|
||||
pub fn use_crossterm_paint()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
crossterm.paint("Black on BLUE").with(Color::Black).on(Color::Blue);
|
||||
}
|
||||
|
||||
/// write text to terminal using `Crossterm` | demonstration.
|
||||
pub fn use_crossterm_write()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
crossterm.write("some text \nsome text on new line");
|
||||
}
|
||||
|
||||
/// Switch to alternate screen using the `Context` of `Crossterm` | demonstration.
|
||||
pub fn create_alternate_screen_from_crossterm()
|
||||
{
|
||||
use crossterm::screen::*;
|
||||
use std::convert::From;
|
||||
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
{
|
||||
// move into alternate screen
|
||||
let alternate_screen = AlternateScreen::from(crossterm.context());
|
||||
|
||||
// this will move the cursor and print `some text` on the alternate screen.
|
||||
crossterm.cursor().goto(10, 10).print("Some text");
|
||||
} // <- alternate screen ends here an will be switched back to main screen.
|
||||
|
||||
// print "Some other text" on the mainscreen at x: 0, y: 10
|
||||
crossterm.cursor().goto(0,10).print("Some other text");
|
||||
}
|
141
examples/Crossterm 0.3.1/cursor/mod.rs
Normal file
141
examples/Crossterm 0.3.1/cursor/mod.rs
Normal file
@ -0,0 +1,141 @@
|
||||
//!
|
||||
//! Examples of actions that could be performed with te cursor.
|
||||
//!
|
||||
|
||||
extern crate crossterm;
|
||||
use self::crossterm::cursor::{cursor, TerminalCursor};
|
||||
use self::crossterm::Context;
|
||||
|
||||
/// Set the cursor to position X: 10, Y: 5 in the terminal.
|
||||
pub fn goto() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
// Set the cursor to position X: 10, Y: 5 in the terminal
|
||||
cursor.goto(10, 5);
|
||||
}
|
||||
|
||||
/// get the cursor position
|
||||
pub fn pos() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
// get the cursor position.
|
||||
let (x, y) = cursor.pos();
|
||||
}
|
||||
|
||||
/// Move the cursor 3 up | demonstration.
|
||||
pub fn move_up() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
|
||||
// Move the cursor to position 3 times to the up in the terminal
|
||||
cursor.move_up(10);
|
||||
}
|
||||
|
||||
/// Move the cursor 3 to the right | demonstration.
|
||||
pub fn move_right() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
// Move the cursor to position 3 times to the right in the terminal
|
||||
cursor.move_right(3);
|
||||
}
|
||||
|
||||
/// Move the cursor 3 down | demonstration.
|
||||
pub fn move_down() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
// Move the cursor to position 3 times to the down in the terminal
|
||||
cursor.move_down(3);
|
||||
}
|
||||
|
||||
/// Move the cursor 3 to the left | demonstration.
|
||||
pub fn move_left() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
// Move the cursor to position 3 times to the left in the terminal
|
||||
cursor.move_left(3);
|
||||
}
|
||||
|
||||
/// Print character at X: 10 Y: 5 | demonstration.
|
||||
pub fn print() {
|
||||
let context = Context::new();
|
||||
|
||||
// To print an some displayable content on an certain position.
|
||||
|
||||
// Get the cursor
|
||||
let mut cursor = cursor(&context);
|
||||
// Set the cursor to position X: 10, Y: 5 in the terminal
|
||||
cursor.goto(10, 5);
|
||||
// Print the @ symbol at position X: 10, Y: 5 in the terminal
|
||||
print!("@");
|
||||
// Rust is line buffered inorder to print at an certain position we need to clear the buffer first.
|
||||
use std;
|
||||
use std::io::Write;
|
||||
std::io::stdout().flush();
|
||||
|
||||
/* Because the above method is a little to much code,
|
||||
you can use the `print()` method for printing an value at an certain position in the terminal.
|
||||
|
||||
Crossterm provides method chaining so that the above points can be inlined.
|
||||
*/
|
||||
|
||||
cursor.goto(10, 5).print("@");
|
||||
}
|
||||
|
||||
/// Save and reset cursor position | demonstration..
|
||||
pub fn safe_and_reset_position() {
|
||||
let context = Context::new();
|
||||
|
||||
let mut cursor = cursor(&context);
|
||||
|
||||
// Goto X: 5 Y: 5
|
||||
cursor.goto(5, 5);
|
||||
// Safe cursor position: X: 5 Y: 5
|
||||
cursor.save_position();
|
||||
// Goto X: 5 Y: 20
|
||||
cursor.goto(5, 20);
|
||||
// Print at X: 5 Y: 20.
|
||||
println!("Yea!");
|
||||
// Reset back to X: 5 Y: 5.
|
||||
cursor.reset_position();
|
||||
// Print Back at X: 5 Y: 5.
|
||||
println!("Back");
|
||||
|
||||
println!()
|
||||
}
|
||||
|
||||
/// Hide cursor display | demonstration.
|
||||
pub fn hide_cursor() {
|
||||
let context = Context::new();
|
||||
|
||||
let cursor = cursor(&context);
|
||||
cursor.hide();
|
||||
}
|
||||
|
||||
/// Show cursor display | demonstration.
|
||||
pub fn show_cursor() {
|
||||
let context = Context::new();
|
||||
|
||||
let cursor = cursor(&context);
|
||||
cursor.show();
|
||||
}
|
||||
|
||||
/// Show cursor display, only works on certain terminals.| demonstration
|
||||
pub fn blink_cursor() {
|
||||
let context = Context::new();
|
||||
|
||||
let cursor = cursor(&context);
|
||||
cursor.blink(false);
|
||||
cursor.blink(false);
|
||||
}
|
51
examples/Crossterm 0.3.1/input/keyboard/async_input.rs
Normal file
51
examples/Crossterm 0.3.1/input/keyboard/async_input.rs
Normal file
@ -0,0 +1,51 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::Context;
|
||||
|
||||
use std::{thread, time};
|
||||
use std::io::Read;
|
||||
|
||||
// this will capture the input until the given key was pressed.
|
||||
pub fn capture_input_until_a_certain_char_async()
|
||||
{
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
|
||||
let mut stdin = input.read_until_async(b'\r').bytes();
|
||||
|
||||
for i in 0..100
|
||||
{
|
||||
let a = stdin.next();
|
||||
|
||||
if let Some(Ok(b'x')) = a {
|
||||
println!("The key: x was pressed.");
|
||||
break;
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(50));
|
||||
}
|
||||
}
|
||||
|
||||
// this will capture an character input until the given key was pressed.
|
||||
pub fn read_async()
|
||||
{
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
for i in 0..100
|
||||
{
|
||||
let a = stdin.next();
|
||||
|
||||
println!("pressed: {:?}", a);
|
||||
|
||||
if let Some(Ok(b'x')) = a {
|
||||
println!("The key: x was pressed.");
|
||||
break;
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(50));
|
||||
}
|
||||
}
|
0
examples/Crossterm 0.3.1/input/keyboard/input
Normal file
0
examples/Crossterm 0.3.1/input/keyboard/input
Normal file
28
examples/Crossterm 0.3.1/input/keyboard/input.rs
Normal file
28
examples/Crossterm 0.3.1/input/keyboard/input.rs
Normal file
@ -0,0 +1,28 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::Context;
|
||||
|
||||
pub fn read_char()
|
||||
{
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
|
||||
match input.read_char()
|
||||
{
|
||||
Ok(c) => println!("character pressed: {}", c),
|
||||
Err(e) => println!("error: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_line()
|
||||
{
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
|
||||
match input.read_line()
|
||||
{
|
||||
Ok(s) => println!("string typed: {}", s),
|
||||
Err(e) => println!("error: {}", e)
|
||||
}
|
||||
}
|
2
examples/Crossterm 0.3.1/input/keyboard/mod.rs
Normal file
2
examples/Crossterm 0.3.1/input/keyboard/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod async_input;
|
||||
pub mod input;
|
1
examples/Crossterm 0.3.1/input/mod.rs
Normal file
1
examples/Crossterm 0.3.1/input/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod keyboard;
|
8
examples/Crossterm 0.3.1/program_examples/README.md
Normal file
8
examples/Crossterm 0.3.1/program_examples/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
This folder will contain some examples of how to use this crate in an real live environment.
|
||||
|
||||
If you have created a game or something feel free to upload it, would be a great help for other people and me to make this crate better!
|
||||
|
||||
The programs are:
|
||||
|
||||
- First depth search:
|
||||
This is an search algorithm implemented visually. This program uses the following functionalities: cursor movement, coloring, alternate screen and terminal clearing.
|
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "first_depth_search"
|
||||
version = "0.1.0"
|
||||
authors = ["TimonPost <timonpost@hotmail.nl>"]
|
||||
|
||||
[dependencies]
|
||||
rand = "0.4.2"
|
||||
|
||||
[dependencies.crossterm]
|
||||
path = "../../../../"
|
||||
branch = "development"
|
@ -0,0 +1,155 @@
|
||||
//! Implementation of the first depth search algorithm
|
||||
use super::variables::{Direction, Position};
|
||||
use super::messages::END_MESSAGE;
|
||||
use super::map::Map;
|
||||
|
||||
use crossterm::style::Color;
|
||||
use crossterm::Crossterm;
|
||||
|
||||
use super::rand;
|
||||
use super::rand::distributions::{IndependentSample, Range};
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::{thread, time};
|
||||
|
||||
pub struct FirstDepthSearch<'crossterm>
|
||||
{
|
||||
direction: Direction,
|
||||
map: Map,
|
||||
stack: Vec<Position>,
|
||||
root_pos: Position,
|
||||
is_terminated: bool,
|
||||
crossterm: &'crossterm Crossterm
|
||||
}
|
||||
|
||||
impl<'crossterm> FirstDepthSearch<'crossterm>
|
||||
{
|
||||
pub fn new(map: Map, start_pos: Position, crossterm: &'crossterm Crossterm) -> FirstDepthSearch<'crossterm>
|
||||
{
|
||||
FirstDepthSearch
|
||||
{
|
||||
direction: Direction::Up,
|
||||
map: map,
|
||||
stack: Vec::new(),
|
||||
root_pos: start_pos,
|
||||
is_terminated: false,
|
||||
crossterm: crossterm,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self)
|
||||
{
|
||||
self.is_terminated = false;
|
||||
|
||||
// push first position on the stack
|
||||
self.stack.push(self.root_pos);
|
||||
|
||||
let mut cursor = self.crossterm.cursor();
|
||||
cursor.hide();
|
||||
|
||||
// loop until there are now items left in the stack.
|
||||
loop {
|
||||
if self.stack.len() == 0
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
self.choose_random_neighbor();
|
||||
|
||||
if self.is_terminated
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
self.update_position();
|
||||
|
||||
let cell = self.crossterm.paint(" ").on(Color::Blue);
|
||||
|
||||
let pos = self.root_pos.clone();
|
||||
|
||||
let x = pos.x as u16;
|
||||
let y = pos.y as u16;
|
||||
|
||||
cursor.goto(x,y).print(cell);
|
||||
::std::io::stdout().flush();
|
||||
|
||||
thread::sleep(time::Duration::from_millis(2));
|
||||
}
|
||||
}
|
||||
|
||||
/// With this function we are choosing an random neighbor that we havent visited yet.
|
||||
fn choose_random_neighbor(&mut self)
|
||||
{
|
||||
let mut available_directions: Vec<Direction> = Vec::with_capacity(4);
|
||||
|
||||
// check every direction if the direction is not visited we can add it to the list.
|
||||
// note that if the y or x is 0 that we don't want to subtract because we get an subtract overflow.
|
||||
if self.root_pos.y != 0 && !self.map.is_cell_visited(self.root_pos.x, self.root_pos.y - 1)
|
||||
{
|
||||
available_directions.push(Direction::Up)
|
||||
}
|
||||
|
||||
if !&self.map.is_cell_visited(self.root_pos.x, self.root_pos.y + 1)
|
||||
{
|
||||
available_directions.push(Direction::Down)
|
||||
}
|
||||
|
||||
if self.root_pos.x != 0 && !self.map.is_cell_visited(self.root_pos.x - 1, self.root_pos.y)
|
||||
{
|
||||
available_directions.push(Direction::Left)
|
||||
}
|
||||
|
||||
if !&self.map.is_cell_visited(self.root_pos.x + 1, self.root_pos.y)
|
||||
{
|
||||
available_directions.push(Direction::Right)
|
||||
}
|
||||
|
||||
let directions_count = available_directions.len();
|
||||
|
||||
// if there are no directions left we need to backtrack until we find directions to go to.
|
||||
if directions_count != 0
|
||||
{
|
||||
let step = Range::new(0, directions_count);
|
||||
let mut rng = rand::thread_rng();
|
||||
let choice = step.ind_sample(&mut rng);
|
||||
|
||||
// set the current direction to the new random generated direction.
|
||||
self.direction = available_directions[choice];
|
||||
}
|
||||
else {
|
||||
self.find_first_possible_direction();
|
||||
}
|
||||
}
|
||||
|
||||
/// Find direction to go to if there is no direction pop the current position of the stack for back tracking to the previous position.
|
||||
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()
|
||||
{
|
||||
// update root pos to previous cell and continue searching for new neighbours
|
||||
self.root_pos = *previous_cell;
|
||||
self.choose_random_neighbor();
|
||||
}
|
||||
else {
|
||||
self.is_terminated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// update the root position to the new direction we went in
|
||||
fn update_position(&mut self)
|
||||
{
|
||||
match self.direction
|
||||
{
|
||||
Direction::Up => self.root_pos.y -= 1,
|
||||
Direction::Down => self.root_pos.y += 1,
|
||||
Direction::Left => self.root_pos.x -= 1,
|
||||
Direction::Right => self.root_pos.x += 1,
|
||||
_ => panic!()
|
||||
};
|
||||
|
||||
self.map.set_visited(self.root_pos.x, self.root_pos.y);
|
||||
self.stack.push(self.root_pos);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
extern crate rand;
|
||||
extern crate crossterm;
|
||||
|
||||
mod map;
|
||||
mod algorithm;
|
||||
mod messages;
|
||||
mod variables;
|
||||
|
||||
use crossterm::Crossterm;
|
||||
use crossterm::terminal::ClearType;
|
||||
use crossterm::style::Color;
|
||||
use crossterm::screen;
|
||||
|
||||
use self::variables::{Size, Position };
|
||||
use self::messages::WELCOME_MESSAGE;
|
||||
|
||||
use std::iter::Iterator;
|
||||
use std::{thread, time};
|
||||
|
||||
fn main()
|
||||
{
|
||||
run();
|
||||
}
|
||||
|
||||
/// run the program
|
||||
pub fn run()
|
||||
{
|
||||
// // create new Crossterm instance.
|
||||
// let mut crossterm = Crossterm::new();
|
||||
//
|
||||
// print_welcome_screen(&crossterm);
|
||||
//
|
||||
// start_algorithm(&mut crossterm);
|
||||
//
|
||||
// print_end_screen(&crossterm);
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn start_algorithm(crossterm: &mut Crossterm)
|
||||
{
|
||||
// we first want to switch to alternate screen. On the alternate screen we are going to run or firstdepthsearch algorithm
|
||||
let alternate_screen = screen::AlternateScreen::from(crossterm.context());
|
||||
|
||||
// setup the map size and the position to start searching for a path.
|
||||
let map_size = Size::new(100,40);
|
||||
let start_pos = Position::new(10,10);
|
||||
|
||||
// create and render the map. Or map border is going to have an █ look and inside the map is just a space.
|
||||
let mut map = map::Map::new(map_size, '█', ' ');
|
||||
map.render_map(crossterm);
|
||||
|
||||
// create the algorithm and start the
|
||||
let mut algorithm = algorithm::FirstDepthSearch::new(map, start_pos, &crossterm);
|
||||
algorithm.start();
|
||||
}
|
||||
|
||||
fn print_end_screen(crossterm: &Crossterm)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
fn print_welcome_screen(crossterm: &Crossterm)
|
||||
{
|
||||
// create the handle for the cursor and terminal.
|
||||
let mut cursor = crossterm.cursor();
|
||||
let mut terminal = crossterm.terminal();
|
||||
|
||||
// clear the screen and print the welcome message.
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(0,0);
|
||||
terminal.write(WELCOME_MESSAGE.join("\n"));
|
||||
|
||||
cursor.hide();
|
||||
cursor.goto(0,10);
|
||||
terminal.write(
|
||||
"The first depth search algorithm will start in: Seconds"
|
||||
);
|
||||
|
||||
// print some progress example.
|
||||
for i in (1..5).rev() {
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor
|
||||
.goto(48, 10)
|
||||
.print(terminal.paint(format!("{}", i)).with(Color::Red).on(Color::Blue));
|
||||
|
||||
// 1 second delay
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
use super::variables::{Cell, Position, Size };
|
||||
use crossterm::terminal::terminal;
|
||||
use crossterm::cursor::cursor;
|
||||
use crossterm::Crossterm;
|
||||
use crossterm::style::{ObjectStyle, StyledObject, Color};
|
||||
use crossterm::Context;
|
||||
use std::rc::Rc;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
pub struct Map
|
||||
{
|
||||
pub map: Vec<Vec<Cell>>,
|
||||
pub size: Size,
|
||||
}
|
||||
|
||||
impl Map
|
||||
{
|
||||
pub fn new(map_size: Size, wall_cell_char: char, map_cell_char: char) -> Map
|
||||
{
|
||||
let mut map: Vec<Vec<Cell>> = Vec::new();
|
||||
|
||||
// initialize the map shown on the screen. Each cell of terminal should have a value that could be changed by the algorithm
|
||||
// create n rows with n cells.
|
||||
for y in 0..map_size.height
|
||||
{
|
||||
let mut row: Vec<Cell> = Vec::new();
|
||||
|
||||
for x in 0..map_size.width
|
||||
{
|
||||
if (y == 0 || y == map_size.height - 1) || (x == 0 || x == map_size.width - 1)
|
||||
{
|
||||
row.push(Cell::new(Position::new(x, y), Color::Black, wall_cell_char, true));
|
||||
} else {
|
||||
row.push(Cell::new(Position::new(x, y), Color::Black, map_cell_char, false));
|
||||
}
|
||||
}
|
||||
map.push(row);
|
||||
}
|
||||
|
||||
Map { map: map, size: Size::new(map_size.width, map_size.height)}
|
||||
}
|
||||
|
||||
// render the map on the screen.
|
||||
pub fn render_map(&mut self, crossterm: &mut Crossterm)
|
||||
{
|
||||
let mut cursor = crossterm.cursor();
|
||||
|
||||
for row in self.map.iter_mut()
|
||||
{
|
||||
for column in row.iter_mut()
|
||||
{
|
||||
// we only have to render the walls
|
||||
if (column.position.y == 0 || column.position.y == self.size.height - 1) || (column.position.x == 0 || column.position.x == self.size.width - 1)
|
||||
{
|
||||
let cell_style = crossterm.paint(column.look).on(column.color);
|
||||
cursor.goto(column.position.x as u16, column.position.y as u16)
|
||||
.print(cell_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if position in the map at the given coords is visted.
|
||||
pub fn is_cell_visited(&self, x: usize, y: usize) -> bool
|
||||
{
|
||||
self.map[y][x].visited
|
||||
}
|
||||
|
||||
// change an position in the map to visited.
|
||||
pub fn set_visited(&mut self, x: usize, y: usize)
|
||||
{
|
||||
self.map[y][x].visited = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
use super::variables::Position;
|
||||
|
||||
pub const WELCOME_MESSAGE: [&str; 6] =
|
||||
[
|
||||
"__ __ .__ __ ",
|
||||
"/ \\ / \\ ____ | | | | ______ _____ ____ ",
|
||||
"\\ \\/\\/ // __ \\| | | |/ / _ \\ / \\_/ __ \\ ",
|
||||
" \\ /\\ ___/| |_| < <_> ) Y Y \\ ___/ ",
|
||||
" \\__/\\ / \\___ >____/__|_ \\____/|__|_| /\\___ > ",
|
||||
" \\/ \\/ \\/ \\/ \\/ "
|
||||
];
|
||||
|
||||
pub const END_MESSAGE: [&str; 5] =
|
||||
[
|
||||
"-----------------------",
|
||||
" ",
|
||||
" No routes (DONE) ",
|
||||
" ",
|
||||
"-----------------------",
|
||||
];
|
||||
|
||||
pub fn print_stack_count(position: Position)
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
mod map;
|
||||
mod messages;
|
||||
mod variables;
|
||||
mod algorithm;
|
@ -0,0 +1,63 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::terminal::{terminal, ClearType};
|
||||
use self::crossterm::style::{Color, StyledObject, ObjectStyle };
|
||||
use self::crossterm::Context;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone,Debug)]
|
||||
pub enum Direction
|
||||
{
|
||||
Up = 0,
|
||||
Down = 1,
|
||||
Left = 2,
|
||||
Right = 3
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Position
|
||||
{
|
||||
pub x: usize,
|
||||
pub y: usize
|
||||
}
|
||||
|
||||
impl Position
|
||||
{
|
||||
pub fn new(x: usize, y: usize) -> Position
|
||||
{
|
||||
Position { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Size
|
||||
{
|
||||
pub width: usize,
|
||||
pub height: usize
|
||||
}
|
||||
|
||||
impl Size
|
||||
{
|
||||
pub fn new(width: usize, height: usize) -> Size
|
||||
{
|
||||
Size {width,height}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Cell
|
||||
{
|
||||
pub position: Position,
|
||||
pub color: Color,
|
||||
pub look: char,
|
||||
pub visited: bool
|
||||
}
|
||||
|
||||
impl Cell
|
||||
{
|
||||
pub fn new(position: Position, color: Color, look: char, visited: bool) -> Cell
|
||||
{
|
||||
Cell { position, color, look, visited }
|
||||
}
|
||||
}
|
81
examples/Crossterm 0.3.1/terminal/alternate_screen.rs
Normal file
81
examples/Crossterm 0.3.1/terminal/alternate_screen.rs
Normal file
@ -0,0 +1,81 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::style::Color;
|
||||
use crossterm::cursor::cursor;
|
||||
use crossterm::screen::AlternateScreen;
|
||||
use crossterm::terminal::{self, ClearType};
|
||||
use crossterm::Context;
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::rc::Rc;
|
||||
use std::{thread, time};
|
||||
|
||||
fn print_wait_screen(context: Rc<Context>) {
|
||||
let mut terminal = terminal::terminal(&context);
|
||||
terminal.clear(ClearType::All);
|
||||
|
||||
let mut cursor = cursor(&context);
|
||||
cursor.goto(0, 0);
|
||||
cursor.hide();
|
||||
|
||||
terminal.write(
|
||||
"Welcome to the wait screen.\n\
|
||||
Please wait a few seconds until we arrive back at the main screen.\n\
|
||||
Progress: ",
|
||||
);
|
||||
|
||||
// print some progress example.
|
||||
for i in 1..5 {
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor
|
||||
.goto(10, 2)
|
||||
.print(terminal.paint(format!("{} of the 5 items processed", i)).with(Color::Red).on(Color::Blue));
|
||||
|
||||
// 1 second delay
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
}
|
||||
|
||||
stdout().flush();
|
||||
}
|
||||
|
||||
/// print wait screen on alternate screen, then swich back.
|
||||
pub fn print_wait_screen_on_alternate_window(context: Rc<Context>) {
|
||||
// create scope. If this scope ends the screen will be switched back to mainscreen.
|
||||
// because `AlternateScreen` switches back to main screen when switching back.
|
||||
{
|
||||
// create new alternate screen instance and switch to the alternate screen.
|
||||
let mut screen = AlternateScreen::from(context.clone());
|
||||
|
||||
write!(screen, "test");
|
||||
println!();
|
||||
// Print the wait screen.
|
||||
print_wait_screen(context.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// some stress test switch from and to alternate screen.
|
||||
pub fn switch_between_main_and_alternate_screen() {
|
||||
let context = Context::new();
|
||||
let mut cursor = cursor(&context);
|
||||
|
||||
{
|
||||
// create new alternate screen instance and switch to the alternate screen.
|
||||
let mut screen = AlternateScreen::from(context.clone());
|
||||
cursor.goto(0, 0);
|
||||
write!(screen, "we are at the alternate screen!");
|
||||
screen.flush();
|
||||
thread::sleep(time::Duration::from_secs(3));
|
||||
|
||||
screen.to_main();
|
||||
write!(screen, "we are at the main screen!");
|
||||
screen.flush();
|
||||
thread::sleep(time::Duration::from_secs(3));
|
||||
|
||||
screen.to_alternate();
|
||||
write!(screen, "we are at the alternate screen!");
|
||||
screen.flush();
|
||||
thread::sleep(time::Duration::from_secs(3));
|
||||
}
|
||||
|
||||
println!("Whe are back at the main screen");
|
||||
}
|
8
examples/Crossterm 0.3.1/terminal/mod.rs
Normal file
8
examples/Crossterm 0.3.1/terminal/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
/// Examples of actions that could be performed on the alternatescreen.
|
||||
pub mod alternate_screen;
|
||||
|
||||
/// Examples of actions that could be performed on the terminal.
|
||||
pub mod terminal;
|
||||
|
||||
// Raw screen
|
||||
pub mod raw_mode;
|
56
examples/Crossterm 0.3.1/terminal/raw_mode.rs
Normal file
56
examples/Crossterm 0.3.1/terminal/raw_mode.rs
Normal file
@ -0,0 +1,56 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::cursor::cursor;
|
||||
use crossterm::screen::AlternateScreen;
|
||||
use crossterm::terminal::{self, ClearType};
|
||||
use crossterm::Context;
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::rc::Rc;
|
||||
use std::{thread, time};
|
||||
|
||||
use crossterm::raw::IntoRawMode;
|
||||
|
||||
// raw screen is not working correctly currently
|
||||
fn print_wait_screen(context: Rc<Context>) {
|
||||
terminal::terminal(&context).clear(ClearType::All);
|
||||
|
||||
let mut cursor = cursor(&context);
|
||||
cursor.goto(0, 0).print("Welcome to the wait screen.");
|
||||
cursor
|
||||
.goto(0, 1)
|
||||
.print("Please wait a few seconds until we arrive back at the main screen.");
|
||||
cursor.goto(0, 2).print("Progress: ");
|
||||
|
||||
// print some progress example.
|
||||
for i in 1..5 {
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor
|
||||
.goto(10, 2)
|
||||
.print(format!("{} of the 5 items processed", i));
|
||||
|
||||
// 1 second delay
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_wait_screen_on_alternate_window() {
|
||||
let context = Context::new();
|
||||
|
||||
// create scope. If this scope ends the screen will be switched back to mainscreen.
|
||||
// because `AlternateScreen` switches back to main screen when going out of scope.
|
||||
{
|
||||
// create new alternate screen instance this call is also switching the screen to alternate screen.
|
||||
// then convert the output of the program to raw mode.
|
||||
// then print the wait screen on the alternate screen in raw mode.
|
||||
let mut screen = AlternateScreen::from(context.clone());
|
||||
let raw_screen = screen.into_raw_mode(context.clone());
|
||||
|
||||
// Print the wait screen.
|
||||
print_wait_screen(context.clone());
|
||||
|
||||
screen.flush();
|
||||
}
|
||||
|
||||
println!("Whe are back at the main screen");
|
||||
}
|
160
examples/Crossterm 0.3.1/terminal/terminal.rs
Normal file
160
examples/Crossterm 0.3.1/terminal/terminal.rs
Normal file
@ -0,0 +1,160 @@
|
||||
//!
|
||||
//! Terminal Examples
|
||||
//!
|
||||
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::cursor;
|
||||
use crossterm::terminal::{terminal, ClearType};
|
||||
use crossterm::Context;
|
||||
|
||||
fn print_test_data() {
|
||||
for i in 0..100 {
|
||||
println!("Test data to test terminal: {}", i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear all lines in terminal | demonstration
|
||||
pub fn clear_all_lines() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
print_test_data();
|
||||
|
||||
// Clear all lines in terminal;
|
||||
terminal.clear(ClearType::All);
|
||||
}
|
||||
|
||||
/// Clear all lines from cursor position X:4, Y:4 down | demonstration
|
||||
pub fn clear_from_cursor_down() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
print_test_data();
|
||||
|
||||
// Set terminal cursor position (see example for more info).
|
||||
cursor::cursor(&context).goto(4, 8);
|
||||
|
||||
// Clear all cells from current cursor position down.
|
||||
terminal.clear(ClearType::FromCursorDown);
|
||||
}
|
||||
|
||||
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
|
||||
pub fn clear_from_cursor_up() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
print_test_data();
|
||||
|
||||
// Set terminal cursor position (see example for more info).
|
||||
cursor::cursor(&context).goto(4, 4);
|
||||
|
||||
// Clear all cells from current cursor position down.
|
||||
terminal.clear(ClearType::FromCursorUp);
|
||||
}
|
||||
|
||||
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
|
||||
pub fn clear_current_line() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
print_test_data();
|
||||
|
||||
// Set terminal cursor position (see example for more info).
|
||||
cursor::cursor(&context).goto(4, 4);
|
||||
|
||||
// Clear current line cells.
|
||||
terminal.clear(ClearType::CurrentLine);
|
||||
}
|
||||
|
||||
/// Clear all lines from cursor position X:4, Y:7 up | demonstration
|
||||
pub fn clear_until_new_line() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
print_test_data();
|
||||
|
||||
// Set terminal cursor position (see example for more info).
|
||||
cursor::cursor(&context).goto(4, 20);
|
||||
|
||||
// Clear all the cells until next line.
|
||||
terminal.clear(ClearType::UntilNewLine);
|
||||
}
|
||||
|
||||
/// Print the the current terminal size | demonstration.
|
||||
pub fn print_terminal_size() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
// Get terminal size
|
||||
let terminal_size = terminal.terminal_size();
|
||||
// Print results
|
||||
print!("X: {}, y: {}", terminal_size.0, terminal_size.1);
|
||||
}
|
||||
|
||||
/// Set the terminal size to width 10, height: 10 | demonstration.
|
||||
pub fn set_terminal_size() {
|
||||
let context = Context::new();
|
||||
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
terminal.set_size(10, 10);
|
||||
}
|
||||
|
||||
/// Scroll down 10 lines | demonstration.
|
||||
pub fn scroll_down() {
|
||||
let context = Context::new();
|
||||
|
||||
print_test_data();
|
||||
|
||||
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
// Scroll down 10 lines.
|
||||
terminal.scroll_down(10);
|
||||
}
|
||||
|
||||
/// Scroll down 10 lines | demonstration.
|
||||
pub fn scroll_up() {
|
||||
let context = Context::new();
|
||||
|
||||
print_test_data();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
// Scroll up 10 lines.
|
||||
terminal.scroll_up(5);
|
||||
}
|
||||
|
||||
/// Resize the terminal to X: 10, Y: 10 | demonstration.
|
||||
pub fn resize_terminal() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
|
||||
// Get terminal size
|
||||
terminal.set_size(10, 10);
|
||||
}
|
||||
|
||||
/// exit the current proccess.
|
||||
pub fn exit() {
|
||||
let context = Context::new();
|
||||
|
||||
// Get terminal
|
||||
let mut terminal = terminal(&context);
|
||||
// Get terminal size
|
||||
terminal.exit();
|
||||
}
|
@ -15,10 +15,10 @@ impl TerminalInput
|
||||
pub fn new(context: Rc<Context>) -> TerminalInput
|
||||
{
|
||||
#[cfg(target_os = "windows")]
|
||||
let input = Box::from(WindowsInput::new());
|
||||
let input = Box::from(WindowsInput::new(context.clone()));
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let cursor = Box::from(UnixInput::new());
|
||||
let input = Box::from(UnixInput::new());
|
||||
|
||||
TerminalInput {
|
||||
terminal_input: input,
|
||||
@ -28,32 +28,27 @@ impl TerminalInput
|
||||
|
||||
pub fn read_line(&self) -> io::Result<String>
|
||||
{
|
||||
let mut rv = String::new();
|
||||
io::stdin().read_line(&mut rv)?;
|
||||
let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
rv.truncate(len);
|
||||
Ok(rv)
|
||||
self.terminal_input.read_line()
|
||||
}
|
||||
|
||||
fn read_char(&self) -> io::Result<String>
|
||||
pub fn read_char(&self) -> io::Result<char>
|
||||
{
|
||||
// todo: read char
|
||||
Ok(String::new())
|
||||
return self.terminal_input.read_char()
|
||||
}
|
||||
|
||||
fn read_key(&self) -> io::Result<()>
|
||||
pub fn read_key(&self) -> io::Result<Key>
|
||||
{
|
||||
// todo: read pressed key
|
||||
Ok(())
|
||||
self.terminal_input.read_pressed_key()
|
||||
}
|
||||
|
||||
fn read_async(&self)
|
||||
pub fn read_async(&self) -> AsyncReader
|
||||
{
|
||||
self.terminal_input.read_async()
|
||||
// todo: async reading
|
||||
}
|
||||
|
||||
fn read_until(&self, delimiter: u8)
|
||||
{ // todo: read until char
|
||||
pub fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||
{ self.terminal_input.read_until_async(delimiter)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,21 +2,75 @@ use std::io;
|
||||
|
||||
pub mod input;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use self::windows_input::WindowsInput;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows_input;
|
||||
mod unix_input;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use self::windows_input::WindowsInput;
|
||||
use self::unix_input::UnixInput;
|
||||
mod unix_input;
|
||||
|
||||
|
||||
pub use self::input::{ input, TerminalInput };
|
||||
|
||||
use std::io::Read;
|
||||
use std::sync::mpsc;
|
||||
|
||||
trait ITerminalInput
|
||||
{
|
||||
fn read_char(&self) -> io::Result<String>;
|
||||
fn read_key(&self) -> io::Result<()>;
|
||||
fn read_line(&self) -> io::Result<String>;
|
||||
|
||||
fn read_async(&self);
|
||||
fn read_until(&self, delimiter: u8);
|
||||
fn read_char(&self) -> io::Result<char>;
|
||||
fn read_pressed_key(&self) -> io::Result<Key>;
|
||||
|
||||
fn read_async(&self) -> AsyncReader;
|
||||
fn read_until_async(&self, delimiter: u8) -> AsyncReader;
|
||||
}
|
||||
|
||||
pub struct AsyncReader
|
||||
{
|
||||
recv: mpsc::Receiver<io::Result<u8>>
|
||||
}
|
||||
|
||||
impl Read for AsyncReader {
|
||||
/// Read from the byte stream.
|
||||
///
|
||||
/// This will never block, but try to drain the event queue until empty. If the total number of
|
||||
/// bytes written is lower than the buffer's length, the event queue is empty or that the event
|
||||
/// stream halted.
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let mut total = 0;
|
||||
|
||||
loop {
|
||||
if total >= buf.len() {
|
||||
break;
|
||||
}
|
||||
|
||||
match self.recv.try_recv() {
|
||||
Ok(Ok(b)) => {
|
||||
buf[total] = b;
|
||||
total += 1;
|
||||
}
|
||||
Ok(Err(e)) => return Err(e),
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(total)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Key {
|
||||
Unknown,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
ArrowUp,
|
||||
ArrowDown,
|
||||
Enter,
|
||||
Escape,
|
||||
Char(char),
|
||||
#[doc(hidden)]
|
||||
__More,
|
||||
}
|
@ -1,3 +1,13 @@
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::char;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
use super::super::terminal::terminal;
|
||||
//use super::super::kernel::unix_kernel::terminal::get_tty;
|
||||
use super::{ Key, ITerminalInput, AsyncReader };
|
||||
|
||||
pub struct UnixInput;
|
||||
|
||||
impl UnixInput
|
||||
@ -7,3 +17,110 @@ impl UnixInput
|
||||
UnixInput {}
|
||||
}
|
||||
}
|
||||
// fn read_line(&self) -> io::Result<String>
|
||||
// {
|
||||
// let mut rv = String::new();
|
||||
// io::stdin().read_line(&mut rv)?;
|
||||
// let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
// rv.truncate(len);
|
||||
// Ok(rv)
|
||||
// }
|
||||
//
|
||||
// fn read_char(&self) -> io::Result<char>
|
||||
// {
|
||||
// let mut buf = [0u8; 20];
|
||||
// let mut termios = termios::Termios::from_fd(fd)?;
|
||||
// let original = termios.clone();
|
||||
// termios::cfmakeraw(&mut termios);
|
||||
// termios::tcsetattr(fd, termios::TCSADRAIN, &termios)?;
|
||||
// let rv = unsafe {
|
||||
// let read = libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, 20);
|
||||
// if read < 0 {
|
||||
// Err(io::Error::last_os_error())
|
||||
// } else if buf[0] == b'\x03' {
|
||||
// Err(io::Error::new(io::ErrorKind::Interrupted, "read interrupted"))
|
||||
// } else {
|
||||
// Ok(key_from_escape_codes(&buf[..read as usize]))
|
||||
// }
|
||||
// };
|
||||
// termios::tcsetattr(fd, termios::TCSADRAIN, &original)?;
|
||||
//
|
||||
// // if the user hit ^C we want to signal SIGINT to outselves.
|
||||
// if let Err(ref err) = rv {
|
||||
// if err.kind() == io::ErrorKind::Interrupted {
|
||||
// unsafe { libc::raise(libc::SIGINT); }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// rv
|
||||
// }
|
||||
//
|
||||
// fn read_pressed_key(&self) -> io::Result<Key>
|
||||
// {
|
||||
// use Context;
|
||||
// let context = Context::new();
|
||||
//
|
||||
// let buf: [u8; 1024] = unsafe { ::std::mem::zeroed() };
|
||||
//// reading::read(&mut buf, &context.screen_manager);
|
||||
//
|
||||
// Ok(Key::Unknown)
|
||||
//// let pressed_char = unsafe { _getwch() };
|
||||
////
|
||||
//// // if 0 or 0xe0 we need to listen again because the next key will be an special key
|
||||
//// if pressed_char == 0 || pressed_char == 0xe0 {
|
||||
//// let special_key: i32 = unsafe { _getwch() };
|
||||
//// println!("spkey {}",special_key);
|
||||
//// return Ok(key_from_key_code(0x26));
|
||||
//// } else {
|
||||
//// match char::from_u32(pressed_char as u32)
|
||||
//// {
|
||||
//// Some(c) => return Ok(Key::Char(c)),
|
||||
//// None => { panic!("Some error needs to be returned") }
|
||||
//// }
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// fn read_async(&self) -> AsyncReader
|
||||
// {
|
||||
// let (send, recv) = mpsc::channel();
|
||||
//
|
||||
// thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||
//
|
||||
// match i {
|
||||
// Ok(byte) => {
|
||||
// let end_of_stream = &byte == &delimiter;
|
||||
// let send_error = send.send(Ok(byte)).is_err();
|
||||
//
|
||||
// if end_of_stream || send_error { return; }
|
||||
// },
|
||||
// Err(_) => { return; }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// AsyncReader { recv: recv }
|
||||
// }
|
||||
//
|
||||
// fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||
// {
|
||||
// let (tx, rx) = mpsc::channel();
|
||||
//
|
||||
// thread::spawn(move || {
|
||||
// loop
|
||||
// {
|
||||
// let pressed_char: u8 = (unsafe { _getwch() }) as u8;
|
||||
//
|
||||
// let end_of_stream = (pressed_char == delimiter);
|
||||
//
|
||||
// // we could return error but maybe option to keep listening until valid character is inputted.
|
||||
// if pressed_char == 0 || pressed_char == 0xe0 || end_of_stream {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// tx.send(Ok(pressed_char as u8));
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// AsyncReader { recv: rx }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
@ -1,40 +1,228 @@
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::char;
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
use super::*;
|
||||
use super::{ Key, ITerminalInput, AsyncReader };
|
||||
|
||||
use winapi::um::winnt::{ INT };
|
||||
use winapi::um::winuser;
|
||||
|
||||
use super::super::terminal::terminal;
|
||||
use super::super::kernel::windows_kernel::reading;
|
||||
use Context;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct WindowsInput
|
||||
{ }
|
||||
{
|
||||
context: Rc<Context>,
|
||||
pub display_input: bool,
|
||||
}
|
||||
|
||||
impl WindowsInput
|
||||
{
|
||||
pub fn new() -> WindowsInput
|
||||
pub fn new(context: Rc<Context>) -> WindowsInput
|
||||
{
|
||||
WindowsInput {}
|
||||
WindowsInput { context, display_input: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl ITerminalInput for WindowsInput
|
||||
{
|
||||
fn read_char(&self) -> io::Result<String>
|
||||
fn read_line(&self) -> io::Result<String>
|
||||
{
|
||||
let mut rv = String::new();
|
||||
Ok(rv)
|
||||
let term = terminal(&self.context);
|
||||
let mut chars: Vec<char> = Vec::new();
|
||||
|
||||
loop {
|
||||
let pressed_char = unsafe { _getwch() };
|
||||
|
||||
// if 0 or 0xe0 we need to listen again because the next key will be an special key
|
||||
if pressed_char != 0 || pressed_char != 0xe0 {
|
||||
match char::from_u32(pressed_char as u32)
|
||||
{
|
||||
Some(c) => {
|
||||
if is_line_end(c) { break; }
|
||||
else { chars.push(c); }
|
||||
|
||||
if self.display_input
|
||||
{
|
||||
term.write(c);
|
||||
}
|
||||
|
||||
fn read_key(&self) -> io::Result<()>
|
||||
{
|
||||
let mut rv = String::new();
|
||||
Ok(())
|
||||
},
|
||||
None => { panic!("Some error needs to be returned") }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn read_async(&self)
|
||||
{
|
||||
|
||||
return Ok(chars.into_iter().collect());
|
||||
}
|
||||
|
||||
fn read_until(&self, delimiter: u8)
|
||||
fn read_char(&self) -> io::Result<char>
|
||||
{
|
||||
let term = terminal(&self.context);
|
||||
|
||||
let pressed_char = unsafe { _getwch() };
|
||||
|
||||
// we could return error but maybe option to keep listening until valid character is inputted.
|
||||
if pressed_char == 0 || pressed_char == 0xe0 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Given input char is not a valid char, mostly occurs when pressing special keys"));
|
||||
}
|
||||
|
||||
match char::from_u32(pressed_char as u32)
|
||||
{
|
||||
Some(c) => {
|
||||
if self.display_input
|
||||
{
|
||||
term.write(c);
|
||||
}
|
||||
return Ok(c);
|
||||
}
|
||||
None => Err(io::Error::new(io::ErrorKind::Other, "Could not parse given input to char"))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_pressed_key(&self) -> io::Result<Key>
|
||||
{
|
||||
use Context;
|
||||
let context = Context::new();
|
||||
|
||||
let buf: [u8; 1024] = unsafe { ::std::mem::zeroed() };
|
||||
// reading::read(&mut buf, &context.screen_manager);
|
||||
|
||||
Ok(Key::Unknown)
|
||||
// let pressed_char = unsafe { _getwch() };
|
||||
//
|
||||
// // if 0 or 0xe0 we need to listen again because the next key will be an special key
|
||||
// if pressed_char == 0 || pressed_char == 0xe0 {
|
||||
// let special_key: i32 = unsafe { _getwch() };
|
||||
// println!("spkey {}",special_key);
|
||||
// return Ok(key_from_key_code(0x26));
|
||||
// } else {
|
||||
// match char::from_u32(pressed_char as u32)
|
||||
// {
|
||||
// Some(c) => return Ok(Key::Char(c)),
|
||||
// None => { panic!("Some error needs to be returned") }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fn read_async(&self) -> AsyncReader
|
||||
{
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
loop
|
||||
{
|
||||
let pressed_char: u8 = (unsafe { _getwch() }) as u8;
|
||||
|
||||
// we could return error but maybe option to keep listening until valid character is inputted.
|
||||
if pressed_char == 0 || pressed_char == 0xe0 {
|
||||
return;
|
||||
}
|
||||
|
||||
tx.send(Ok(pressed_char as u8));
|
||||
|
||||
if pressed_char == 13
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AsyncReader { recv: rx }
|
||||
}
|
||||
|
||||
fn read_until_async(&self, delimiter: u8) -> AsyncReader
|
||||
{
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
loop
|
||||
{
|
||||
let pressed_char: u8 = (unsafe { _getwch() }) as u8;
|
||||
|
||||
let end_of_stream = (pressed_char == delimiter);
|
||||
|
||||
// we could return error but maybe option to keep listening until valid character is inputted.
|
||||
if pressed_char == 0 || pressed_char == 0xe0 || end_of_stream {
|
||||
return;
|
||||
}
|
||||
|
||||
tx.send(Ok(pressed_char as u8));
|
||||
}
|
||||
});
|
||||
|
||||
AsyncReader { recv: rx }
|
||||
}
|
||||
}
|
||||
|
||||
fn is_line_end(key: char) -> bool
|
||||
{
|
||||
if key as u8 == 13
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//0 59 = F1
|
||||
//0 60 = F2
|
||||
//0 61 = F3
|
||||
//0 62 = F4
|
||||
//0 63 = F5
|
||||
//0 64 = F6
|
||||
//0 65 = F7
|
||||
//0 66 = F8
|
||||
//0 67 = F9
|
||||
//0 68 = F10
|
||||
//224 71 = Home
|
||||
//224 72 = ↑ (up arrow)
|
||||
//224 73 = Page Up
|
||||
//224 75 = ← (left arrow)
|
||||
//224 77 = → (right arrow)
|
||||
//224 79 = End
|
||||
//224 80 = ↓ (down arrow)
|
||||
//224 81 = Page Down
|
||||
//224 82 = Insert
|
||||
//224 83 = Delete
|
||||
//224 133 = F11
|
||||
//224 134 = F12
|
||||
|
||||
|
||||
fn key_from_key_code(code: INT) -> Key {
|
||||
|
||||
println!("code: {}", code);
|
||||
println!("up winapi: {}", winuser::VK_UP);
|
||||
|
||||
match code {
|
||||
// 59 => Key::F1,
|
||||
// 60 => Key::F2,
|
||||
// 61 => Key::F3,
|
||||
// 62 => Key::F4,
|
||||
// 63 => Key::F5,
|
||||
// 64 => Key::F6,
|
||||
// 65 => Key::F7,
|
||||
// 66 => Key::F8,
|
||||
// 67 => Key::F9,
|
||||
// 68 => Key::F10,
|
||||
winuser::VK_LEFT => Key::ArrowLeft,
|
||||
winuser::VK_RIGHT => Key::ArrowRight,
|
||||
winuser::VK_UP => Key::ArrowUp,
|
||||
winuser::VK_DOWN => Key::ArrowDown,
|
||||
winuser::VK_RETURN => Key::Enter,
|
||||
winuser::VK_ESCAPE => Key::Escape,
|
||||
winuser::VK_BACK => Key::Char('\x08'),
|
||||
winuser::VK_TAB => Key::Char('\x09'),
|
||||
_ => Key::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn _getwch() -> INT;
|
||||
fn _getwch_nolock() -> INT;
|
||||
}
|
@ -8,7 +8,7 @@ use {libc, CommandManager, Context, StateManager};
|
||||
|
||||
use std::io::Error;
|
||||
use std::rc::Rc;
|
||||
use std::{io, mem};
|
||||
use std::{io, mem, fs};
|
||||
|
||||
/// A representation of the size of the current terminal.
|
||||
#[repr(C)]
|
||||
@ -133,6 +133,13 @@ pub fn get_terminal_mode() -> io::Result<Termios> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the TTY device.
|
||||
///
|
||||
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
|
||||
pub fn get_tty() -> io::Result<fs::File> {
|
||||
fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
|
||||
}
|
||||
|
||||
pub fn exit() {
|
||||
::std::process::exit(0);
|
||||
}
|
||||
|
@ -258,54 +258,7 @@ pub fn set_console_screen_buffer_size(
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill a certain block with characters.
|
||||
pub fn fill_console_output_character(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32,
|
||||
screen_manager: &Rc<Mutex<ScreenManager>>,
|
||||
) -> bool {
|
||||
|
||||
let handle = get_current_handle(screen_manager);
|
||||
|
||||
unsafe {
|
||||
// fill the cells in console with blanks
|
||||
let success = FillConsoleOutputCharacterA(
|
||||
handle,
|
||||
' ' as i8,
|
||||
cells_to_write,
|
||||
start_location,
|
||||
cells_written,
|
||||
);
|
||||
is_true(success)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set console ouput attribute for certain block.
|
||||
pub fn fill_console_output_attribute(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32,
|
||||
screen_manager: &Rc<Mutex<ScreenManager>>,
|
||||
) -> bool {
|
||||
// Get the position of the current console window
|
||||
|
||||
let (csbi, mut handle) = get_buffer_info_and_hande(screen_manager);
|
||||
|
||||
let success;
|
||||
|
||||
unsafe {
|
||||
success = FillConsoleOutputAttribute(
|
||||
handle,
|
||||
csbi.wAttributes,
|
||||
cells_to_write,
|
||||
start_location,
|
||||
cells_written,
|
||||
);
|
||||
}
|
||||
|
||||
is_true(success)
|
||||
}
|
||||
|
||||
/// Create new console screen buffer. This can be used for alternate screen.
|
||||
pub fn create_console_screen_buffer() -> HANDLE {
|
||||
@ -343,104 +296,9 @@ pub fn set_active_screen_buffer(new_buffer: HANDLE) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the console outptut.
|
||||
pub fn read_console_output(
|
||||
read_buffer: &HANDLE,
|
||||
copy_buffer: &mut [CHAR_INFO; 160],
|
||||
buffer_size: COORD,
|
||||
buffer_coord: COORD,
|
||||
source_buffer: PSMALL_RECT,
|
||||
) {
|
||||
use self::wincon::ReadConsoleOutputA;
|
||||
|
||||
unsafe {
|
||||
if !is_true(
|
||||
ReadConsoleOutputA(
|
||||
*read_buffer, // screen buffer to read from
|
||||
copy_buffer.as_mut_ptr(), // buffer to copy into
|
||||
buffer_size, // col-row size of chiBuffer
|
||||
buffer_coord, // top left dest. cell in chiBuffer
|
||||
source_buffer,
|
||||
), // screen buffer source rectangle
|
||||
) {
|
||||
panic!("Cannot read console output");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write console output.
|
||||
pub fn write_console_output(
|
||||
write_buffer: &HANDLE,
|
||||
copy_buffer: &mut [CHAR_INFO; 160],
|
||||
buffer_size: COORD,
|
||||
buffer_coord: COORD,
|
||||
source_buffer: PSMALL_RECT,
|
||||
) {
|
||||
use self::wincon::WriteConsoleOutputA;
|
||||
|
||||
unsafe {
|
||||
if !is_true(
|
||||
WriteConsoleOutputA(
|
||||
*write_buffer, // screen buffer to write to
|
||||
copy_buffer.as_mut_ptr(), // buffer to copy into
|
||||
buffer_size, // col-row size of chiBuffer
|
||||
buffer_coord, // top left dest. cell in chiBuffer
|
||||
source_buffer,
|
||||
), // screen buffer source rectangle
|
||||
) {
|
||||
panic!("Cannot write to console output");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//use std::os::raw::c_void;
|
||||
use std::str;
|
||||
use winapi::ctypes::c_void;
|
||||
|
||||
/// Write utf8 buffer to console.
|
||||
pub fn write_char_buffer(handle: &HANDLE, buf: &[u8]) -> ::std::io::Result<usize> {
|
||||
// get string from u8[] and parse it to an c_str
|
||||
let mut utf8 = match str::from_utf8(buf) {
|
||||
Ok(string) => string,
|
||||
Err(_) => "123",
|
||||
};
|
||||
|
||||
let utf16: Vec<u16> = utf8.encode_utf16().collect();
|
||||
let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void;
|
||||
|
||||
// get buffer info
|
||||
let csbi = get_console_screen_buffer_info_from_handle(handle);
|
||||
|
||||
// get current position
|
||||
let current_pos = COORD {
|
||||
X: csbi.dwCursorPosition.X,
|
||||
Y: csbi.dwCursorPosition.Y,
|
||||
};
|
||||
|
||||
let mut cells_written: u32 = 0;
|
||||
|
||||
let mut success = false;
|
||||
// write to console
|
||||
unsafe {
|
||||
success = is_true(WriteConsoleW(
|
||||
*handle,
|
||||
utf16_ptr,
|
||||
utf16.len() as u32,
|
||||
&mut cells_written,
|
||||
NULL,
|
||||
));
|
||||
}
|
||||
|
||||
match success
|
||||
{
|
||||
// think this is wrong could be done better!
|
||||
true => Ok(utf8.as_bytes().len()),
|
||||
false => Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse integer to an bool
|
||||
fn is_true(value: i32) -> bool {
|
||||
pub fn is_true(value: i32) -> bool {
|
||||
if value == 0 {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -4,6 +4,8 @@ pub mod ansi_support;
|
||||
pub mod cursor;
|
||||
pub mod kernel;
|
||||
pub mod terminal;
|
||||
pub mod writing;
|
||||
pub mod reading;
|
||||
|
||||
use self::winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
||||
use shared::traits::Empty;
|
||||
|
84
src/kernel/windows_kernel/reading.rs
Normal file
84
src/kernel/windows_kernel/reading.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use { Context, ScreenManager };
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use winapi::um::consoleapi::ReadConsoleW;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use winapi::um::wincon::{ COORD, PSMALL_RECT, ReadConsoleOutputA, CHAR_INFO, };
|
||||
use winapi::shared::minwindef::{ DWORD, LPDWORD, LPVOID };
|
||||
use winapi::shared::ntdef::NULL;
|
||||
|
||||
use super::kernel;
|
||||
use winapi::ctypes::c_void;
|
||||
|
||||
pub fn read(buf: &mut [u8], screen_manager: &Rc<Mutex<ScreenManager>>) {
|
||||
// // Read more if the buffer is empty
|
||||
// let mut utf16: Vec<u16> = Vec::new();
|
||||
// let mut num: DWORD = 0;
|
||||
//
|
||||
// let handle = kernel::get_current_handle(&screen_manager);
|
||||
//
|
||||
// unsafe {
|
||||
// ReadConsoleW(handle,
|
||||
// utf16.as_mut_ptr() as LPVOID,
|
||||
// utf16.len() as u32,
|
||||
// &mut num as LPDWORD,
|
||||
// ptr::mut_null())
|
||||
// };
|
||||
//
|
||||
// utf16.truncate(num as uint);
|
||||
// let utf8 = match from_utf16(utf16.as_slice()) {
|
||||
// Some(utf8) => utf8.into_bytes(),
|
||||
// None => {}
|
||||
// };
|
||||
//
|
||||
// panic!(utf8);
|
||||
|
||||
}
|
||||
|
||||
pub fn read_line(screen_manager: &Rc<Mutex<ScreenManager>>) -> ::std::io::Result<String>
|
||||
{
|
||||
const BUFFER_LENGHT: u32 = 1024;
|
||||
let mut buffer: &mut [CHAR_INFO; BUFFER_LENGHT as usize] = unsafe {::std::mem::zeroed() };
|
||||
|
||||
let handle = kernel::get_current_handle(&screen_manager);
|
||||
|
||||
let mut dw_mode: DWORD = 0;
|
||||
let console_mode = kernel::get_console_mode(&handle, &mut dw_mode);
|
||||
|
||||
let ptr = buffer.as_ptr() as *const _ as *mut c_void;
|
||||
let mut chars_read: u32 = 0;
|
||||
|
||||
panic!();
|
||||
unsafe
|
||||
{
|
||||
ReadConsoleW(handle, ptr, BUFFER_LENGHT , &mut chars_read, unsafe {::std::mem::zeroed() });
|
||||
}
|
||||
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
/// Read the console outptut.
|
||||
pub fn read_console_output(
|
||||
read_buffer: &HANDLE,
|
||||
copy_buffer: &mut [CHAR_INFO; 160],
|
||||
buffer_size: COORD,
|
||||
buffer_coord: COORD,
|
||||
source_buffer: PSMALL_RECT,
|
||||
) {
|
||||
|
||||
|
||||
unsafe {
|
||||
if !kernel::is_true(
|
||||
ReadConsoleOutputA(
|
||||
*read_buffer, // screen buffer to read from
|
||||
copy_buffer.as_mut_ptr(), // buffer to copy into
|
||||
buffer_size, // col-row size of chiBuffer
|
||||
buffer_coord, // top left dest. cell in chiBuffer
|
||||
source_buffer,
|
||||
), // screen buffer source rectangle
|
||||
) {
|
||||
panic!("Cannot read console output");
|
||||
}
|
||||
}
|
||||
}
|
130
src/kernel/windows_kernel/writing.rs
Normal file
130
src/kernel/windows_kernel/writing.rs
Normal file
@ -0,0 +1,130 @@
|
||||
use { Context, ScreenManager };
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use winapi::um::wincon;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use winapi::um::consoleapi::WriteConsoleW;
|
||||
use winapi::um::wincon::{WriteConsoleOutputA, PSMALL_RECT, FillConsoleOutputAttribute, FillConsoleOutputCharacterA, COORD, CHAR_INFO};
|
||||
use winapi::shared::ntdef::NULL;
|
||||
|
||||
use super::kernel;
|
||||
|
||||
/// Fill a certain block with characters.
|
||||
pub fn fill_console_output_character(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32,
|
||||
screen_manager: &Rc<Mutex<ScreenManager>>,
|
||||
) -> bool {
|
||||
|
||||
let handle = kernel::get_current_handle(screen_manager);
|
||||
|
||||
unsafe {
|
||||
// fill the cells in console with blanks
|
||||
let success = FillConsoleOutputCharacterA(
|
||||
handle,
|
||||
' ' as i8,
|
||||
cells_to_write,
|
||||
start_location,
|
||||
cells_written,
|
||||
);
|
||||
kernel::is_true(success)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set console ouput attribute for certain block.
|
||||
pub fn fill_console_output_attribute(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32,
|
||||
screen_manager: &Rc<Mutex<ScreenManager>>,
|
||||
) -> bool {
|
||||
// Get the position of the current console window
|
||||
|
||||
let (csbi, mut handle) = kernel::get_buffer_info_and_hande(screen_manager);
|
||||
|
||||
let success;
|
||||
|
||||
unsafe {
|
||||
success = FillConsoleOutputAttribute(
|
||||
handle,
|
||||
csbi.wAttributes,
|
||||
cells_to_write,
|
||||
start_location,
|
||||
cells_written,
|
||||
);
|
||||
}
|
||||
|
||||
kernel::is_true(success)
|
||||
}
|
||||
|
||||
/// Write console output.
|
||||
pub fn write_console_output(
|
||||
write_buffer: &HANDLE,
|
||||
copy_buffer: &mut [CHAR_INFO; 160],
|
||||
buffer_size: COORD,
|
||||
buffer_coord: COORD,
|
||||
source_buffer: PSMALL_RECT,
|
||||
) {
|
||||
use self::wincon::WriteConsoleOutputA;
|
||||
|
||||
unsafe {
|
||||
if !kernel::is_true(
|
||||
WriteConsoleOutputA(
|
||||
*write_buffer, // screen buffer to write to
|
||||
copy_buffer.as_mut_ptr(), // buffer to copy into
|
||||
buffer_size, // col-row size of chiBuffer
|
||||
buffer_coord, // top left dest. cell in chiBuffer
|
||||
source_buffer,
|
||||
), // screen buffer source rectangle
|
||||
) {
|
||||
panic!("Cannot write to console output");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use winapi::ctypes::c_void;
|
||||
use std::str;
|
||||
|
||||
/// Write utf8 buffer to console.
|
||||
pub fn write_char_buffer(handle: &HANDLE, buf: &[u8]) -> ::std::io::Result<usize> {
|
||||
// get string from u8[] and parse it to an c_str
|
||||
let mut utf8 = match str::from_utf8(buf) {
|
||||
Ok(string) => string,
|
||||
Err(_) => "123",
|
||||
};
|
||||
|
||||
let utf16: Vec<u16> = utf8.encode_utf16().collect();
|
||||
let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void;
|
||||
|
||||
// get buffer info
|
||||
let csbi = kernel::get_console_screen_buffer_info_from_handle(handle);
|
||||
|
||||
// get current position
|
||||
let current_pos = COORD {
|
||||
X: csbi.dwCursorPosition.X,
|
||||
Y: csbi.dwCursorPosition.Y,
|
||||
};
|
||||
|
||||
let mut cells_written: u32 = 0;
|
||||
|
||||
let mut success = false;
|
||||
// write to console
|
||||
unsafe {
|
||||
success = kernel::is_true(WriteConsoleW(
|
||||
*handle,
|
||||
utf16_ptr,
|
||||
utf16.len() as u32,
|
||||
&mut cells_written,
|
||||
NULL,
|
||||
));
|
||||
}
|
||||
|
||||
match success
|
||||
{
|
||||
// think this is wrong could be done better!
|
||||
true => Ok(utf8.as_bytes().len()),
|
||||
false => Ok(0)
|
||||
}
|
||||
}
|
@ -3,13 +3,14 @@
|
||||
//! This module uses the stdout to write to the console.
|
||||
|
||||
use std::any::Any;
|
||||
use std::io::{self, Write};
|
||||
use std::io::{self, Write, Read };
|
||||
|
||||
use super::IScreenManager;
|
||||
|
||||
pub struct AnsiScreenManager {
|
||||
pub is_alternate_screen: bool,
|
||||
output: Box<Write>,
|
||||
input: Box<Read>
|
||||
}
|
||||
|
||||
impl IScreenManager for AnsiScreenManager {
|
||||
@ -29,6 +30,20 @@ impl IScreenManager for AnsiScreenManager {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
// fn read_line(&mut self) -> io::Result<String>
|
||||
// {
|
||||
// let mut rv = String::new();
|
||||
// self.input.read_line(&mut rv)?;
|
||||
// let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
// rv.truncate(len);
|
||||
// Ok(rv)
|
||||
// }
|
||||
//
|
||||
// fn read_char(&mut self) -> io::Result<String>
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.output.write(buf)
|
||||
}
|
||||
@ -45,6 +60,7 @@ impl IScreenManager for AnsiScreenManager {
|
||||
impl AnsiScreenManager {
|
||||
pub fn new() -> Self {
|
||||
AnsiScreenManager {
|
||||
input: (Box::from(io::stdin()) as Box<Read>),
|
||||
output: (Box::from(io::stdout()) as Box<Write>),
|
||||
is_alternate_screen: false,
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use super::IScreenManager;
|
||||
|
||||
use kernel::windows_kernel::kernel;
|
||||
use kernel::windows_kernel::writing;
|
||||
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
@ -30,9 +32,9 @@ impl IScreenManager for WinApiScreenManager {
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
if self.is_alternate_screen {
|
||||
kernel::write_char_buffer(&self.alternate_handle, buf)
|
||||
writing::write_char_buffer(&self.alternate_handle, buf)
|
||||
} else {
|
||||
kernel::write_char_buffer(&self.output, buf)
|
||||
writing::write_char_buffer(&self.output, buf)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,14 +50,14 @@ use {ScreenManager, StateManager};
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use std::marker::Sync;
|
||||
/// This type is the context of the current terminal. The context is a wrapper for states changes of the terminal and can be used for managing the output of the terminal.
|
||||
pub struct Context {
|
||||
pub screen_manager: Rc<Mutex<ScreenManager>>,
|
||||
pub state_manager: Mutex<StateManager>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
impl Context{
|
||||
/// Create new Context instance so that you can provide it to other modules like terminal, cursor and color
|
||||
///
|
||||
/// This context type is just an wrapper that crossterm uses for managing the state the terminal.
|
||||
|
@ -5,7 +5,7 @@ use super::super::shared::functions;
|
||||
use super::super::ScreenManager;
|
||||
use super::{ClearType, ITerminal, Rc};
|
||||
use cursor::cursor;
|
||||
use kernel::windows_kernel::{kernel, terminal};
|
||||
use kernel::windows_kernel::{kernel, terminal, writing};
|
||||
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
||||
use Context;
|
||||
|
||||
@ -276,7 +276,7 @@ fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &Rc<Mutex<S
|
||||
let mut cells_written = 0;
|
||||
let mut success = false;
|
||||
|
||||
success = kernel::fill_console_output_character(
|
||||
success = writing::fill_console_output_character(
|
||||
&mut cells_written,
|
||||
start_loaction,
|
||||
cells_to_write,
|
||||
@ -289,7 +289,7 @@ fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &Rc<Mutex<S
|
||||
|
||||
cells_written = 0;
|
||||
|
||||
success = kernel::fill_console_output_attribute(
|
||||
success = writing::fill_console_output_attribute(
|
||||
&mut cells_written,
|
||||
start_loaction,
|
||||
cells_to_write,
|
||||
|
Loading…
Reference in New Issue
Block a user