read line, read char, read async and read async until implemented for windows

This commit is contained in:
TimonPost 2018-07-20 18:00:46 +02:00
parent fcc4ca31bc
commit 07502c016d
37 changed files with 1956 additions and 192 deletions

View File

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

View File

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

View 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)

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

View 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))
);
}
}

View 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");
}

View 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);
}

View 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));
}
}

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

View File

@ -0,0 +1,2 @@
pub mod async_input;
pub mod input;

View File

@ -0,0 +1 @@
pub mod keyboard;

View 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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,4 @@
mod map;
mod messages;
mod variables;
mod algorithm;

View File

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

View 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");
}

View 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;

View 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");
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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");
}
}
}

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

View File

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

View File

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

View File

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

View File

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