Refactor
This commit is contained in:
parent
a6149f75f3
commit
685bc5e961
@ -28,6 +28,8 @@ use crossterm::cursor::cursor;
|
||||
use std::io::Read;
|
||||
|
||||
fn main() {
|
||||
use crossterm::color;
|
||||
|
||||
let input = CROSSTERM.input();
|
||||
let mut stdin = input.read_async().bytes();
|
||||
CROSSTERM.cursor().hide();
|
||||
|
11
examples/program_examples/snake/Cargo.toml
Normal file
11
examples/program_examples/snake/Cargo.toml
Normal 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"
|
141
examples/program_examples/snake/src/main.rs
Normal file
141
examples/program_examples/snake/src/main.rs
Normal file
@ -0,0 +1,141 @@
|
||||
extern crate crossterm;
|
||||
extern crate rand;
|
||||
|
||||
mod map;
|
||||
mod snake;
|
||||
mod variables;
|
||||
mod messages;
|
||||
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::terminal::{terminal, ClearType};
|
||||
use self::crossterm::style::Color;
|
||||
|
||||
use self::crossterm::{Screen, Crossterm};
|
||||
|
||||
use map::Map;
|
||||
use variables::{Size, Direction, Position};
|
||||
use snake::Snake;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{thread, time};
|
||||
use std::iter::Iterator;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let map_size = title_screen();
|
||||
|
||||
{
|
||||
let mut screen = Screen::new(true);
|
||||
let crossterm = Crossterm::new(&screen);
|
||||
|
||||
let cursor = crossterm.cursor();
|
||||
let mut input = crossterm.input();
|
||||
|
||||
cursor.hide();
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
let mut free_positions: HashMap<String, Position> = HashMap::with_capacity((map_size.width * map_size.height) as usize);
|
||||
|
||||
let mut map = Map::new(map_size.clone());
|
||||
map.render_map(&screen, &mut free_positions);
|
||||
|
||||
let mut direction = Direction::Right;
|
||||
|
||||
let mut snake = Snake::new(map_size.clone());
|
||||
|
||||
for part in snake.get_parts().iter() {
|
||||
free_positions.remove_entry(format!("{},{}", part.position.x, part.position.y).as_str());
|
||||
}
|
||||
|
||||
map.spawn_food(&free_positions, &screen);
|
||||
|
||||
loop {
|
||||
thread::sleep(time::Duration::from_millis(500));
|
||||
let pressed_key = stdin.next();
|
||||
|
||||
if let Some(Ok(key)) = pressed_key {
|
||||
match key as char {
|
||||
'w' => direction = Direction::Up,
|
||||
'a' => direction = Direction::Left,
|
||||
's' => direction = Direction::Down,
|
||||
'd' => direction = Direction::Right,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
snake.move_snake(&direction, &screen, &mut free_positions);
|
||||
|
||||
if map.is_out_of_bounds(snake.snake_parts[0].position)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
snake.draw_snake(&screen);
|
||||
|
||||
|
||||
|
||||
if snake.has_eaten_food(map.foot_pos)
|
||||
{
|
||||
map.spawn_food(&free_positions, &screen);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
game_over_screen();
|
||||
}
|
||||
|
||||
fn title_screen() -> Size
|
||||
{
|
||||
let crossterm = Crossterm::new(&Screen::default());
|
||||
|
||||
let cursor = crossterm.cursor();
|
||||
let terminal = crossterm.terminal().clear(ClearType::All);
|
||||
|
||||
println!("{}",messages::SNAKERS.join("\n\r"));
|
||||
cursor.goto(0, 15);
|
||||
println!("Enter map width:");
|
||||
cursor.goto(17, 15);
|
||||
let width = crossterm.input().read_line().unwrap();
|
||||
println!("\n\rEnter map height:");
|
||||
cursor.goto(17, 16);
|
||||
let height = crossterm.input().read_line().unwrap();
|
||||
|
||||
let parsed_width = width.parse::<usize>().unwrap();
|
||||
let parsed_height = height.parse::<usize>().unwrap();
|
||||
|
||||
let terminal = crossterm.terminal().clear(ClearType::All);
|
||||
|
||||
return Size::new(parsed_width, parsed_height);
|
||||
}
|
||||
|
||||
fn print_game_stats(map_size: Size, snake_lenght: usize, food_aten: usize, screen: &mut Screen)
|
||||
{
|
||||
let crossterm = Crossterm::new(&Screen::default());
|
||||
|
||||
let cursor = crossterm.cursor();
|
||||
let terminal = crossterm.terminal().clear(ClearType::All);
|
||||
|
||||
screen.write(format!("Snake Lenght: {}\n\r", snake_lenght).as_ref());
|
||||
screen.write(format!("Food aten: {}\n\r", snake_lenght).as_ref());
|
||||
|
||||
cursor.goto(0,map_size.height as u16);
|
||||
cursor.goto(0,map_size.height as u16);
|
||||
}
|
||||
|
||||
fn game_over_screen()
|
||||
{
|
||||
let crossterm = Crossterm::new(&Screen::default());
|
||||
|
||||
let cursor = crossterm.cursor();
|
||||
let terminal = crossterm.terminal();
|
||||
|
||||
terminal.clear(ClearType::All);
|
||||
|
||||
println!("{}",messages::END_MESSAGE.join("\n\r"));
|
||||
// cursor.goto()
|
||||
cursor.show();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,80 @@
|
||||
use super::variables::{Position, Size, Direction };
|
||||
use super::snake::Snake;
|
||||
|
||||
use crossterm::{Crossterm, Screen};
|
||||
use crossterm::cursor::cursor;
|
||||
use crossterm::style::{ObjectStyle, StyledObject, Color, style};
|
||||
|
||||
use rand::distributions::{IndependentSample, Range};
|
||||
|
||||
use std::hash::Hash;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Index;
|
||||
|
||||
use rand;
|
||||
|
||||
pub struct Map
|
||||
{
|
||||
pub size: Size,
|
||||
pub foot_pos: Position,
|
||||
}
|
||||
|
||||
impl Map
|
||||
{
|
||||
pub fn new(size: Size) -> Self
|
||||
{
|
||||
Map { size: size, foot_pos: Position::new(0,0) }
|
||||
}
|
||||
|
||||
// render the map on the screen.
|
||||
pub fn render_map(&mut self, screen: &Screen, free_positions: &mut HashMap<String, Position>)
|
||||
{
|
||||
let crossterm = Crossterm::new(screen);
|
||||
let mut cursor = crossterm.cursor();
|
||||
let mut terminal = crossterm.terminal();
|
||||
|
||||
for y in 0..self.size.height
|
||||
{
|
||||
for x in 0..self.size.height
|
||||
{
|
||||
if (y == 0 || y == self.size.height - 1) || (x == 0 || x == self.size.width - 1)
|
||||
{
|
||||
cursor.goto(x as u16, y as u16);
|
||||
terminal.write("█")
|
||||
}else {
|
||||
free_positions.insert(format!("{},{}",x,y), Position::new(x,y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_out_of_bounds(&self, new_pos: Position) -> bool
|
||||
{
|
||||
if (new_pos.x == 0 || new_pos.x == self.size.width) || (new_pos.y == 0 || new_pos.y == self.size.height)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn is_food_eaten(&self, snake_head: Position) -> bool
|
||||
{
|
||||
snake_head.x == self.foot_pos.x && snake_head.y == self.foot_pos.y
|
||||
}
|
||||
|
||||
pub fn spawn_food(&mut self, free_positions: &HashMap<String, Position>, screen: &Screen)
|
||||
{
|
||||
let index = Range::new(0, free_positions.len()).ind_sample(&mut rand::thread_rng());
|
||||
self.foot_pos = free_positions.values().skip(index).next().unwrap().clone();
|
||||
self.draw_food(screen);
|
||||
}
|
||||
|
||||
fn draw_food(&self, screen: &Screen)
|
||||
{
|
||||
cursor(screen).goto(self.foot_pos.x as u16, self.foot_pos.y as u16);
|
||||
style("$").with(Color::Green).paint(screen);
|
||||
screen.stdout.flush();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
pub const SNAKERS: [&str; 11] =
|
||||
[
|
||||
" ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ",
|
||||
"▐░░░░░░░░░░░▌▐░░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌",
|
||||
"▐░█▀▀▀▀▀▀▀▀▀ ▐░▌░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀",
|
||||
"▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌",
|
||||
"▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄█░▌▐░▌░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄",
|
||||
"▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌",
|
||||
" ▀▀▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀█░█▀▀ ▀▀▀▀▀▀▀▀▀█░▌",
|
||||
" ▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌",
|
||||
" ▄▄▄▄▄▄▄▄▄█░▌▐░▌ ▐░▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▄▄▄▄▄▄▄▄▄█░▌",
|
||||
"▐░░░░░░░░░░░▌▐░▌ ▐░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌",
|
||||
" ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀"
|
||||
];
|
||||
|
||||
pub const END_MESSAGE: [&str; 11] =
|
||||
[
|
||||
" ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ",
|
||||
" ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░░▌▐░░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ",
|
||||
" ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ",
|
||||
" ▐░▌ ▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ",
|
||||
" ▐░▌ ▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌ ",
|
||||
" ▐░▌▐░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ",
|
||||
" ▐░▌ ▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▀ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀█░█▀▀ ",
|
||||
" ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ ",
|
||||
" ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌ ▐░▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ",
|
||||
" ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌ ▐░░░░░░░░░░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ ",
|
||||
" ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ",
|
||||
|
||||
];
|
@ -0,0 +1,100 @@
|
||||
use crossterm::{Screen, Crossterm};
|
||||
use crossterm::style::Color;
|
||||
use super::variables::{Position, Direction, Size};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Part
|
||||
{
|
||||
pub position: Position,
|
||||
}
|
||||
|
||||
impl Part
|
||||
{
|
||||
pub fn new(x: usize, y: usize) -> Part
|
||||
{
|
||||
Part { position: Position::new(x,y) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Snake
|
||||
{
|
||||
pub snake_parts: Vec<Part>,
|
||||
pub parent_pos: Position,
|
||||
map_size: Size
|
||||
}
|
||||
|
||||
impl Snake
|
||||
{
|
||||
pub fn new(map_size: Size) -> Snake
|
||||
{
|
||||
return Snake { map_size, snake_parts: vec![Part::new(9, 10), Part::new(8, 10)], parent_pos: Position::new(0,0) }
|
||||
}
|
||||
|
||||
pub fn move_snake(&mut self, direction: &Direction, screen: &Screen, free_positions: &mut HashMap<String, Position> )
|
||||
{
|
||||
let crossterm = Crossterm::new(screen);
|
||||
let cursor = crossterm.cursor();
|
||||
let terminal = crossterm.terminal();
|
||||
|
||||
let count = self.snake_parts.len();
|
||||
let is_food_eaten = false;
|
||||
|
||||
for (index, ref mut snake_part) in self.snake_parts.iter_mut().enumerate() {
|
||||
if index == count - 1
|
||||
{
|
||||
snake_part.position.remove(screen);
|
||||
free_positions.insert(format!("{},{}",snake_part.position.x,snake_part.position.y), snake_part.position);
|
||||
}
|
||||
|
||||
if index == 0
|
||||
{
|
||||
self.parent_pos = snake_part.position.clone();
|
||||
|
||||
match direction {
|
||||
&Direction::Up => { snake_part.position.y -= 1 },
|
||||
&Direction::Down => { snake_part.position.y += 1 },
|
||||
&Direction::Left => { snake_part.position.x -= 1 },
|
||||
&Direction::Right => { snake_part.position.x += 1 },
|
||||
}
|
||||
|
||||
free_positions.remove_entry(format!("{},{}",snake_part.position.x,snake_part.position.y).as_str());
|
||||
|
||||
} else {
|
||||
let new_pos = self.parent_pos.clone();
|
||||
self.parent_pos = snake_part.position.clone();
|
||||
snake_part.position = new_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_snake(&mut self, screen: &Screen)
|
||||
{
|
||||
for (index, ref mut snake_part) in self.snake_parts.iter_mut().enumerate() {
|
||||
snake_part.position.draw("■", screen);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_eaten_food(&mut self, food_pos: Position) -> bool
|
||||
{
|
||||
if self.snake_parts[0].position.x == food_pos.x && self.snake_parts[0].position.y == food_pos.y
|
||||
{
|
||||
self.snake_parts.push(Part::new(1,1));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn get_parts(&self) -> &Vec<Part>
|
||||
{
|
||||
return &self.snake_parts;
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SnakeState
|
||||
{
|
||||
MovedOutMap,
|
||||
Moved,
|
||||
AteFood
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::terminal::{terminal, ClearType};
|
||||
use self::crossterm::style::{Color, StyledObject, ObjectStyle, style };
|
||||
use self::crossterm::cursor::cursor;
|
||||
use self::crossterm::Screen;
|
||||
|
||||
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, PartialOrd, PartialEq)]
|
||||
pub struct Position
|
||||
{
|
||||
pub x: usize,
|
||||
pub y: usize
|
||||
}
|
||||
|
||||
impl Position
|
||||
{
|
||||
pub fn new(x: usize, y: usize) -> Position
|
||||
{
|
||||
Position { x, y }
|
||||
}
|
||||
|
||||
pub fn draw(&self, val: &str, screen: &Screen)
|
||||
{
|
||||
cursor(screen).goto(self.x as u16, self.y as u16);
|
||||
style(val).with(Color::Red).paint(&screen);
|
||||
screen.stdout.flush();
|
||||
}
|
||||
|
||||
pub fn remove(&self, screen: &Screen)
|
||||
{
|
||||
cursor(screen).goto(self.x as u16, self.y as u16);
|
||||
terminal(&screen).write(" ");
|
||||
}
|
||||
}
|
||||
|
||||
#[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}
|
||||
}
|
||||
}
|
@ -11,11 +11,11 @@ use std::io::{self, Read, Write,Stdout, stdout};
|
||||
use std::str::from_utf8;
|
||||
|
||||
/// This struct is a wrapper for `Stdout`
|
||||
pub struct AnsiStdout {
|
||||
pub struct AnsiOutput {
|
||||
pub handle: Stdout,
|
||||
}
|
||||
|
||||
impl IStdout for AnsiStdout {
|
||||
impl IStdout for AnsiOutput {
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
let out = &self.handle;
|
||||
let mut handle = out.lock();
|
||||
@ -47,8 +47,8 @@ impl IStdout for AnsiStdout {
|
||||
}
|
||||
}
|
||||
|
||||
impl AnsiStdout {
|
||||
impl AnsiOutput {
|
||||
pub fn new() -> Self {
|
||||
AnsiStdout { handle: stdout() }
|
||||
AnsiOutput { handle: stdout() }
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
//! This module provides a way to work with an handle to an screen on different platforms.
|
||||
|
||||
mod stdout;
|
||||
mod output;
|
||||
|
||||
mod ansi_stdout;
|
||||
mod ansi_output;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod winapi_stdout;
|
||||
mod winapi_output;
|
||||
|
||||
pub use self::ansi_stdout::AnsiStdout;
|
||||
pub use self::ansi_output::AnsiOutput;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use self::winapi_stdout::WinApiStdout;
|
||||
pub use self::winapi_output::WinApiOutput;
|
||||
|
||||
pub use self::stdout::Stdout;
|
||||
pub use self::output::TerminalOutput;
|
||||
|
||||
use std::any::Any;
|
||||
use std::io;
|
@ -34,67 +34,67 @@ use std::sync::Arc;
|
||||
/// This handle could be used to write to the current screen
|
||||
///
|
||||
/// For unix and windows 10 `stdout()` will be used for handle when on windows systems with versions lower than 10 WinApi `HANDLE` will be used.
|
||||
pub struct Stdout {
|
||||
screen_manager: Box<IStdout + Send + Sync>,
|
||||
pub struct TerminalOutput {
|
||||
stdout: Box<IStdout + Send + Sync>,
|
||||
pub is_in_raw_mode:bool,
|
||||
}
|
||||
|
||||
impl Stdout {
|
||||
impl TerminalOutput {
|
||||
/// Create new screen write instance whereon screen related actions can be performed.
|
||||
pub fn new(is_in_raw_mode: bool) -> Self {
|
||||
#[cfg(target_os = "windows")]
|
||||
let screen_manager: Box<IStdout + Send + Sync> = functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||
let stdout: Box<IStdout + Send + Sync> = functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||
Box::from(WinApiStdout::new()),
|
||||
Box::from(AnsiStdout::new()),
|
||||
).unwrap();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let screen_manager = Box::from(AnsiStdout::new()) as Box<IStdout + Send + Sync>;
|
||||
let stdout = Box::from(AnsiStdout::new()) as Box<IStdout + Send + Sync>;
|
||||
|
||||
Stdout { screen_manager , is_in_raw_mode}
|
||||
TerminalOutput { stdout , is_in_raw_mode}
|
||||
}
|
||||
|
||||
/// Write String to the current screen.
|
||||
pub fn write_string(&self, string: String) -> io::Result<usize> {
|
||||
self.screen_manager.write_str(string.as_str())
|
||||
self.stdout.write_str(string.as_str())
|
||||
}
|
||||
|
||||
/// Flush the current screen.
|
||||
pub fn flush(&self) -> io::Result<()> {
|
||||
self.screen_manager.flush()
|
||||
self.stdout.flush()
|
||||
}
|
||||
|
||||
/// Write &str to the current screen.
|
||||
pub fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
self.screen_manager.write_str(string)
|
||||
self.stdout.write_str(string)
|
||||
}
|
||||
|
||||
/// Write buffer to the screen
|
||||
pub fn write_buf(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.screen_manager.write(buf)
|
||||
self.stdout.write(buf)
|
||||
}
|
||||
|
||||
pub fn as_any(&self) -> &Any {
|
||||
self.screen_manager.as_any()
|
||||
self.stdout.as_any()
|
||||
}
|
||||
pub fn as_any_mut(&mut self) -> &mut Any {
|
||||
self.screen_manager.as_any_mut()
|
||||
self.stdout.as_any_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Stdout
|
||||
impl Default for TerminalOutput
|
||||
{
|
||||
/// Get the default handle to the current screen.
|
||||
fn default() -> Self {
|
||||
#[cfg(target_os = "windows")]
|
||||
let screen_manager = functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||
let stdout = functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||
Box::from(WinApiStdout::new()),
|
||||
Box::from(AnsiStdout::new()),
|
||||
).unwrap();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let screen_manager = Box::from(AnsiStdout::new()) as Box<IStdout + Send + Sync>;
|
||||
let stdout = Box::from(AnsiStdout::new()) as Box<IStdout + Send + Sync>;
|
||||
|
||||
Stdout { screen_manager , is_in_raw_mode: false}
|
||||
TerminalOutput { stdout , is_in_raw_mode: false}
|
||||
}
|
||||
}
|
@ -3,17 +3,18 @@ use kernel::windows_kernel::{handle, kernel, writing};
|
||||
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use std::sync::Mutex;
|
||||
use std::ptr::NonNull;
|
||||
use std::any::Any;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::{Mutex,Arc, };
|
||||
use std::io;
|
||||
|
||||
|
||||
/// This struct is a wrapper for WINAPI `HANDLE`
|
||||
pub struct WinApiStdout {
|
||||
pub struct WinApiOutput {
|
||||
pub handle: Mutex<HANDLE>,
|
||||
}
|
||||
|
||||
impl IStdout for WinApiStdout {
|
||||
impl IStdout for WinApiOutput {
|
||||
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
self.write(string.as_bytes())
|
||||
@ -36,9 +37,9 @@ impl IStdout for WinApiStdout {
|
||||
}
|
||||
}
|
||||
|
||||
impl WinApiStdout {
|
||||
impl WinApiOutput {
|
||||
pub fn new() -> Self {
|
||||
WinApiStdout { handle: Mutex::new(handle::get_output_handle().unwrap()) }
|
||||
WinApiOutput { handle: Mutex::new(handle::get_output_handle().unwrap()) }
|
||||
}
|
||||
|
||||
pub fn set(&mut self, handle: HANDLE)
|
||||
@ -53,6 +54,6 @@ impl WinApiStdout {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for WinApiStdout {}
|
||||
unsafe impl Send for WinApiOutput {}
|
||||
|
||||
unsafe impl Sync for WinApiStdout {}
|
||||
unsafe impl Sync for WinApiOutput {}
|
Loading…
Reference in New Issue
Block a user