some examples fixed added multy threaded logging example and tested input and changed styling system
This commit is contained in:
parent
f6b1955cae
commit
e1bbf1689f
@ -31,6 +31,10 @@ path = "src/lib.rs"
|
||||
name = "simple"
|
||||
path = "examples/simple.rs"
|
||||
|
||||
[[example]]
|
||||
name = "logging"
|
||||
path = "examples/program_examples/logging.rs"
|
||||
|
||||
[[example]]
|
||||
name = "duplex"
|
||||
path = "examples/duplex.rs"
|
||||
path = "examples/program_examples/duplex.rs"
|
||||
|
@ -1,53 +1,53 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::{Crossterm, Screen};
|
||||
use self::crossterm::terminal::ClearType;
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::Context;
|
||||
use self::crossterm::Crossterm;
|
||||
use crossterm::terminal::ClearType;
|
||||
|
||||
use crossterm::raw::IntoRawMode;
|
||||
use std::{thread, time};
|
||||
|
||||
use std::io::{stdout, Read, Write};
|
||||
use std::time::Duration;
|
||||
|
||||
/// this will capture the input until the given key.
|
||||
pub fn read_async_until() {
|
||||
let screen = Screen::new();
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input();
|
||||
let terminal = crossterm.terminal();
|
||||
let mut cursor = crossterm.cursor();
|
||||
if let Ok(raw) = screen.enable_raw_modes()
|
||||
{
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input(&raw.screen);
|
||||
let terminal = crossterm.terminal(&raw.screen);
|
||||
let mut cursor = crossterm.cursor(&raw.screen);
|
||||
|
||||
let mut stdout = stdout().into_raw_mode(crossterm.context()).unwrap();
|
||||
let mut stdin = input.read_until_async(b'\r').bytes();
|
||||
|
||||
for i in 0..100 {
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
let a = stdin.next();
|
||||
let mut stdin = input.read_until_async(b'\r').bytes();
|
||||
|
||||
println!("pressed key: {:?}", a);
|
||||
for i in 0..100 {
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
let a = stdin.next();
|
||||
|
||||
if let Some(Ok(b'\r')) = a {
|
||||
println!("The enter key is hit and program is not listening to input anymore.");
|
||||
break;
|
||||
println!("pressed key: {:?}", a);
|
||||
|
||||
if let Some(Ok(b'\r')) = a {
|
||||
println!("The enter key is hit and program is not listening to input anymore.");
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(Ok(b'x')) = a {
|
||||
println!("The key: x was pressed and program is terminated.");
|
||||
break;
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
}
|
||||
|
||||
if let Some(Ok(b'x')) = a {
|
||||
println!("The key: x was pressed and program is terminated.");
|
||||
break;
|
||||
}
|
||||
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
||||
/// this will read pressed characters async until `x` is typed .
|
||||
pub fn read_async() {
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
let input = input(&Screen::new());
|
||||
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
@ -66,15 +66,16 @@ pub fn read_async() {
|
||||
}
|
||||
|
||||
pub fn read_async_demo() {
|
||||
let screen = Screen::new();
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input();
|
||||
let terminal = crossterm.terminal();
|
||||
let mut cursor = crossterm.cursor();
|
||||
|
||||
// put stdout in raw mode so that characters wil not be outputted.
|
||||
let mut stdout = stdout().into_raw_mode(crossterm.context()).unwrap();
|
||||
let raw = screen.enable_raw_modes().unwrap();
|
||||
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input(&raw.screen);
|
||||
let terminal = crossterm.terminal(&raw.screen);
|
||||
let mut cursor = crossterm.cursor(&raw.screen);
|
||||
|
||||
// this will setup the async reading.
|
||||
let mut stdin = input.read_async().bytes();
|
||||
@ -92,7 +93,6 @@ pub fn read_async_demo() {
|
||||
let pressed_key = stdin.next();
|
||||
terminal.write(format!("\r{:?} <- Character pressed", pressed_key));
|
||||
|
||||
|
||||
// check if pressed key is enter (\r)
|
||||
if let Some(Ok(b'\r')) = pressed_key {
|
||||
break;
|
||||
@ -106,38 +106,41 @@ pub fn read_async_demo() {
|
||||
pub fn async_reading_on_alternate_screen() {
|
||||
use crossterm::screen::AlternateScreen;
|
||||
|
||||
let screen = Screen::new();
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input();
|
||||
let terminal = crossterm.terminal();
|
||||
let mut cursor = crossterm.cursor();
|
||||
|
||||
// switch to alternate screen
|
||||
let mut alternate_screen = AlternateScreen::from(crossterm.context());
|
||||
// put alternate screen in raw mode so that characters wil not be outputted.
|
||||
let mut raw_screen = alternate_screen.into_raw_mode(crossterm.context());
|
||||
if let Ok(alternate) = screen.enable_alternate_modes()
|
||||
{
|
||||
// put alternate screen in raw mode so that characters wil not be outputted.
|
||||
if let Ok(raw) = alternate.enable_raw_modes()
|
||||
{
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input(&raw.screen);
|
||||
let terminal = crossterm.terminal(&raw.screen);
|
||||
let mut cursor = crossterm.cursor(&raw.screen);
|
||||
|
||||
// this will setup the async reading.
|
||||
let mut stdin = input.read_async().bytes();
|
||||
// this will setup the async reading.
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
// loop until the enter key (\r) is pressed.
|
||||
loop {
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
|
||||
// loop until the enter key (\r) is pressed.
|
||||
loop {
|
||||
terminal.clear(ClearType::All);
|
||||
cursor.goto(1, 1);
|
||||
// get the next pressed key
|
||||
let pressed_key = stdin.next();
|
||||
|
||||
// get the next pressed key
|
||||
let pressed_key = stdin.next();
|
||||
terminal.write(format!("\r{:?} <- Character pressed", pressed_key));
|
||||
|
||||
terminal.write(format!("\r{:?} <- Character pressed", pressed_key));
|
||||
// check if pressed key is enter (\r)
|
||||
if let Some(Ok(b'\r')) = pressed_key {
|
||||
break;
|
||||
}
|
||||
|
||||
// check if pressed key is enter (\r)
|
||||
if let Some(Ok(b'\r')) = pressed_key {
|
||||
break;
|
||||
// wait 200 ms and reset cursor write
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
}
|
||||
}
|
||||
|
||||
// wait 200 ms and reset cursor write
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,19 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::Crossterm;
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::Screen;
|
||||
|
||||
pub fn read_char() {
|
||||
let context = Context::new();
|
||||
let input = input(&context);
|
||||
let input = input(&Screen::new());
|
||||
|
||||
match input.read_char() {
|
||||
Ok(c) => println!("character pressed: {}", c),
|
||||
Err(e) => println!("error: {}", e),
|
||||
Ok(s) => println!("char typed: {}", s),
|
||||
Err(e) => println!("char error : {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_line() {
|
||||
let crossterm = Crossterm::new();
|
||||
let input = crossterm.input();
|
||||
let input = input(&Screen::new());
|
||||
|
||||
match input.read_line() {
|
||||
Ok(s) => println!("string typed: {}", s),
|
||||
|
@ -29,40 +29,40 @@ use std::time::Duration;
|
||||
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let mut terminal = Arc::new(Mutex::new(Crossterm::new()));
|
||||
let input = terminal.lock().unwrap().input().read_async();
|
||||
terminal.lock().unwrap().enable_raw_mode();
|
||||
let mut input_buf = Arc::new(Mutex::new(String::new()));
|
||||
let mut key_buf = [0 as u8; 32];
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
swap_write(&mut terminal.lock().unwrap(), "random program output",&input_buf.lock().unwrap());
|
||||
sleep(Duration::from_millis(100));
|
||||
}
|
||||
});
|
||||
}fn main() {
|
||||
let mut terminal = Arc::new(Mutex::new(Crossterm::new()));
|
||||
let input = terminal.lock().unwrap().input().read_async();
|
||||
terminal.lock().unwrap().enable_raw_mode();
|
||||
let mut input_buf = Arc::new(Mutex::new(String::new()));
|
||||
let mut key_buf = [0 as u8; 32];
|
||||
|
||||
loop {
|
||||
let mut term = terminal.lock().unwrap();
|
||||
let (term_width, term_height) = term.terminal().terminal_size();
|
||||
if let Ok(count) = input.read(&mut key_buf) {
|
||||
for idx in 0..count {
|
||||
let b = key_buf.get(idx).unwrap();
|
||||
if *b == 3 {
|
||||
std::process::exit(0); // Ctrl+C = exit immediate
|
||||
} else if *b == 13 {
|
||||
// The return key was pressed.
|
||||
let mut input_buf_tmp = &mut input_buf.lock().unwrap();
|
||||
input_buf.lock().unwrap().clear();
|
||||
swap_write(&mut term, "", &input_buf_tmp);
|
||||
} else {
|
||||
let mut input_buf_tmp = &mut input_buf.lock().unwrap();
|
||||
input_buf_tmp.push(*b as char);
|
||||
swap_write(&mut term, "", &input_buf_tmp);
|
||||
}
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
swap_write(&mut terminal.lock().unwrap(), "random program output",&input_buf.lock().unwrap());
|
||||
sleep(Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
let mut term = terminal.lock().unwrap();
|
||||
let (term_width, term_height) = term.terminal().terminal_size();
|
||||
if let Ok(count) = input.read(&mut key_buf) {
|
||||
for idx in 0..count {
|
||||
let b = key_buf.get(idx).unwrap();
|
||||
if *b == 3 {
|
||||
std::process::exit(0); // Ctrl+C = exit immediate
|
||||
} else if *b == 13 {
|
||||
// The return key was pressed.
|
||||
let mut input_buf_tmp = &mut input_buf.lock().unwrap();
|
||||
input_buf.lock().unwrap().clear();
|
||||
swap_write(&mut term, "", &input_buf_tmp);
|
||||
} else {
|
||||
let mut input_buf_tmp = &mut input_buf.lock().unwrap();
|
||||
input_buf_tmp.push(*b as char);
|
||||
swap_write(&mut term, "", &input_buf_tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ use super::messages::END_MESSAGE;
|
||||
use super::map::Map;
|
||||
|
||||
use crossterm::style::Color;
|
||||
use crossterm::Crossterm;
|
||||
use crossterm::{Crossterm, Screen};
|
||||
|
||||
use super::rand;
|
||||
use super::rand::distributions::{IndependentSample, Range};
|
||||
@ -12,19 +12,19 @@ use super::rand::distributions::{IndependentSample, Range};
|
||||
use std::io::{stdout, Write};
|
||||
use std::{thread, time};
|
||||
|
||||
pub struct FirstDepthSearch<'crossterm>
|
||||
pub struct FirstDepthSearch<'screen>
|
||||
{
|
||||
direction: Direction,
|
||||
map: Map,
|
||||
stack: Vec<Position>,
|
||||
root_pos: Position,
|
||||
is_terminated: bool,
|
||||
crossterm: &'crossterm Crossterm
|
||||
screen: &'screen Screen
|
||||
}
|
||||
|
||||
impl<'crossterm> FirstDepthSearch<'crossterm>
|
||||
impl<'screen> FirstDepthSearch<'screen>
|
||||
{
|
||||
pub fn new(map: Map, start_pos: Position, crossterm: &'crossterm Crossterm) -> FirstDepthSearch<'crossterm>
|
||||
pub fn new(map: Map, start_pos: Position, crossterm: &'screen Screen) -> FirstDepthSearch<'screen>
|
||||
{
|
||||
FirstDepthSearch
|
||||
{
|
||||
@ -33,7 +33,7 @@ impl<'crossterm> FirstDepthSearch<'crossterm>
|
||||
stack: Vec::new(),
|
||||
root_pos: start_pos,
|
||||
is_terminated: false,
|
||||
crossterm: crossterm,
|
||||
screen: crossterm,
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,8 @@ impl<'crossterm> FirstDepthSearch<'crossterm>
|
||||
// push first position on the stack
|
||||
self.stack.push(self.root_pos);
|
||||
|
||||
let mut cursor = self.crossterm.cursor();
|
||||
let crossterm = Crossterm::new();
|
||||
let mut cursor = crossterm.cursor(&self.screen);
|
||||
cursor.hide();
|
||||
|
||||
// loop until there are now items left in the stack.
|
||||
@ -63,15 +64,16 @@ impl<'crossterm> FirstDepthSearch<'crossterm>
|
||||
|
||||
self.update_position();
|
||||
|
||||
let cell = self.crossterm.paint(" ").on(Color::Blue);
|
||||
let cell = crossterm.style(" ").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();
|
||||
cursor.goto(x,y);
|
||||
cell.paint(&self.screen);
|
||||
self.screen.stdout.flush();
|
||||
|
||||
thread::sleep(time::Duration::from_millis(2));
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ mod algorithm;
|
||||
mod messages;
|
||||
mod variables;
|
||||
|
||||
use crossterm::Crossterm;
|
||||
use crossterm::terminal::ClearType;
|
||||
use crossterm::style::Color;
|
||||
use self::crossterm::{ Crossterm, Screen};
|
||||
use self::crossterm::terminal::{terminal, ClearType};
|
||||
use self::crossterm::style::Color;
|
||||
|
||||
use self::variables::{Size, Position };
|
||||
use self::messages::WELCOME_MESSAGE;
|
||||
@ -25,79 +25,74 @@ fn main()
|
||||
/// run the program
|
||||
pub fn run()
|
||||
{
|
||||
// // create new Crossterm instance.
|
||||
let mut crossterm = Crossterm::new();
|
||||
// This is represents the current screen.
|
||||
let screen = Screen::new();
|
||||
|
||||
// set size of terminal so the map we are going to draw is fitting the screen.
|
||||
crossterm.terminal().set_size(110,50);
|
||||
terminal(&screen).set_size(110,50);
|
||||
|
||||
print_welcome_screen(&mut crossterm);
|
||||
print_welcome_screen(&screen);
|
||||
|
||||
start_algorithm(&mut crossterm);
|
||||
|
||||
print_end_screen(&crossterm);
|
||||
start_algorithm(&screen);
|
||||
}
|
||||
|
||||
fn start_algorithm(crossterm: &mut Crossterm)
|
||||
fn start_algorithm(screen: &Screen)
|
||||
{
|
||||
// we first want to switch to alternate screen. On the alternate screen we are going to run or firstdepthsearch algorithm
|
||||
crossterm.to_alternate_screen();
|
||||
if let Ok(ref alternate_screen) = screen.enable_alternate_modes()
|
||||
{
|
||||
// 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);
|
||||
|
||||
// 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(&alternate_screen.screen);
|
||||
|
||||
// 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: &mut Crossterm)
|
||||
{
|
||||
// create the handle for the cursor and terminal.
|
||||
|
||||
crossterm.enable_raw_mode();
|
||||
let mut terminal = crossterm.terminal();
|
||||
let mut cursor = crossterm.cursor();
|
||||
|
||||
// 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\n\
|
||||
Press `q` to abort the program"
|
||||
);
|
||||
|
||||
let input = crossterm.input();
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
// print some progress example.
|
||||
for i in (1..5).rev() {
|
||||
|
||||
let a = stdin.next();
|
||||
|
||||
if let Some(Ok(b'q')) = a {
|
||||
terminal.exit();
|
||||
}
|
||||
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor
|
||||
.goto(48, 10)
|
||||
.print(crossterm.paint(format!("{}", i)).with(Color::Red).on(Color::Blue));
|
||||
|
||||
// 1 second delay
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
// create the algorithm and start it on the alternate screen. Make sure to pass the refrence to the AlternateScreen screen.
|
||||
let mut algorithm = algorithm::FirstDepthSearch::new(map, start_pos, &alternate_screen.screen);
|
||||
algorithm.start();
|
||||
}
|
||||
}
|
||||
|
||||
fn print_welcome_screen(screen: &Screen)
|
||||
{
|
||||
// create the handle for the cursor and terminal.
|
||||
if let Ok(raw) = screen.enable_raw_modes()
|
||||
{
|
||||
let crossterm = Crossterm::new();
|
||||
let terminal = crossterm.terminal(&screen);
|
||||
let cursor = crossterm.cursor(&raw.screen);
|
||||
let input = crossterm.input(&raw.screen);
|
||||
|
||||
// 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\n\
|
||||
Press `q` to abort the program"
|
||||
);
|
||||
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
// print some progress example.
|
||||
for i in (1..5).rev() {
|
||||
let a = stdin.next();
|
||||
|
||||
if let Some(Ok(b'q')) = a {
|
||||
terminal.exit();
|
||||
}
|
||||
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor.goto(48, 10);
|
||||
crossterm.style(format!("{}", i)).with(Color::Red).on(Color::Blue).paint(&screen);
|
||||
|
||||
// 1 second delay
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
use super::variables::{Cell, Position, Size };
|
||||
use crossterm::Crossterm;
|
||||
use crossterm::{Crossterm, Screen};
|
||||
use crossterm::cursor::cursor;
|
||||
use crossterm::style::{ObjectStyle, StyledObject, Color};
|
||||
|
||||
use std::fmt::Display;
|
||||
@ -23,14 +24,14 @@ impl Map
|
||||
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));
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -38,9 +39,10 @@ impl Map
|
||||
}
|
||||
|
||||
// render the map on the screen.
|
||||
pub fn render_map(&mut self, crossterm: &mut Crossterm)
|
||||
pub fn render_map(&mut self, screen: &Screen)
|
||||
{
|
||||
let mut cursor = crossterm.cursor();
|
||||
let crossterm = Crossterm::new();
|
||||
let mut cursor = crossterm.cursor(screen);
|
||||
|
||||
for row in self.map.iter_mut()
|
||||
{
|
||||
@ -48,11 +50,11 @@ impl Map
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
{
|
||||
let cell_style = crossterm.style(column.look).on(column.color);
|
||||
cursor.goto(column.position.x as u16, column.position.y as u16);
|
||||
cell_style.paint(&screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
149
examples/program_examples/logging.rs
Normal file
149
examples/program_examples/logging.rs
Normal file
@ -0,0 +1,149 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::Screen;
|
||||
use std::sync::Mutex;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use std::io::Write;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::thread::{JoinHandle, self};
|
||||
|
||||
/// This is an que that could be shared between threads safely.
|
||||
#[derive(Clone)]
|
||||
struct WorkQueue<T: Send + Clone> {
|
||||
inner: Arc<Mutex<VecDeque<T>>>,
|
||||
}
|
||||
|
||||
impl<T: Send + Clone> WorkQueue<T> {
|
||||
fn new() -> Self {
|
||||
Self { inner: Arc::new(Mutex::new(VecDeque::new())) }
|
||||
}
|
||||
|
||||
// get an item from the que if exists
|
||||
fn get_work(&self) -> Option<T> {
|
||||
let maybe_queue = self.inner.lock();
|
||||
|
||||
if let Ok(mut queue) = maybe_queue {
|
||||
queue.pop_front()
|
||||
} else {
|
||||
panic!("WorkQueue::get_work() tried to lock a poisoned mutex");
|
||||
}
|
||||
}
|
||||
|
||||
// add an item to the que
|
||||
fn add_work(&self, work: T) -> usize {
|
||||
if let Ok(mut queue) = self.inner.lock() {
|
||||
queue.push_back(work);
|
||||
queue.len()
|
||||
} else {
|
||||
panic!("WorkQueue::add_work() tried to lock a poisoned mutex");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SyncFlagTx {
|
||||
inner: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl SyncFlagTx {
|
||||
pub fn set(&mut self, state: bool) -> Result<(), ()> {
|
||||
if let Ok(mut v) = self.inner.lock() {
|
||||
*v = state;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SyncFlagRx {
|
||||
inner: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl SyncFlagRx {
|
||||
pub fn get(&self) -> Result<bool, ()> {
|
||||
if let Ok(v) = self.inner.lock() {
|
||||
Ok(*v)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_sync_flag(initial_state: bool) -> (SyncFlagTx, SyncFlagRx) {
|
||||
let state = Arc::new(Mutex::new(initial_state));
|
||||
let tx = SyncFlagTx { inner: state.clone() };
|
||||
let rx = SyncFlagRx { inner: state.clone() };
|
||||
|
||||
return (tx, rx);
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
let (results_tx, results_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
|
||||
let (mut more_jobs_tx, more_jobs_rx) = new_sync_flag(true);
|
||||
|
||||
// queue with all log entry's.
|
||||
let queue = WorkQueue::new();
|
||||
|
||||
// queue x logs with different threads.
|
||||
let thread_handles = log_with_different_threads(more_jobs_tx.clone(), queue.clone());
|
||||
|
||||
// a thread that will log all logs in the queue.
|
||||
handle_incoming_logs(more_jobs_rx.clone(), queue.clone());
|
||||
|
||||
for handle in thread_handles
|
||||
{
|
||||
handle.join();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_incoming_logs(more_jobs_rx: SyncFlagRx, queue: WorkQueue<String>)
|
||||
{
|
||||
thread::spawn( move || {
|
||||
let mut screen: Screen = Screen::new();
|
||||
|
||||
// Loop while there's expected to be work, looking for work.
|
||||
while more_jobs_rx.get().unwrap() {
|
||||
// If work is available, do that work.
|
||||
if let Some(work) = queue.get_work() {
|
||||
|
||||
// write the log
|
||||
write!(screen, "{}\n", work);
|
||||
screen.flush();
|
||||
}
|
||||
std::thread::yield_now();
|
||||
}
|
||||
}).join();
|
||||
}
|
||||
|
||||
// start different threads that log contiguously.
|
||||
fn log_with_different_threads(more_jobs_tx: SyncFlagTx, queue: WorkQueue<String>) -> Vec<JoinHandle<()>>
|
||||
{
|
||||
// one vector that will have the thread handles in it.
|
||||
let mut threads = Vec::new();
|
||||
|
||||
for thread_num in 1..5
|
||||
{
|
||||
let mut more_jobs = more_jobs_tx.clone();
|
||||
let thread_queue = queue.clone();
|
||||
|
||||
// create new thread
|
||||
let thread = thread::spawn(move || {
|
||||
|
||||
// log 400 messages
|
||||
for log_entry_count in 1..400
|
||||
{
|
||||
thread_queue.add_work(format!("Log {} from thread {} ",log_entry_count, thread_num));
|
||||
more_jobs.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
threads.push(thread);
|
||||
}
|
||||
|
||||
println!("All logging threads started");
|
||||
return threads;
|
||||
}
|
@ -16,31 +16,20 @@ extern crate crossterm;
|
||||
|
||||
use crossterm::style::Color;
|
||||
use crossterm::Crossterm;
|
||||
|
||||
use crossterm::write::Stdout;
|
||||
use crossterm::common::screen::Screen;
|
||||
use std::io::Write;
|
||||
// mod terminal;
|
||||
// mod color;
|
||||
// mod cursor;
|
||||
// mod crossterm_type;
|
||||
// mod input;
|
||||
mod input;
|
||||
|
||||
//use input::keyboard::{async_input, input as stdin};
|
||||
|
||||
use std::{thread, time};
|
||||
use std::{thread, time, };
|
||||
use std::sync::mpsc;
|
||||
|
||||
fn main() {
|
||||
do_something();
|
||||
input::keyboard::async_input::async_reading_on_alternate_screen();
|
||||
}
|
||||
|
||||
fn do_something()
|
||||
{
|
||||
let mut crossterm = Crossterm::new();
|
||||
|
||||
{
|
||||
let mut cursor = crossterm.cursor(); // <- Immutable borrow occurs here ( cursor(&self) ) end lives until the end of this function call.
|
||||
cursor.goto(10, 10);
|
||||
}
|
||||
crossterm.to_alternate_screen(); // <- mutable borrow occurs here ( to_alternate_screen(&mut self) ) but because we already have borrowed immutable we can not mutate it.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
//! This module contains some commands that could be executed for specific task.
|
||||
|
||||
use super::super::manager::ScreenManager;
|
||||
use std::io::Result;
|
||||
use super::super::write::Stdout;
|
||||
use std::io;
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub mod shared_commands;
|
||||
use common::screen::Screen;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub mod unix_command;
|
||||
@ -13,23 +15,23 @@ pub mod win_commands;
|
||||
|
||||
/// This trait provides a way to execute some state changing commands.
|
||||
pub trait IStateCommand {
|
||||
fn execute(&mut self) -> Result<()>;
|
||||
fn undo(&mut self) -> Result<()>;
|
||||
fn execute(&mut self) -> io::Result<()>;
|
||||
fn undo(&mut self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
pub trait IEnableAnsiCommand {
|
||||
fn enable(&mut self) -> bool;
|
||||
fn disable(&mut self) -> bool;
|
||||
fn enable(&self) -> bool;
|
||||
fn disable(&self) -> bool;
|
||||
}
|
||||
|
||||
// This trait provides an interface for switching to alternate screen and back.
|
||||
pub trait IAlternateScreenCommand: Send {
|
||||
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()>;
|
||||
fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()>;
|
||||
fn enable(&self, screen_manager: &mut Stdout) -> io::Result<()>;
|
||||
fn disable(&self, screen_manager: &Stdout) -> io::Result<()>;
|
||||
}
|
||||
|
||||
// This trait provides an interface for switching to raw mode and back.
|
||||
/*pub trait IRawScreenCommand: Send{
|
||||
fn enable(&mut self) -> Result<()>;
|
||||
fn disable(&mut self) -> Result<()>;
|
||||
}*/
|
||||
pub trait IRawScreenCommand: Send{
|
||||
fn enable(&mut self) -> io::Result<()>;
|
||||
fn disable(&self) -> io::Result<()>;
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! This module contains the commands that can be used for both unix and windows 10 systems because they support ANSI escape codes
|
||||
|
||||
use super::{IAlternateScreenCommand, ScreenManager};
|
||||
use super::{IAlternateScreenCommand, Stdout};
|
||||
|
||||
use std::io::Result;
|
||||
use std::sync::Mutex;
|
||||
use std::io::{ Result, stdout, Write};
|
||||
|
||||
/// This command is used for switching to alternate screen and back to main screen.
|
||||
pub struct ToAlternateScreenCommand;
|
||||
@ -14,14 +15,15 @@ impl ToAlternateScreenCommand {
|
||||
}
|
||||
|
||||
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
||||
|
||||
/// enable alternate screen.
|
||||
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
|
||||
fn enable(&self, screen_manager: &mut Stdout) -> Result<()> {
|
||||
screen_manager.write_str(csi!("?1049h"));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// disable alternate screen.
|
||||
fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
|
||||
fn disable(&self, screen_manager: &Stdout) -> Result<()> {
|
||||
screen_manager.write_str(csi!("?1049l"));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! This module contains the commands that can be used for unix systems.
|
||||
|
||||
use super::{ IStateCommand};
|
||||
use super::{ IStateCommand, IRawScreenCommand};
|
||||
use kernel::unix_kernel::terminal;
|
||||
use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH};
|
||||
|
||||
@ -60,15 +60,18 @@ pub struct RawModeCommand {
|
||||
original_mode: Result<Termios>,
|
||||
}
|
||||
|
||||
impl RawModeCommand {
|
||||
impl RawModeCommand
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
RawModeCommand {
|
||||
original_mode: terminal::get_terminal_mode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawModeCommand {
|
||||
/// Enables raw mode.
|
||||
pub fn enable(&mut self) -> Result<()> {
|
||||
fn enable(&mut self) -> Result<()> {
|
||||
if let Ok(original_mode) = self.original_mode {
|
||||
let mut new_mode = original_mode;
|
||||
terminal::make_raw(&mut new_mode);
|
||||
@ -83,7 +86,7 @@ impl RawModeCommand {
|
||||
}
|
||||
|
||||
/// Disables raw mode.
|
||||
pub fn disable(&mut self) -> Result<()> {
|
||||
fn disable(&self) -> Result<()> {
|
||||
if let Ok(ref original_mode) = self.original_mode {
|
||||
let result = terminal::set_terminal_mode(&original_mode)?;
|
||||
} else {
|
||||
|
@ -1,14 +1,16 @@
|
||||
//! This module contains the commands that can be used for windows systems.
|
||||
|
||||
use super::{IAlternateScreenCommand, IEnableAnsiCommand, ScreenManager};
|
||||
use super::{IAlternateScreenCommand, IEnableAnsiCommand, IRawScreenCommand, Stdout};
|
||||
|
||||
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
|
||||
use modules::write::IStdout;
|
||||
use std::mem;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::wincon;
|
||||
use winapi::um::wincon::{CHAR_INFO, COORD, ENABLE_VIRTUAL_TERMINAL_PROCESSING, SMALL_RECT};
|
||||
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// This command is used for enabling and disabling ANSI code support for windows systems,
|
||||
/// For more info check: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences.
|
||||
@ -27,7 +29,7 @@ impl EnableAnsiCommand {
|
||||
}
|
||||
|
||||
impl IEnableAnsiCommand for EnableAnsiCommand {
|
||||
fn enable(&mut self) -> bool {
|
||||
fn enable(&self) -> bool {
|
||||
// we need to check whether we tried to enable ansi before. If we have we can just return if that had succeeded.
|
||||
if ansi_support::has_been_tried_to_enable_ansi() && ansi_support::ansi_enabled() {
|
||||
return ansi_support::windows_supportable();
|
||||
@ -47,7 +49,7 @@ impl IEnableAnsiCommand for EnableAnsiCommand {
|
||||
}
|
||||
}
|
||||
|
||||
fn disable(&mut self) -> bool {
|
||||
fn disable(&self) -> bool {
|
||||
if ansi_support::ansi_enabled() {
|
||||
let output_handle = handle::get_output_handle().unwrap();
|
||||
|
||||
@ -74,7 +76,8 @@ pub struct RawModeCommand {
|
||||
mask: DWORD,
|
||||
}
|
||||
|
||||
impl RawModeCommand {
|
||||
impl RawModeCommand
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
use self::wincon::{ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT};
|
||||
|
||||
@ -82,9 +85,11 @@ impl RawModeCommand {
|
||||
mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IRawScreenCommand for RawModeCommand {
|
||||
/// Enables raw mode.
|
||||
pub fn enable(&mut self) -> Result<()> {
|
||||
fn enable(&mut self) -> Result<()> {
|
||||
let input_handle = handle::get_input_handle()?;
|
||||
|
||||
let mut dw_mode: DWORD = 0;
|
||||
@ -108,7 +113,7 @@ impl RawModeCommand {
|
||||
}
|
||||
|
||||
/// Disables raw mode.
|
||||
pub fn disable(&mut self) -> Result<()> {
|
||||
fn disable(&self) -> Result<()> {
|
||||
let output_handle = handle::get_input_handle()?;
|
||||
|
||||
let mut dw_mode: DWORD = 0;
|
||||
@ -143,8 +148,8 @@ impl ToAlternateScreenCommand {
|
||||
}
|
||||
|
||||
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
||||
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
|
||||
use super::super::super::manager::WinApiScreenManager;
|
||||
fn enable(&self, screen_manager: &mut Stdout) -> Result<()> {
|
||||
use super::super::super::modules::write::WinApiStdout;
|
||||
|
||||
let handle = handle::get_output_handle()?;
|
||||
|
||||
@ -154,28 +159,20 @@ impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
||||
// Make the new screen buffer the active screen buffer.
|
||||
csbi::set_active_screen_buffer(new_handle)?;
|
||||
|
||||
match screen_manager
|
||||
let b: &mut WinApiStdout = match screen_manager
|
||||
.as_any_mut()
|
||||
.downcast_mut::<WinApiScreenManager>()
|
||||
{
|
||||
Some(b) => b.set_alternate_handle(new_handle),
|
||||
None => return Err(Error::new(ErrorKind::Other, "Invalid cast exception")),
|
||||
};
|
||||
|
||||
let b: &mut WinApiScreenManager = match screen_manager
|
||||
.as_any_mut()
|
||||
.downcast_mut::<WinApiScreenManager>()
|
||||
.downcast_mut::<WinApiStdout>()
|
||||
{
|
||||
Some(b) => b,
|
||||
None => return Err(Error::new(ErrorKind::Other, "Invalid cast exception")),
|
||||
};
|
||||
|
||||
b.set_alternate_handle(new_handle);
|
||||
b.set(new_handle);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
|
||||
fn disable(&self, screen_manager: &Stdout) -> Result<()> {
|
||||
let handle = handle::get_output_handle()?;
|
||||
csbi::set_active_screen_buffer(handle);
|
||||
|
||||
|
@ -1,17 +1,18 @@
|
||||
use super::commands::{IAlternateScreenCommand};
|
||||
|
||||
use super::screen::AlternateScreen;
|
||||
use super::screen::{AlternateScreen, Screen};
|
||||
|
||||
use super::super::cursor;
|
||||
use super::super::input;
|
||||
use super::super::manager;
|
||||
use super::super::write;
|
||||
use super::super::style;
|
||||
use super::super::terminal;
|
||||
use super::super::terminal;
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::io::Write;
|
||||
|
||||
use std::sync::RwLock;
|
||||
use std::io::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use common::commands::unix_command;
|
||||
@ -19,143 +20,58 @@ use common::commands::unix_command;
|
||||
#[cfg(windows)]
|
||||
use common::commands::win_commands;
|
||||
|
||||
pub struct Crossterm {
|
||||
pub active_screen: manager::ScreenManager,
|
||||
use write::Stdout;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
raw_terminal: Option<unix_command::RawModeCommand>,
|
||||
pub struct Crossterm { }
|
||||
|
||||
#[cfg(windows)]
|
||||
raw_terminal: Option<win_commands::RawModeCommand>,
|
||||
// Would be cool to figure out a way to have multiple screens instead of just only the main and alternate screen.
|
||||
// For windows this would be easy but for unix I have no idea.
|
||||
alternate_screen: Option<Box<IAlternateScreenCommand + Send>>,
|
||||
}
|
||||
|
||||
impl<'a> Crossterm {
|
||||
impl<'crossterm> Crossterm {
|
||||
pub fn new() -> Crossterm {
|
||||
Crossterm {
|
||||
active_screen: manager::ScreenManager::new(),
|
||||
raw_terminal: None,
|
||||
alternate_screen: None,
|
||||
}
|
||||
Crossterm {}
|
||||
}
|
||||
|
||||
pub fn enable_raw_mode(&mut self) -> Result<()> {
|
||||
match self.raw_terminal {
|
||||
None => {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let raw_terminal = Some(unix_command::RawModeCommand::new());
|
||||
#[cfg(target_os = "windows")]
|
||||
let raw_terminal = Some(win_commands::RawModeCommand::new());
|
||||
|
||||
self.raw_terminal = raw_terminal;
|
||||
|
||||
return self.enable_raw_mode();
|
||||
}
|
||||
Some(ref mut raw_terminal) => {
|
||||
raw_terminal.enable()?;
|
||||
self.active_screen.set_is_raw_screen(true);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
pub fn cursor(&self, screen: &'crossterm Screen) -> cursor::TerminalCursor {
|
||||
cursor::TerminalCursor::new(&screen.stdout.clone())
|
||||
}
|
||||
|
||||
pub fn disable_raw_mode(&mut self) -> Result<()> {
|
||||
match self.raw_terminal {
|
||||
None => {
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let raw_terminal = Some(unix_command::RawModeCommand::new());
|
||||
#[cfg(target_os = "windows")]
|
||||
let raw_terminal = Some(win_commands::RawModeCommand::new());
|
||||
|
||||
self.raw_terminal = raw_terminal;
|
||||
return self.disable_raw_mode();
|
||||
}
|
||||
Some(ref mut raw_terminal) => {
|
||||
raw_terminal.disable()?;
|
||||
self.active_screen.set_is_raw_screen(false);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
pub fn input(&self, screen: &'crossterm Screen) -> input::TerminalInput {
|
||||
return input::TerminalInput::new(&screen.stdout);
|
||||
}
|
||||
|
||||
pub fn to_alternate_screen(&mut self) -> Result<()> {
|
||||
match self.alternate_screen {
|
||||
None => {
|
||||
self.alternate_screen = Some(AlternateScreen::new());
|
||||
return self.to_alternate_screen();
|
||||
}
|
||||
Some(ref mut alternate_screen) => {
|
||||
alternate_screen.enable(&mut self.active_screen)?;
|
||||
self.active_screen.set_is_alternate_screen(true);
|
||||
}
|
||||
}
|
||||
pub fn terminal(&self, screen: &'crossterm Screen) -> terminal::Terminal {
|
||||
return terminal::Terminal::new(&screen.stdout);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
pub fn color(&self, screen: &'crossterm Screen) -> style::TerminalColor {
|
||||
return style::TerminalColor::new(&screen.stdout);
|
||||
}
|
||||
|
||||
pub fn to_main_screen(&mut self) -> Result<()> {
|
||||
match self.alternate_screen {
|
||||
None => {
|
||||
self.alternate_screen = Some(AlternateScreen::new());
|
||||
return self.to_main_screen();
|
||||
}
|
||||
Some(ref mut alternate_screen) => {
|
||||
alternate_screen.disable(&mut self.active_screen)?;
|
||||
self.active_screen.set_is_alternate_screen(false);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub fn cursor(&self) -> cursor::TerminalCursor {
|
||||
cursor::TerminalCursor::new(&self.active_screen)
|
||||
}
|
||||
|
||||
pub fn input(&self) -> input::TerminalInput {
|
||||
return input::TerminalInput::new(&self.active_screen);
|
||||
}
|
||||
|
||||
pub fn terminal(&self) -> terminal::Terminal {
|
||||
return terminal::Terminal::new(&self.active_screen);
|
||||
}
|
||||
|
||||
pub fn color(&self) -> style::TerminalColor {
|
||||
return style::TerminalColor::new(&self.active_screen);
|
||||
}
|
||||
|
||||
// Wraps an displayable object so it can be formatted with colors and attributes.
|
||||
//
|
||||
// Check `/examples/color` in the libary for more spesific examples.
|
||||
//
|
||||
pub fn paint<D>(&self, val: D) -> style::StyledObject<D>
|
||||
// Wraps an displayable object so it can be formatted with colors and attributes.
|
||||
//
|
||||
// Check `/examples/color` in the libary for more spesific examples.
|
||||
pub fn style<D>(&self, val: D) -> style::StyledObject<D>
|
||||
where
|
||||
D: Display,
|
||||
{
|
||||
style::ObjectStyle::new().apply_to(val, &self.active_screen)
|
||||
D: Display, {
|
||||
style::ObjectStyle::new().apply_to(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Crossterm {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.active_screen.write_buf(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
self.active_screen.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Crossterm {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref mut screen) = self.alternate_screen {
|
||||
screen.disable(&mut self.active_screen);
|
||||
}
|
||||
if let Some(ref mut raw_terminal) = self.raw_terminal {
|
||||
raw_terminal.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
//impl Write for Crossterm {M
|
||||
// fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
// self.active_screen.write_buf(buf)
|
||||
// }
|
||||
//
|
||||
// fn flush(&mut self) -> Result<()> {
|
||||
// self.active_screen.flush()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//impl Drop for Crossterm {
|
||||
// fn drop(&mut self) {
|
||||
// if let Some(ref mut screen) = self.alternate_screen {
|
||||
// screen.disable(&mut self.active_screen);
|
||||
// }
|
||||
// if let Some(ref mut raw_terminal) = self.raw_terminal {
|
||||
// raw_terminal.disable();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! Some actions need to preformed platform independently since they can not be solved `ANSI escape codes`.
|
||||
|
||||
use super::ScreenManager;
|
||||
use super::Stdout;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(windows)]
|
||||
use kernel::windows_kernel::terminal::{buffer_size, exit, terminal_size};
|
||||
@ -21,12 +22,12 @@ pub fn get_terminal_size() -> (u16, u16) {
|
||||
}
|
||||
|
||||
/// Get the cursor position based on the current platform.
|
||||
pub fn get_cursor_position(screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
pub fn get_cursor_position(stdout: &Arc<Stdout>) -> (u16, u16) {
|
||||
#[cfg(unix)]
|
||||
return pos();
|
||||
return pos(stdout);
|
||||
|
||||
#[cfg(windows)]
|
||||
return pos(screen_manager);
|
||||
return pos(stdout);
|
||||
}
|
||||
|
||||
/// exit the current terminal.
|
||||
|
@ -10,4 +10,5 @@ pub mod traits;
|
||||
mod crossterm;
|
||||
|
||||
pub use self::crossterm::Crossterm;
|
||||
use super::manager::ScreenManager;
|
||||
use super::modules::Stdout;
|
||||
pub use screen::Screen;
|
||||
|
@ -22,17 +22,27 @@
|
||||
//! Todo: example
|
||||
//!
|
||||
|
||||
use super::commands;
|
||||
use super::{functions, ScreenManager};
|
||||
use super::commands::{self, IAlternateScreenCommand};
|
||||
use super::{functions, Screen, Stdout, RawScreen};
|
||||
|
||||
use std::convert::From;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub struct AlternateScreen;
|
||||
pub struct AlternateScreen
|
||||
{
|
||||
command: Box<IAlternateScreenCommand + Send>,
|
||||
pub screen: Screen,
|
||||
}
|
||||
|
||||
impl AlternateScreen {
|
||||
/// Create an new alternate screen type.
|
||||
pub fn new() -> Box<commands::IAlternateScreenCommand + Send> {
|
||||
|
||||
pub fn new(command: Box<IAlternateScreenCommand + Send>, screen: Screen) -> Self
|
||||
{
|
||||
return AlternateScreen { command, screen }
|
||||
}
|
||||
|
||||
pub fn to_alternate_screen(screen_manager: Stdout) -> io::Result<AlternateScreen> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Send>>(
|
||||
Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
|
||||
@ -42,6 +52,25 @@ impl AlternateScreen {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let command = Box::from(commands::shared_commands::ToAlternateScreenCommand::new());
|
||||
|
||||
command
|
||||
let mut stdout = screen_manager;
|
||||
command.enable(&mut stdout)?;
|
||||
return Ok(AlternateScreen::new(command, Screen::from(stdout)));
|
||||
}
|
||||
|
||||
pub fn to_main_screen(&self) -> io::Result<()> {
|
||||
self.command.disable(&self.screen.stdout)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enable_raw_modes(&self) -> io::Result<RawScreen>
|
||||
{
|
||||
return self.screen.enable_raw_modes();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AlternateScreen
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.to_main_screen();
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@
|
||||
|
||||
mod alternate;
|
||||
mod raw;
|
||||
mod screen;
|
||||
|
||||
use super::{commands, functions, ScreenManager};
|
||||
use super::{commands, functions, Stdout};
|
||||
|
||||
pub use self::alternate::AlternateScreen;
|
||||
//pub use self::raw::RawScreen;
|
||||
pub use self::screen::Screen;
|
||||
pub use self::raw::RawScreen;
|
||||
|
@ -12,21 +12,47 @@
|
||||
//!
|
||||
//! With these modes you can easier design the terminal screen.
|
||||
|
||||
//
|
||||
//use super::commands;
|
||||
//use super::{functions, ScreenManager};
|
||||
//
|
||||
//use std::io::{self, Write};
|
||||
//
|
||||
///// A wrapper for the raw terminal state. Which can be used to write to.
|
||||
//pub struct RawScreen;
|
||||
//
|
||||
//impl RawScreen {
|
||||
// /// Create a new RawScreen type.
|
||||
// pub fn new() -> Box<commands::IRawScreenCommand> {
|
||||
// Box::from(EnableRawModeCommand::new())
|
||||
// }
|
||||
//}
|
||||
use super::commands::*;
|
||||
use super::{functions, Screen};
|
||||
|
||||
use std::io::{self, Write};
|
||||
|
||||
/// A wrapper for the raw terminal state. Which can be used to write to.
|
||||
pub struct RawScreen
|
||||
{
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
command: unix_command::RawModeCommand,
|
||||
#[cfg(target_os = "windows")]
|
||||
command: win_commands::RawModeCommand,
|
||||
|
||||
pub screen: Screen,
|
||||
}
|
||||
|
||||
impl RawScreen {
|
||||
pub fn into_raw_mode(screen: Screen) -> io::Result<RawScreen>
|
||||
{
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let command = unix_command::RawModeCommand::new();
|
||||
#[cfg(target_os = "windows")]
|
||||
let command = win_commands::RawModeCommand::new();
|
||||
|
||||
Ok(RawScreen { command: command, screen})
|
||||
}
|
||||
|
||||
pub fn disable_raw_modes(&self) -> io::Result<()>
|
||||
{
|
||||
self.command.disable()?;
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawScreen
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
self.disable_raw_modes();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
/////// Trait withs contains a method for switching into raw mode.
|
||||
////pub trait IntoRawMode: Write + Sized {
|
||||
|
58
src/common/screen/screen.rs
Normal file
58
src/common/screen/screen.rs
Normal file
@ -0,0 +1,58 @@
|
||||
#[cfg(not(windows))]
|
||||
use common::commands::unix_command;
|
||||
|
||||
#[cfg(windows)]
|
||||
use common::commands::win_commands;
|
||||
|
||||
use common::commands::IAlternateScreenCommand;
|
||||
|
||||
use super::{AlternateScreen,RawScreen};
|
||||
use super::super::super::modules::write::Stdout;
|
||||
|
||||
use std::io::Write;
|
||||
use std::io::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Screen
|
||||
{
|
||||
buffer: Vec<u8>,
|
||||
pub stdout: Arc<Stdout>,
|
||||
}
|
||||
|
||||
impl Screen
|
||||
{
|
||||
pub fn new() -> Screen
|
||||
{
|
||||
return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() };
|
||||
}
|
||||
|
||||
pub fn from(stdout: Stdout) -> Screen
|
||||
{
|
||||
return Screen { stdout: Arc::new(stdout), buffer: Vec::new() };
|
||||
}
|
||||
|
||||
pub fn enable_raw_modes(&self) -> Result<RawScreen> {
|
||||
let mut screen = Screen::from(Stdout::new(true));
|
||||
let raw_screen = RawScreen::into_raw_mode(screen)?;
|
||||
return Ok(raw_screen)
|
||||
}
|
||||
|
||||
pub fn enable_alternate_modes(&self) -> Result<AlternateScreen> {
|
||||
let mut stdout = Stdout::new(true);
|
||||
let alternate_screen = AlternateScreen::to_alternate_screen(stdout)?;
|
||||
return Ok(alternate_screen);
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Screen
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.buffer.write(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> Result<()> {
|
||||
self.stdout.write_buf(&self.buffer);
|
||||
self.stdout.flush()
|
||||
}
|
||||
}
|
@ -2,15 +2,14 @@
|
||||
|
||||
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ};
|
||||
use common::commands::unix_command::{EnableRawModeCommand, NoncanonicalModeCommand};
|
||||
use libc;
|
||||
use {libc, Stdout};
|
||||
pub use libc::termios;
|
||||
|
||||
use std::io::Error;
|
||||
use std::io::ErrorKind;
|
||||
use std::io::Read;
|
||||
use std::sync::Arc;
|
||||
use std::io::{self, Error, ErrorKind, Read};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{fs, io, mem};
|
||||
use std::{fs, mem};
|
||||
use termios::{cfmakeraw, tcsetattr, Termios, TCSADRAIN};
|
||||
|
||||
use Crossterm;
|
||||
@ -46,9 +45,9 @@ pub fn terminal_size() -> (u16, u16) {
|
||||
}
|
||||
|
||||
/// Get the current cursor position.
|
||||
pub fn pos() -> (u16, u16) {
|
||||
pub fn pos(stdout: &Arc<Stdout>) -> (u16, u16) {
|
||||
let mut crossterm = Crossterm::new();
|
||||
let input = crossterm.input();
|
||||
let input = crossterm.input(stdout);
|
||||
|
||||
let delimiter = b'R';
|
||||
let mut stdin = input.read_until_async(delimiter);
|
||||
|
@ -10,12 +10,13 @@ use winapi::um::wincon::{
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
|
||||
|
||||
use super::{handle, kernel, Empty, ScreenManager};
|
||||
use super::{handle, kernel, Empty, Stdout};
|
||||
use std::io::{self, ErrorKind, Result};
|
||||
use std::mem::size_of;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Create a new console screen buffer info struct.
|
||||
pub fn get_csbi(screen_manager: &ScreenManager) -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
||||
pub fn get_csbi(screen_manager: &Arc<Stdout>) -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
||||
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
|
||||
let success;
|
||||
|
||||
@ -35,7 +36,7 @@ pub fn get_csbi(screen_manager: &ScreenManager) -> Result<CONSOLE_SCREEN_BUFFER_
|
||||
|
||||
/// Get buffer info and handle of the current screen.
|
||||
pub fn get_csbi_and_handle(
|
||||
screen_manager: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) -> Result<(CONSOLE_SCREEN_BUFFER_INFO, HANDLE)> {
|
||||
let handle = handle::get_current_handle(screen_manager)?;
|
||||
let csbi = get_csbi_by_handle(&handle)?;
|
||||
@ -60,7 +61,7 @@ pub fn get_csbi_by_handle(handle: &HANDLE) -> Result<CONSOLE_SCREEN_BUFFER_INFO>
|
||||
}
|
||||
|
||||
/// Set the console screen buffer size
|
||||
pub fn set_console_screen_buffer_size(size: COORD, screen_manager: &ScreenManager) -> bool {
|
||||
pub fn set_console_screen_buffer_size(size: COORD, screen_manager: &Arc<Stdout>) -> bool {
|
||||
let handle = handle::get_current_handle(screen_manager).unwrap();
|
||||
|
||||
unsafe {
|
||||
|
@ -5,16 +5,17 @@ use winapi::um::wincon::{
|
||||
SetConsoleCursorInfo, SetConsoleCursorPosition, CONSOLE_CURSOR_INFO, COORD,
|
||||
};
|
||||
|
||||
use super::super::super::manager::{ScreenManager, WinApiScreenManager};
|
||||
use super::super::super::modules::write::{Stdout, WinApiStdout};
|
||||
use super::{csbi, handle, kernel};
|
||||
|
||||
use std::io::{self, ErrorKind, Result};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// This stores the cursor pos, at program level. So it can be recalled later.
|
||||
static mut SAVED_CURSOR_POS: (u16, u16) = (0, 0);
|
||||
|
||||
/// Reset to saved cursor position
|
||||
pub fn reset_to_saved_position(screen_manager: &ScreenManager) {
|
||||
pub fn reset_to_saved_position(screen_manager: &Arc<Stdout>) {
|
||||
unsafe {
|
||||
set_console_cursor_position(
|
||||
SAVED_CURSOR_POS.0 as i16,
|
||||
@ -25,7 +26,7 @@ pub fn reset_to_saved_position(screen_manager: &ScreenManager) {
|
||||
}
|
||||
|
||||
/// Save current cursor position to recall later.
|
||||
pub fn save_cursor_pos(screen_manager: &ScreenManager) {
|
||||
pub fn save_cursor_pos(screen_manager: &Arc<Stdout>) {
|
||||
let position = pos(screen_manager);
|
||||
|
||||
unsafe {
|
||||
@ -34,7 +35,7 @@ pub fn save_cursor_pos(screen_manager: &ScreenManager) {
|
||||
}
|
||||
|
||||
/// get the current cursor position.
|
||||
pub fn pos(screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
pub fn pos(screen_manager: &Arc<Stdout>) -> (u16, u16) {
|
||||
let handle = handle::get_current_handle(screen_manager).unwrap();
|
||||
|
||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
||||
@ -48,7 +49,7 @@ pub fn pos(screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
}
|
||||
|
||||
/// Set the cursor position to the given x and y. Note that this is 0 based.
|
||||
pub fn set_console_cursor_position(x: i16, y: i16, screen_manager: &ScreenManager) {
|
||||
pub fn set_console_cursor_position(x: i16, y: i16, screen_manager: &Arc<Stdout>) {
|
||||
if x < 0 || x >= <i16>::max_value() {
|
||||
panic!(
|
||||
"Argument Out of Range Exception when setting cursor position to X: {}",
|
||||
@ -77,7 +78,7 @@ pub fn set_console_cursor_position(x: i16, y: i16, screen_manager: &ScreenManage
|
||||
}
|
||||
|
||||
/// change the cursor visibility.
|
||||
pub fn cursor_visibility(visable: bool, screen_manager: &ScreenManager) -> Result<()> {
|
||||
pub fn cursor_visibility(visable: bool, screen_manager: &Arc<Stdout>) -> Result<()> {
|
||||
let handle = handle::get_current_handle(screen_manager).unwrap();
|
||||
|
||||
let cursor_info = CONSOLE_CURSOR_INFO {
|
||||
|
@ -5,20 +5,20 @@ use winapi::um::processenv::GetStdHandle;
|
||||
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use std::sync::Arc;
|
||||
use super::super::super::manager::{ScreenManager, WinApiScreenManager};
|
||||
use super::super::super::modules::write::{Stdout, WinApiStdout};
|
||||
|
||||
/// Get the global stored handle whits provides access to the current screen.
|
||||
pub fn get_current_handle(screen_manager: &ScreenManager) -> Result<HANDLE> {
|
||||
pub fn get_current_handle(screen_manager: &Arc<Stdout>) -> Result<HANDLE> {
|
||||
let mut mutex = screen_manager;
|
||||
|
||||
let handle: Result<HANDLE>;
|
||||
|
||||
let winapi_screen_manager: &WinApiScreenManager = match screen_manager
|
||||
let winapi_screen_manager: &WinApiStdout = match screen_manager
|
||||
.as_any()
|
||||
.downcast_ref::<WinApiScreenManager>()
|
||||
.downcast_ref::<WinApiStdout>()
|
||||
{
|
||||
Some(win_api) => win_api,
|
||||
None => return Err(io::Error::new(io::ErrorKind::Other,"Could not convert to winapi screen manager, this could happen when the user has an ANSI screen manager and is calling the platform specific operations 'get_cursor_pos' or 'get_terminal_size'"))
|
||||
None => return Err(io::Error::new(io::ErrorKind::Other,"Could not convert to winapi screen write, this could happen when the user has an ANSI screen write and is calling the platform specific operations 'get_cursor_pos' or 'get_terminal_size'"))
|
||||
};
|
||||
|
||||
|
||||
|
@ -6,10 +6,11 @@ use winapi::um::wincon::{
|
||||
};
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use super::super::super::manager::ScreenManager;
|
||||
use super::super::super::modules::Stdout;
|
||||
use super::{handle, Empty};
|
||||
|
||||
use std::io::{ErrorKind, Result};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Get the largest console window size possible.
|
||||
pub fn get_largest_console_window_size() -> COORD {
|
||||
@ -33,7 +34,7 @@ pub fn get_console_mode(handle: &HANDLE, current_mode: &mut u32) -> bool {
|
||||
}
|
||||
|
||||
/// Change the console text attribute.
|
||||
pub fn set_console_text_attribute(value: u16, screen_manager: &ScreenManager) -> bool {
|
||||
pub fn set_console_text_attribute(value: u16, screen_manager: &Arc<Stdout>) -> bool {
|
||||
let handle = handle::get_current_handle(screen_manager).unwrap();
|
||||
|
||||
unsafe {
|
||||
@ -42,7 +43,7 @@ pub fn set_console_text_attribute(value: u16, screen_manager: &ScreenManager) ->
|
||||
}
|
||||
|
||||
/// Change console info.
|
||||
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT, screen_manager: &ScreenManager) -> bool {
|
||||
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT, screen_manager: &Arc<Stdout>) -> bool {
|
||||
let handle = handle::get_current_handle(screen_manager).unwrap();
|
||||
|
||||
let absolute = match absolute {
|
||||
|
@ -8,7 +8,7 @@ pub mod kernel;
|
||||
pub mod terminal;
|
||||
pub mod writing;
|
||||
|
||||
use super::super::manager::ScreenManager;
|
||||
use super::super::modules::Stdout;
|
||||
use common::traits::Empty;
|
||||
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! This module contains terminal specific logic.
|
||||
|
||||
use super::{csbi, handle, ScreenManager};
|
||||
use super::{csbi, handle, Stdout};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Get the terminal size
|
||||
pub fn terminal_size() -> (u16, u16) {
|
||||
@ -16,7 +18,7 @@ pub fn terminal_size() -> (u16, u16) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_size(screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
pub fn buffer_size(screen_manager: &Arc<Stdout>) -> (u16, u16) {
|
||||
let handle = handle::get_output_handle().unwrap();
|
||||
|
||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
||||
|
@ -9,17 +9,18 @@ use winapi::um::wincon::{
|
||||
};
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use super::{csbi, handle, kernel, ScreenManager};
|
||||
use super::{csbi, handle, kernel, Stdout};
|
||||
|
||||
use std::io::{self, ErrorKind, Result};
|
||||
use std::str;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// 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: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) -> bool {
|
||||
let handle = handle::get_current_handle(screen_manager).unwrap();
|
||||
|
||||
@ -41,7 +42,7 @@ pub fn fill_console_output_attribute(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32,
|
||||
screen_manager: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) -> bool {
|
||||
// Get the position of the current console window
|
||||
|
||||
|
@ -12,12 +12,13 @@ mod modules;
|
||||
pub use common::screen;
|
||||
pub use modules::cursor;
|
||||
pub use modules::input;
|
||||
pub use modules::manager;
|
||||
pub use modules::write;
|
||||
pub use modules::style;
|
||||
pub use modules::terminal;
|
||||
pub use modules::terminal;
|
||||
|
||||
pub use common::Crossterm;
|
||||
|
||||
pub use write::{IStdout, Stdout};
|
||||
pub use common::screen::Screen;
|
||||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
#[cfg(unix)]
|
||||
|
@ -2,7 +2,10 @@
|
||||
//! This module is used for windows 10 terminals and unix terminals by default.
|
||||
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
|
||||
|
||||
use super::{functions, ITerminalCursor, ScreenManager};
|
||||
use super::{functions, ITerminalCursor, Stdout};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
/// This struct is an ansi implementation for cursor related actions.
|
||||
pub struct AnsiCursor;
|
||||
@ -14,47 +17,47 @@ impl AnsiCursor {
|
||||
}
|
||||
|
||||
impl ITerminalCursor for AnsiCursor {
|
||||
fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager) {
|
||||
fn goto(&self, x: u16, y: u16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{};{}H"), y + 1, x + 1));
|
||||
}
|
||||
|
||||
fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
fn pos(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
|
||||
functions::get_cursor_position(screen_manager)
|
||||
}
|
||||
|
||||
fn move_up(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_up(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{}A"), count));
|
||||
}
|
||||
|
||||
fn move_right(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_right(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{}C"), count));
|
||||
}
|
||||
|
||||
fn move_down(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_down(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{}B"), count));
|
||||
}
|
||||
|
||||
fn move_left(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_left(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{}D"), count));
|
||||
}
|
||||
|
||||
fn save_position(&self, screen_manager: &ScreenManager) {
|
||||
fn save_position(&self, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_str(csi!("s"));
|
||||
}
|
||||
|
||||
fn reset_position(&self, screen_manager: &ScreenManager) {
|
||||
fn reset_position(&self, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_str(csi!("u"));
|
||||
}
|
||||
|
||||
fn hide(&self, screen_manager: &ScreenManager) {
|
||||
fn hide(&self, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_str(csi!("?25l"));
|
||||
}
|
||||
|
||||
fn show(&self, screen_manager: &ScreenManager) {
|
||||
fn show(&self, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_str(csi!("?25h"));
|
||||
}
|
||||
|
||||
fn blink(&self, blink: bool, screen_manager: &ScreenManager) {
|
||||
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>) {
|
||||
if blink {
|
||||
screen_manager.write_str(csi!("?12h"));
|
||||
} else {
|
||||
|
@ -8,6 +8,7 @@ use super::*;
|
||||
use std::fmt::Display;
|
||||
use std::io::Write;
|
||||
|
||||
use std::sync::Arc;
|
||||
/// Struct that stores an specific platform implementation for cursor related actions.
|
||||
///
|
||||
/// Check `/examples/version/cursor` in the library for more specific examples.
|
||||
@ -33,14 +34,14 @@ use std::io::Write;
|
||||
/// // or in one line
|
||||
/// cursor.goto(5,5).move_left(2).move_right(2).print("10");
|
||||
/// ```
|
||||
pub struct TerminalCursor<'cursor> {
|
||||
screen_manager: &'cursor ScreenManager,
|
||||
pub struct TerminalCursor {
|
||||
screen: Arc<Stdout>,
|
||||
terminal_cursor: Box<ITerminalCursor>,
|
||||
}
|
||||
|
||||
impl<'cursor> TerminalCursor<'cursor> {
|
||||
impl TerminalCursor {
|
||||
/// Create new cursor instance whereon cursor related actions can be performed.
|
||||
pub fn new(screen_manager: &'cursor ScreenManager) -> TerminalCursor<'cursor> {
|
||||
pub fn new(screen: &Arc<Stdout>) -> TerminalCursor {
|
||||
#[cfg(target_os = "windows")]
|
||||
let cursor =
|
||||
functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new())
|
||||
@ -51,7 +52,7 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
|
||||
TerminalCursor {
|
||||
terminal_cursor: cursor,
|
||||
screen_manager: screen_manager,
|
||||
screen: screen.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,9 +69,8 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
/// cursor.goto(4,5);
|
||||
///
|
||||
/// ```
|
||||
pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor<'cursor> {
|
||||
self.terminal_cursor.goto(x, y, &self.screen_manager);
|
||||
self
|
||||
pub fn goto(&self, x: u16, y: u16) {
|
||||
self.terminal_cursor.goto(x, y, &self.screen);
|
||||
}
|
||||
|
||||
/// Get current cursor position (x,y) in the terminal.
|
||||
@ -87,7 +87,7 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
///
|
||||
/// ```
|
||||
pub fn pos(&self) -> (u16, u16) {
|
||||
self.terminal_cursor.pos(&self.screen_manager)
|
||||
self.terminal_cursor.pos(&self.screen)
|
||||
}
|
||||
|
||||
/// Move the current cursor position `n` times up.
|
||||
@ -102,8 +102,8 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
/// cursor.move_up(3);
|
||||
///
|
||||
/// ```
|
||||
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
|
||||
self.terminal_cursor.move_up(count, &self.screen_manager);
|
||||
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor {
|
||||
self.terminal_cursor.move_up(count, &self.screen);
|
||||
self
|
||||
}
|
||||
|
||||
@ -119,8 +119,8 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
/// cursor.move_right(3);
|
||||
///
|
||||
/// ```
|
||||
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
|
||||
self.terminal_cursor.move_right(count, &self.screen_manager);
|
||||
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor {
|
||||
self.terminal_cursor.move_right(count, &self.screen);
|
||||
self
|
||||
}
|
||||
|
||||
@ -137,8 +137,8 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
/// cursor.move_down(3);
|
||||
///
|
||||
/// ```
|
||||
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
|
||||
self.terminal_cursor.move_down(count, &self.screen_manager);
|
||||
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor {
|
||||
self.terminal_cursor.move_down(count, &self.screen);
|
||||
self
|
||||
}
|
||||
|
||||
@ -155,8 +155,8 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
/// cursor.move_left(3);
|
||||
///
|
||||
/// ```
|
||||
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
|
||||
self.terminal_cursor.move_left(count, &self.screen_manager);
|
||||
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor {
|
||||
self.terminal_cursor.move_left(count, &self.screen);
|
||||
self
|
||||
}
|
||||
|
||||
@ -197,13 +197,13 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
/// .print("@");
|
||||
///
|
||||
/// ```
|
||||
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor<'cursor> {
|
||||
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor {
|
||||
use std::fmt::Write;
|
||||
let mut string = String::new();
|
||||
write!(string, "{}", value).unwrap();
|
||||
|
||||
&self.screen_manager.write_string(string);
|
||||
&self.screen_manager.flush();
|
||||
&self.screen.write_string(string);
|
||||
&self.screen.flush();
|
||||
self
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
///
|
||||
/// ```
|
||||
pub fn save_position(&self) {
|
||||
self.terminal_cursor.save_position(&self.screen_manager);
|
||||
self.terminal_cursor.save_position(&self.screen);
|
||||
}
|
||||
|
||||
/// Return to saved cursor position
|
||||
@ -240,7 +240,7 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
///
|
||||
/// ```
|
||||
pub fn reset_position(&self) {
|
||||
self.terminal_cursor.reset_position(&self.screen_manager);
|
||||
self.terminal_cursor.reset_position(&self.screen);
|
||||
}
|
||||
|
||||
/// Hide de cursor in the console.
|
||||
@ -256,7 +256,7 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
///
|
||||
/// ```
|
||||
pub fn hide(&self) {
|
||||
self.terminal_cursor.hide(&self.screen_manager);
|
||||
self.terminal_cursor.hide(&self.screen);
|
||||
}
|
||||
|
||||
/// Show the cursor in the console.
|
||||
@ -272,7 +272,7 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
///
|
||||
/// ```
|
||||
pub fn show(&self) {
|
||||
self.terminal_cursor.show(&self.screen_manager);
|
||||
self.terminal_cursor.show(&self.screen);
|
||||
}
|
||||
|
||||
/// Enable or disable blinking of the terminal.
|
||||
@ -291,11 +291,11 @@ impl<'cursor> TerminalCursor<'cursor> {
|
||||
///
|
||||
/// ```
|
||||
pub fn blink(&self, blink: bool) {
|
||||
self.terminal_cursor.blink(blink, &self.screen_manager);
|
||||
self.terminal_cursor.blink(blink, &self.screen);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an TerminalCursor implementation whereon cursor related actions can be performed.
|
||||
pub fn cursor(screen_manager: &ScreenManager) -> TerminalCursor {
|
||||
TerminalCursor::new(screen_manager)
|
||||
pub fn cursor(screen_manager: &Screen) -> TerminalCursor {
|
||||
TerminalCursor::new(&screen_manager.stdout)
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ use self::ansi_cursor::AnsiCursor;
|
||||
use self::winapi_cursor::WinApiCursor;
|
||||
|
||||
pub use self::cursor::{cursor, TerminalCursor};
|
||||
use super::{functions, ScreenManager};
|
||||
use super::{functions, Stdout, Screen};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
///! This trait defines the actions that can be preformed with the terminal cursor.
|
||||
///! This trait can be implemented so that an concrete implementation of the ITerminalCursor can forfill
|
||||
@ -24,25 +26,25 @@ use super::{functions, ScreenManager};
|
||||
///! so that cursor related actions can be preformed on both unix and windows systems.
|
||||
pub trait ITerminalCursor {
|
||||
/// Goto some location (x,y) in the context.
|
||||
fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager);
|
||||
fn goto(&self, x: u16, y: u16, screen_manager: &Arc<Stdout>);
|
||||
/// Get the location (x,y) of the current cusror in the context
|
||||
fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16);
|
||||
fn pos(&self, screen_manager: &Arc<Stdout>) -> (u16, u16);
|
||||
/// Move cursor n times up
|
||||
fn move_up(&self, count: u16, screen_manager: &ScreenManager);
|
||||
fn move_up(&self, count: u16, screen_manager: &Arc<Stdout>);
|
||||
/// Move the cursor `n` times to the right.
|
||||
fn move_right(&self, count: u16, screen_manager: &ScreenManager);
|
||||
fn move_right(&self, count: u16, screen_manager: &Arc<Stdout>);
|
||||
/// Move the cursor `n` times down.
|
||||
fn move_down(&self, count: u16, screen_manager: &ScreenManager);
|
||||
fn move_down(&self, count: u16, screen_manager: &Arc<Stdout>);
|
||||
/// Move the cursor `n` times left.
|
||||
fn move_left(&self, count: u16, screen_manager: &ScreenManager);
|
||||
fn move_left(&self, count: u16, screen_manager: &Arc<Stdout>);
|
||||
/// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct.
|
||||
fn save_position(&self, screen_manager: &ScreenManager);
|
||||
fn save_position(&self, screen_manager: &Arc<Stdout>);
|
||||
/// Return to saved cursor position
|
||||
fn reset_position(&self, screen_manager: &ScreenManager);
|
||||
fn reset_position(&self, screen_manager: &Arc<Stdout>);
|
||||
/// Hide the terminal cursor.
|
||||
fn hide(&self, screen_manager: &ScreenManager);
|
||||
fn hide(&self, screen_manager: &Arc<Stdout>);
|
||||
/// Show the terminal cursor
|
||||
fn show(&self, screen_manager: &ScreenManager);
|
||||
fn show(&self, screen_manager: &Arc<Stdout>);
|
||||
/// enable or disable the blinking of the cursor.
|
||||
fn blink(&self, blink: bool, screen_manager: &ScreenManager);
|
||||
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>);
|
||||
}
|
||||
|
@ -2,11 +2,14 @@
|
||||
//! This module is used for windows terminals that do not support ANSI escape codes.
|
||||
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
|
||||
|
||||
use super::super::manager::{ScreenManager, WinApiScreenManager};
|
||||
use super::super::super::write::{Stdout, WinApiStdout};
|
||||
use super::ITerminalCursor;
|
||||
|
||||
use kernel::windows_kernel::{cursor, kernel};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
/// This struct is an windows implementation for cursor related actions.
|
||||
pub struct WinApiCursor;
|
||||
|
||||
@ -17,48 +20,48 @@ impl WinApiCursor {
|
||||
}
|
||||
|
||||
impl ITerminalCursor for WinApiCursor {
|
||||
fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager) {
|
||||
fn goto(&self, x: u16, y: u16, screen_manager: &Arc<Stdout>) {
|
||||
cursor::set_console_cursor_position(x as i16, y as i16, screen_manager);
|
||||
}
|
||||
|
||||
fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
fn pos(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
|
||||
cursor::pos(screen_manager)
|
||||
}
|
||||
|
||||
fn move_up(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_up(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
let (xpos, ypos) = self.pos(screen_manager);
|
||||
self.goto(xpos, ypos - count, screen_manager);
|
||||
}
|
||||
|
||||
fn move_right(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_right(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
let (xpos, ypos) = self.pos(screen_manager);
|
||||
self.goto(xpos + count, ypos, screen_manager);
|
||||
}
|
||||
|
||||
fn move_down(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_down(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
let (xpos, ypos) = self.pos(screen_manager);
|
||||
self.goto(xpos, ypos + count, screen_manager);
|
||||
}
|
||||
|
||||
fn move_left(&self, count: u16, screen_manager: &ScreenManager) {
|
||||
fn move_left(&self, count: u16, screen_manager: &Arc<Stdout>) {
|
||||
let (xpos, ypos) = self.pos(screen_manager);
|
||||
self.goto(xpos - count, ypos, screen_manager);
|
||||
}
|
||||
|
||||
fn save_position(&self, screen_manager: &ScreenManager) {
|
||||
fn save_position(&self, screen_manager: &Arc<Stdout>) {
|
||||
cursor::save_cursor_pos(screen_manager);
|
||||
}
|
||||
|
||||
fn reset_position(&self, screen_manager: &ScreenManager) {
|
||||
fn reset_position(&self, screen_manager: &Arc<Stdout>) {
|
||||
cursor::reset_to_saved_position(screen_manager);
|
||||
}
|
||||
|
||||
fn hide(&self, screen_manager: &ScreenManager) {
|
||||
fn hide(&self, screen_manager: &Arc<Stdout>) {
|
||||
cursor::cursor_visibility(false, screen_manager);
|
||||
}
|
||||
|
||||
fn show(&self, screen_manager: &ScreenManager) {
|
||||
fn show(&self, screen_manager: &Arc<Stdout>) {
|
||||
cursor::cursor_visibility(true, screen_manager);
|
||||
}
|
||||
fn blink(&self, blink: bool, screen_manager: &ScreenManager) {}
|
||||
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>) {}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! Like reading a line, reading a character and reading asynchronously.
|
||||
|
||||
use std::io;
|
||||
|
||||
use std::sync::Arc;
|
||||
use super::*;
|
||||
|
||||
/// Struct that stores an specific platform implementation for input related actions.
|
||||
@ -23,14 +23,14 @@ use super::*;
|
||||
/// let pressed_char = input.read_char();
|
||||
///
|
||||
/// ```
|
||||
pub struct TerminalInput<'terminal> {
|
||||
pub struct TerminalInput {
|
||||
terminal_input: Box<ITerminalInput>,
|
||||
screen_manager: &'terminal ScreenManager,
|
||||
stdout: Arc<Stdout>,
|
||||
}
|
||||
|
||||
impl<'terminal> TerminalInput<'terminal> {
|
||||
impl TerminalInput{
|
||||
/// Create new instance of TerminalInput whereon input related actions could be preformed.
|
||||
pub fn new(screen_manager: &'terminal ScreenManager) -> TerminalInput<'terminal> {
|
||||
pub fn new(stdout: &Arc<Stdout>) -> TerminalInput {
|
||||
#[cfg(target_os = "windows")]
|
||||
let input = Box::from(WindowsInput::new());
|
||||
|
||||
@ -39,7 +39,7 @@ impl<'terminal> TerminalInput<'terminal> {
|
||||
|
||||
TerminalInput {
|
||||
terminal_input: input,
|
||||
screen_manager: screen_manager,
|
||||
stdout: stdout.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ impl<'terminal> TerminalInput<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn read_line(&self) -> io::Result<String> {
|
||||
self.terminal_input.read_line(&self.screen_manager)
|
||||
self.terminal_input.read_line(&self.stdout)
|
||||
}
|
||||
|
||||
/// Read one character from the user input
|
||||
@ -72,7 +72,7 @@ impl<'terminal> TerminalInput<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn read_char(&self) -> io::Result<char> {
|
||||
return self.terminal_input.read_char(&self.screen_manager);
|
||||
return self.terminal_input.read_char(&self.stdout);
|
||||
}
|
||||
|
||||
/// Read the input asynchronously from the user.
|
||||
@ -104,7 +104,7 @@ impl<'terminal> TerminalInput<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn read_async(&self) -> AsyncReader {
|
||||
self.terminal_input.read_async(&self.screen_manager)
|
||||
self.terminal_input.read_async(&self.stdout)
|
||||
}
|
||||
|
||||
/// Read the input asynchronously until a certain character is hit.
|
||||
@ -144,11 +144,11 @@ impl<'terminal> TerminalInput<'terminal> {
|
||||
/// ```
|
||||
pub fn read_until_async(&self, delimiter: u8) -> AsyncReader {
|
||||
self.terminal_input
|
||||
.read_until_async(delimiter, &self.screen_manager)
|
||||
.read_until_async(delimiter, &self.stdout)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an Terminal Input implementation whereon input related actions can be performed.
|
||||
pub fn input(screen_manager: &ScreenManager) -> TerminalInput {
|
||||
return TerminalInput::new(screen_manager);
|
||||
pub fn input(stdout: &Screen) -> TerminalInput {
|
||||
return TerminalInput::new(&stdout.stdout);
|
||||
}
|
||||
|
@ -14,10 +14,11 @@ use self::unix_input::UnixInput;
|
||||
use self::windows_input::WindowsInput;
|
||||
|
||||
pub use self::input::{input, TerminalInput};
|
||||
use super::ScreenManager;
|
||||
use super::Stdout;
|
||||
|
||||
use std::io::{self, Read};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use Screen;
|
||||
|
||||
/// This trait defines the actions that can be preformed with the terminal color.
|
||||
/// This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
|
||||
@ -29,13 +30,13 @@ use std::sync::mpsc;
|
||||
/// Unix is using the tty and windows is using libc C functions to read the input.
|
||||
trait ITerminalInput {
|
||||
/// Read one line from the user input
|
||||
fn read_line(&self, screen_manger: &ScreenManager) -> io::Result<String>;
|
||||
fn read_line(&self, screen_manger: &Arc<Stdout>) -> io::Result<String>;
|
||||
/// Read one character from the user input
|
||||
fn read_char(&self, screen_manger: &ScreenManager) -> io::Result<char>;
|
||||
fn read_char(&self, screen_manger: &Arc<Stdout>) -> io::Result<char>;
|
||||
/// Read the input asynchronously from the user.
|
||||
fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader;
|
||||
fn read_async(&self, screen_manger: &Arc<Stdout>) -> AsyncReader;
|
||||
/// Read the input asynchronously until a certain character is hit.
|
||||
fn read_until_async(&self, delimiter: u8, screen_manger: &ScreenManager) -> AsyncReader;
|
||||
fn read_until_async(&self, delimiter: u8, screen_manger: &Arc<Stdout>) -> AsyncReader;
|
||||
}
|
||||
|
||||
/// This is a wrapper for reading from the input asynchronously.
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
use std::char;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::thread;
|
||||
|
||||
use super::{AsyncReader, ITerminalInput, ScreenManager};
|
||||
use super::{AsyncReader, ITerminalInput, Stdout};
|
||||
use kernel::unix_kernel::terminal::{get_tty, read_char};
|
||||
|
||||
pub struct UnixInput;
|
||||
@ -17,7 +17,7 @@ impl UnixInput {
|
||||
}
|
||||
|
||||
impl ITerminalInput for UnixInput {
|
||||
fn read_line(&self, screen_manger: &ScreenManager) -> io::Result<String> {
|
||||
fn read_line(&self, screen_manger: &Stdout) -> io::Result<String> {
|
||||
let mut rv = String::new();
|
||||
io::stdin().read_line(&mut rv)?;
|
||||
let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
|
||||
@ -25,11 +25,11 @@ impl ITerminalInput for UnixInput {
|
||||
Ok(rv)
|
||||
}
|
||||
|
||||
fn read_char(&self, screen_manger: &ScreenManager) -> io::Result<char> {
|
||||
fn read_char(&self, screen_manger: &Arc<Stdout>) -> io::Result<char> {
|
||||
read_char()
|
||||
}
|
||||
|
||||
fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader {
|
||||
fn read_async(&self, screen_manger: &Arc<Stdout>) -> AsyncReader {
|
||||
let (send, recv) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
@ -43,7 +43,7 @@ impl ITerminalInput for UnixInput {
|
||||
AsyncReader { recv: recv }
|
||||
}
|
||||
|
||||
fn read_until_async(&self, delimiter: u8, screen_manger: &ScreenManager) -> AsyncReader {
|
||||
fn read_until_async(&self, delimiter: u8, screen_manger: &Arc<Stdout>) -> AsyncReader {
|
||||
let (send, recv) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
use std::char;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use std::thread;
|
||||
|
||||
use super::{AsyncReader, ITerminalInput, ScreenManager};
|
||||
use super::{AsyncReader, ITerminalInput, Stdout};
|
||||
|
||||
use winapi::um::winnt::INT;
|
||||
use winapi::um::winuser;
|
||||
@ -19,11 +19,11 @@ impl WindowsInput {
|
||||
}
|
||||
|
||||
impl ITerminalInput for WindowsInput {
|
||||
fn read_line(&self, screen_manger: &ScreenManager) -> io::Result<String> {
|
||||
fn read_line(&self, screen_manger: &Arc<Stdout>) -> io::Result<String> {
|
||||
let mut chars: Vec<char> = Vec::new();
|
||||
|
||||
loop {
|
||||
let is_raw_screen = screen_manger.is_raw_screen();
|
||||
let is_raw_screen = screen_manger.is_in_raw_mode;
|
||||
|
||||
// _getwch is without echo and _getwche is with echo
|
||||
let pressed_char = unsafe {
|
||||
@ -52,8 +52,8 @@ impl ITerminalInput for WindowsInput {
|
||||
return Ok(chars.into_iter().collect());
|
||||
}
|
||||
|
||||
fn read_char(&self, screen_manger: &ScreenManager) -> io::Result<char> {
|
||||
let is_raw_screen = screen_manger.is_raw_screen();
|
||||
fn read_char(&self, screen_manger: &Arc<Stdout>) -> io::Result<char> {
|
||||
let is_raw_screen = screen_manger.is_in_raw_mode;
|
||||
|
||||
// _getwch is without echo and _getwche is with echo
|
||||
let pressed_char = unsafe {
|
||||
@ -83,10 +83,10 @@ impl ITerminalInput for WindowsInput {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader {
|
||||
fn read_async(&self, screen_manger: &Arc<Stdout>) -> AsyncReader {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let is_raw_screen = screen_manger.is_raw_screen();
|
||||
let is_raw_screen = screen_manger.is_in_raw_mode;
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
@ -115,10 +115,10 @@ impl ITerminalInput for WindowsInput {
|
||||
AsyncReader { recv: rx }
|
||||
}
|
||||
|
||||
fn read_until_async(&self, delimiter: u8, screen_manger: &ScreenManager) -> AsyncReader {
|
||||
fn read_until_async(&self, delimiter: u8, screen_manger: &Arc<Stdout>) -> AsyncReader {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let is_raw_screen = screen_manger.is_raw_screen();
|
||||
let is_raw_screen = screen_manger.is_in_raw_mode;
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
|
@ -1,78 +0,0 @@
|
||||
//! This is an ANSI specific implementation for the screen manager
|
||||
//! This module is used for windows 10 terminals and unix terminals by default.
|
||||
//! This module uses the stdout to write to the console.
|
||||
|
||||
use super::IScreenManager;
|
||||
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::{Arc,Mutex};
|
||||
use std::io::{self, Read, Write,Stdout};
|
||||
use std::str::from_utf8;
|
||||
|
||||
/// This struct is an ANSI escape code implementation for screen related actions.
|
||||
pub struct AnsiScreenManager {
|
||||
is_alternate_screen: bool,
|
||||
is_raw_screen: bool,
|
||||
output: Box<Stdout>,
|
||||
}
|
||||
|
||||
impl IScreenManager for AnsiScreenManager {
|
||||
fn set_is_raw_screen(&mut self, value: bool) {
|
||||
self.is_raw_screen = value;
|
||||
}
|
||||
|
||||
fn set_is_alternate_screen(&mut self, value: bool) {
|
||||
self.is_alternate_screen = value;
|
||||
}
|
||||
|
||||
fn is_raw_screen(&self) -> bool {
|
||||
self.is_raw_screen
|
||||
}
|
||||
|
||||
fn is_alternate_screen(&self) -> bool {
|
||||
self.is_alternate_screen
|
||||
}
|
||||
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
let out = &self.output;
|
||||
let mut handle = out.lock();
|
||||
write!(handle, "{}", string)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
{
|
||||
let out = &self.output;
|
||||
let mut handle = out.lock();
|
||||
handle.write(buf)?;
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn flush(&self) -> io::Result<()> {
|
||||
let out = &self.output;
|
||||
let mut handle = out.lock();
|
||||
handle.flush();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AnsiScreenManager {
|
||||
pub fn new() -> Self {
|
||||
AnsiScreenManager {
|
||||
output: Box::from(io::stdout()),
|
||||
is_alternate_screen: false,
|
||||
is_raw_screen: false,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
use super::IScreenManager;
|
||||
use kernel::windows_kernel::{handle, kernel, writing};
|
||||
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use std::ptr::NonNull;
|
||||
use std::any::Any;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// This struct is an WINAPI implementation for screen related actions.
|
||||
pub struct WinApiScreenManager {
|
||||
is_alternate_screen: bool,
|
||||
is_raw_screen: bool,
|
||||
output: HANDLE,
|
||||
alternate_handle: HANDLE,
|
||||
}
|
||||
|
||||
impl IScreenManager for WinApiScreenManager {
|
||||
fn set_is_raw_screen(&mut self, value: bool) {
|
||||
self.is_raw_screen = value;
|
||||
}
|
||||
fn set_is_alternate_screen(&mut self, value: bool) {
|
||||
self.is_alternate_screen = value;
|
||||
}
|
||||
|
||||
fn is_raw_screen(&self) -> bool {
|
||||
self.is_raw_screen
|
||||
}
|
||||
|
||||
fn is_alternate_screen(&self) -> bool {
|
||||
self.is_alternate_screen
|
||||
}
|
||||
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
self.write(string.as_bytes())
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
if self.is_alternate_screen {
|
||||
writing::write_char_buffer(&self.alternate_handle, buf)
|
||||
} else {
|
||||
writing::write_char_buffer(&self.output, buf)
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// for winapi we have some custom implementation that will be used by windows only. You can get a reference to this implementation by using the `as_any()` and that cast it to this struct.
|
||||
impl WinApiScreenManager {
|
||||
/// Create a new instance.
|
||||
pub fn new() -> Self {
|
||||
|
||||
WinApiScreenManager {
|
||||
output: handle::get_output_handle().unwrap(),
|
||||
alternate_handle: handle::get_output_handle().unwrap(),
|
||||
is_alternate_screen: false,
|
||||
is_raw_screen: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the alternate handle to the given handle.
|
||||
pub fn set_alternate_handle(&mut self, alternate_handle: HANDLE) {
|
||||
self.alternate_handle = alternate_handle;
|
||||
// needs to be turned on so that escape characters like \n and \t will be processed.
|
||||
kernel::set_console_mode(&self.alternate_handle, ENABLE_PROCESSED_OUTPUT as u32);
|
||||
}
|
||||
|
||||
/// get the current screen handle.
|
||||
pub fn get_handle(&self) -> &HANDLE {
|
||||
if self.is_alternate_screen {
|
||||
return &self.alternate_handle;
|
||||
} else {
|
||||
return &self.output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for WinApiScreenManager {}
|
@ -1,10 +1,12 @@
|
||||
pub mod cursor;
|
||||
pub mod input;
|
||||
pub mod manager;
|
||||
pub mod write;
|
||||
pub mod style;
|
||||
pub mod terminal;
|
||||
//pub mod handle;
|
||||
pub mod terminal;
|
||||
|
||||
use super::common::commands;
|
||||
use super::common::functions;
|
||||
use super::common::traits;
|
||||
pub use super::manager::ScreenManager;
|
||||
pub use self::write::{Stdout, IStdout};
|
||||
pub use super::common::Screen;
|
@ -1,7 +1,7 @@
|
||||
//! This is an ANSI specific implementation for styling related action.
|
||||
//! This module is used for windows 10 terminals and unix terminals by default.
|
||||
|
||||
use super::{Color, ColorType, ITerminalColor, ScreenManager};
|
||||
use std::sync::Arc;
|
||||
use super::{Color, ColorType, ITerminalColor, Stdout};
|
||||
|
||||
/// This struct is an ANSI escape code implementation for color related actions.
|
||||
pub struct AnsiColor;
|
||||
@ -13,22 +13,22 @@ impl AnsiColor {
|
||||
}
|
||||
|
||||
impl ITerminalColor for AnsiColor {
|
||||
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager) {
|
||||
screen_manager.write_string(format!(
|
||||
fn set_fg(&self, fg_color: Color, stdout: &Arc<Stdout>) {
|
||||
stdout.write_string(format!(
|
||||
csi!("{}m"),
|
||||
self.color_value(fg_color, ColorType::Foreground)
|
||||
));
|
||||
}
|
||||
|
||||
fn set_bg(&self, bg_color: Color, screen_manager: &ScreenManager) {
|
||||
screen_manager.write_string(format!(
|
||||
fn set_bg(&self, bg_color: Color, stdout: &Arc<Stdout>) {
|
||||
stdout.write_string(format!(
|
||||
csi!("{}m"),
|
||||
self.color_value(bg_color, ColorType::Background)
|
||||
));
|
||||
}
|
||||
|
||||
fn reset(&self, screen_manager: &ScreenManager) {
|
||||
screen_manager.write_str(csi!("0m"));
|
||||
fn reset(&self, stdout: &Arc<Stdout>) {
|
||||
stdout.write_str(csi!("0m"));
|
||||
}
|
||||
|
||||
fn color_value(&self, color: Color, color_type: ColorType) -> String {
|
||||
|
@ -23,14 +23,14 @@ use std::io;
|
||||
/// colored_terminal.reset();
|
||||
///
|
||||
/// ```
|
||||
pub struct TerminalColor<'terminal> {
|
||||
pub struct TerminalColor {
|
||||
color: Box<ITerminalColor>,
|
||||
screen_manager: &'terminal ScreenManager,
|
||||
stdout: Arc<Stdout>,
|
||||
}
|
||||
|
||||
impl<'terminal> TerminalColor<'terminal> {
|
||||
impl<'terminal> TerminalColor {
|
||||
/// Create new instance whereon color related actions can be performed.
|
||||
pub fn new(screen_manager: &'terminal ScreenManager) -> TerminalColor<'terminal> {
|
||||
pub fn new(stdout: &Arc<Stdout>) -> TerminalColor {
|
||||
#[cfg(target_os = "windows")]
|
||||
let color = functions::get_module::<Box<ITerminalColor>>(
|
||||
Box::from(WinApiColor::new()),
|
||||
@ -42,7 +42,7 @@ impl<'terminal> TerminalColor<'terminal> {
|
||||
|
||||
TerminalColor {
|
||||
color,
|
||||
screen_manager,
|
||||
stdout: stdout.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ impl<'terminal> TerminalColor<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn set_fg(&self, color: Color) {
|
||||
self.color.set_fg(color, &self.screen_manager);
|
||||
self.color.set_fg(color, &self.stdout);
|
||||
}
|
||||
|
||||
/// Set the background color to the given color.
|
||||
@ -80,7 +80,7 @@ impl<'terminal> TerminalColor<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn set_bg(&self, color: Color) {
|
||||
self.color.set_bg(color, &self.screen_manager);
|
||||
self.color.set_bg(color, &self.stdout);
|
||||
}
|
||||
|
||||
/// Reset the terminal colors and attributes to default.
|
||||
@ -95,7 +95,7 @@ impl<'terminal> TerminalColor<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn reset(&self) {
|
||||
self.color.reset(&self.screen_manager);
|
||||
self.color.reset(&self.stdout);
|
||||
}
|
||||
|
||||
/// Get available color count.
|
||||
@ -116,6 +116,6 @@ impl<'terminal> TerminalColor<'terminal> {
|
||||
}
|
||||
|
||||
/// Get an Terminal Color implementation whereon color related actions can be performed.
|
||||
pub fn color(screen_manager: &ScreenManager) -> TerminalColor {
|
||||
TerminalColor::new(screen_manager)
|
||||
pub fn color(stdout: &Arc<Stdout>) -> TerminalColor {
|
||||
TerminalColor::new(stdout)
|
||||
}
|
||||
|
@ -14,11 +14,12 @@ use self::winapi_color::WinApiColor;
|
||||
|
||||
use std::convert::From;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use self::color::TerminalColor;
|
||||
pub use self::objectstyle::ObjectStyle;
|
||||
pub use self::styledobject::StyledObject;
|
||||
use super::{functions, ScreenManager};
|
||||
use super::{functions, Stdout};
|
||||
|
||||
/// This trait defines the actions that can be preformed with the terminal color.
|
||||
/// This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
|
||||
@ -30,11 +31,11 @@ use super::{functions, ScreenManager};
|
||||
/// so that color related actions can be preformed on both unix and windows systems.
|
||||
pub trait ITerminalColor {
|
||||
/// Set the foreground color to the given color.
|
||||
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager);
|
||||
fn set_fg(&self, fg_color: Color, stdout: &Arc<Stdout>);
|
||||
/// Set the background color to the given color.
|
||||
fn set_bg(&self, fg_color: Color, screen_manager: &ScreenManager);
|
||||
fn set_bg(&self, fg_color: Color, stdout: &Arc<Stdout>);
|
||||
/// Reset the terminal color to default.
|
||||
fn reset(&self, screen_manager: &ScreenManager);
|
||||
fn reset(&self, stdout: &Arc<Stdout>);
|
||||
/// Gets an value that represents an color from the given `Color` and `ColorType`.
|
||||
fn color_value(&self, color: Color, color_type: ColorType) -> String;
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! This module contains the `object style` that can be applied to an `styled object`.
|
||||
|
||||
use super::{Color, ScreenManager, StyledObject};
|
||||
use super::{Color, Stdout, StyledObject};
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::Attribute;
|
||||
@ -30,14 +31,12 @@ impl Default for ObjectStyle {
|
||||
|
||||
impl ObjectStyle {
|
||||
/// Apply an `StyledObject` to the passed displayable object.
|
||||
pub fn apply_to<'style, D: Display>(
|
||||
pub fn apply_to<D: Display>(
|
||||
&self,
|
||||
val: D,
|
||||
screen_manager: &'style ScreenManager,
|
||||
) -> StyledObject<'style, D> {
|
||||
) -> StyledObject<D> {
|
||||
StyledObject {
|
||||
object_style: self.clone(),
|
||||
screen_manager: screen_manager,
|
||||
content: val,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! This module contains the logic to style an object that contains some state witch can be styled.
|
||||
|
||||
use super::{Color, ObjectStyle, ScreenManager};
|
||||
use super::{Color, ObjectStyle, Stdout};
|
||||
use Screen;
|
||||
|
||||
use std::fmt::{self, Display};
|
||||
use std::io::Write;
|
||||
@ -9,16 +10,15 @@ use std::io::Write;
|
||||
use super::Attribute;
|
||||
|
||||
#[cfg(windows)]
|
||||
use super::super::super::manager::WinApiScreenManager;
|
||||
use super::super::super::write::WinApiStdout;
|
||||
|
||||
/// Struct that contains both the style and the content wits can be styled.
|
||||
pub struct StyledObject<'terminal, D: Display> {
|
||||
pub struct StyledObject<D: Display> {
|
||||
pub object_style: ObjectStyle,
|
||||
pub content: D,
|
||||
pub screen_manager: &'terminal ScreenManager,
|
||||
}
|
||||
|
||||
impl<'terminal, D: Display> StyledObject<'terminal, D> {
|
||||
impl<D: Display> StyledObject<D> {
|
||||
/// Set the foreground of the styled object to the passed `Color`
|
||||
///
|
||||
/// #Example
|
||||
@ -39,7 +39,7 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
|
||||
/// println!("{}", paint("I am colored green").with(Color::Green));
|
||||
///
|
||||
/// ```
|
||||
pub fn with(mut self, foreground_color: Color) -> StyledObject<'terminal, D> {
|
||||
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
|
||||
self.object_style = self.object_style.fg(foreground_color);
|
||||
self
|
||||
}
|
||||
@ -64,7 +64,7 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
|
||||
/// println!("{}", paint("I am colored green").on(Color::Green))
|
||||
///
|
||||
/// ```
|
||||
pub fn on(mut self, background_color: Color) -> StyledObject<'terminal, D> {
|
||||
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
|
||||
self.object_style = self.object_style.bg(background_color);
|
||||
self
|
||||
}
|
||||
@ -82,7 +82,7 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
|
||||
///
|
||||
/// ```
|
||||
#[cfg(unix)]
|
||||
pub fn attr(mut self, attr: Attribute) -> StyledObject<'terminal, D> {
|
||||
pub fn attr(mut self, attr: Attribute) -> StyledObject<D> {
|
||||
&self.object_style.add_attr(attr);
|
||||
self
|
||||
}
|
||||
@ -90,62 +90,61 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
|
||||
/// Increase the font intensity.
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn bold(self) -> StyledObject<'terminal, D> {
|
||||
pub fn bold(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::Bold)
|
||||
}
|
||||
/// Faint (decreased intensity) (Not widely supported).
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn dim(self) -> StyledObject<'terminal, D> {
|
||||
pub fn dim(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::Dim)
|
||||
}
|
||||
/// Make the font italic (Not widely supported; Sometimes treated as inverse).
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn italic(self) -> StyledObject<'terminal, D> {
|
||||
pub fn italic(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::Italic)
|
||||
}
|
||||
/// Underline font.
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn underlined(self) -> StyledObject<'terminal, D> {
|
||||
pub fn underlined(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::Underlined)
|
||||
}
|
||||
/// Slow Blink (less than 150 per minute; not widely supported).
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn slow_blink(self) -> StyledObject<'terminal, D> {
|
||||
pub fn slow_blink(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::SlowBlink)
|
||||
}
|
||||
/// Rapid Blink (MS-DOS ANSI.SYS; 150+ per minute; not widely supported).
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn rapid_blink(self) -> StyledObject<'terminal, D> {
|
||||
pub fn rapid_blink(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::RapidBlink)
|
||||
}
|
||||
/// Swap foreground and background colors.
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn reverse(self) -> StyledObject<'terminal, D> {
|
||||
pub fn reverse(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::Reverse)
|
||||
}
|
||||
/// Hide text (Not widely supported).
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn hidden(self) -> StyledObject<'terminal, D> {
|
||||
pub fn hidden(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::Hidden)
|
||||
}
|
||||
/// Characters legible, but marked for deletion. Not widely supported.
|
||||
#[cfg(unix)]
|
||||
#[inline(always)]
|
||||
pub fn crossed_out(self) -> StyledObject<'terminal, D> {
|
||||
pub fn crossed_out(self) -> StyledObject<D> {
|
||||
self.attr(Attribute::CrossedOut)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'terminal, D: Display> Display for StyledObject<'terminal, D> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
let mut colored_terminal = super::super::super::style::color::color(self.screen_manager);
|
||||
pub fn paint(&self, screen: &Screen)
|
||||
{
|
||||
let mut colored_terminal = super::super::super::style::color::color(&screen.stdout);
|
||||
let mut reset = true;
|
||||
|
||||
if let Some(bg) = self.object_style.bg_color {
|
||||
@ -159,22 +158,20 @@ impl<'terminal, D: Display> Display for StyledObject<'terminal, D> {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
for attr in self.object_style.attrs.iter() {
|
||||
self.screen_manager
|
||||
for attr in self.object_style.attrs.iter() {
|
||||
self.stdout
|
||||
.write_string(format!(csi!("{}m"), *attr as i16));
|
||||
reset = true;
|
||||
}
|
||||
|
||||
use std::fmt::Write;
|
||||
let mut string = String::new();
|
||||
write!(string, "{}", self.content).unwrap();
|
||||
self.screen_manager.write_string(string);
|
||||
self.screen_manager.flush();
|
||||
let mut content = String::new();
|
||||
write!(content, "{}", self.content).unwrap();
|
||||
screen.stdout.write_string(content);
|
||||
screen.stdout.flush();
|
||||
|
||||
if reset {
|
||||
colored_terminal.reset();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@
|
||||
//!
|
||||
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
|
||||
|
||||
use super::super::super::manager::WinApiScreenManager;
|
||||
use super::{Color, ColorType, ITerminalColor, ScreenManager};
|
||||
use super::super::super::write::WinApiStdout;
|
||||
use super::{Color, ColorType, ITerminalColor, Stdout};
|
||||
use kernel::windows_kernel::{csbi, kernel};
|
||||
use winapi::um::wincon;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
/// This struct is an windows implementation for color related actions.
|
||||
pub struct WinApiColor;
|
||||
|
||||
@ -18,10 +20,10 @@ impl WinApiColor {
|
||||
}
|
||||
|
||||
impl ITerminalColor for WinApiColor {
|
||||
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager) {
|
||||
fn set_fg(&self, fg_color: Color, stdout: &Arc<Stdout>) {
|
||||
let color_value = &self.color_value(fg_color, ColorType::Foreground);
|
||||
|
||||
let csbi = csbi::get_csbi(screen_manager).unwrap();
|
||||
let csbi = csbi::get_csbi(stdout).unwrap();
|
||||
|
||||
// Notice that the color values are stored in wAttribute.
|
||||
// So we need to use bitwise operators to check if the values exists or to get current console colors.
|
||||
@ -36,13 +38,13 @@ impl ITerminalColor for WinApiColor {
|
||||
color = color | wincon::BACKGROUND_INTENSITY as u16;
|
||||
}
|
||||
|
||||
kernel::set_console_text_attribute(color, screen_manager);
|
||||
kernel::set_console_text_attribute(color, stdout);
|
||||
}
|
||||
|
||||
fn set_bg(&self, bg_color: Color, screen_manager: &ScreenManager) {
|
||||
fn set_bg(&self, bg_color: Color, stdout: &Arc<Stdout>) {
|
||||
let color_value = &self.color_value(bg_color, ColorType::Background);
|
||||
|
||||
let (csbi, handle) = csbi::get_csbi_and_handle(screen_manager).unwrap();
|
||||
let (csbi, handle) = csbi::get_csbi_and_handle(stdout).unwrap();
|
||||
|
||||
// Notice that the color values are stored in wAttribute.
|
||||
// So wee need to use bitwise operators to check if the values exists or to get current console colors.
|
||||
@ -57,12 +59,12 @@ impl ITerminalColor for WinApiColor {
|
||||
color = color | wincon::FOREGROUND_INTENSITY as u16;
|
||||
}
|
||||
|
||||
kernel::set_console_text_attribute(color, screen_manager);
|
||||
kernel::set_console_text_attribute(color, stdout);
|
||||
}
|
||||
|
||||
fn reset(&self, screen_manager: &ScreenManager) {
|
||||
self.set_bg(Color::Black, screen_manager);
|
||||
self.set_fg(Color::White, screen_manager);
|
||||
fn reset(&self, stdout: &Arc<Stdout>) {
|
||||
self.set_bg(Color::Black, stdout);
|
||||
self.set_fg(Color::White, stdout);
|
||||
}
|
||||
|
||||
/// This will get the winapi color value from the Color and ColorType struct
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! This module is used for windows 10 terminals and unix terminals by default.
|
||||
|
||||
use super::super::cursor::cursor;
|
||||
use super::{functions, ClearType, ITerminal, ScreenManager};
|
||||
use super::*;
|
||||
|
||||
/// This struct is an ansi escape code implementation for terminal related actions.
|
||||
pub struct AnsiTerminal;
|
||||
@ -14,7 +14,7 @@ impl AnsiTerminal {
|
||||
}
|
||||
|
||||
impl ITerminal for AnsiTerminal {
|
||||
fn clear(&self, clear_type: ClearType, screen_manager: &ScreenManager) {
|
||||
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>) {
|
||||
match clear_type {
|
||||
ClearType::All => {
|
||||
screen_manager.write_str(csi!("2J"));
|
||||
@ -34,19 +34,19 @@ impl ITerminal for AnsiTerminal {
|
||||
};
|
||||
}
|
||||
|
||||
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
|
||||
functions::get_terminal_size()
|
||||
}
|
||||
|
||||
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) {
|
||||
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{}S"), count));
|
||||
}
|
||||
|
||||
fn scroll_down(&self, count: i16, screen_manager: &ScreenManager) {
|
||||
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("{}T"), count));
|
||||
}
|
||||
|
||||
fn set_size(&self, width: i16, height: i16, screen_manager: &ScreenManager) {
|
||||
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>) {
|
||||
screen_manager.write_string(format!(csi!("8;{};{}t"), width, height));
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,10 @@ use self::ansi_terminal::AnsiTerminal;
|
||||
#[cfg(target_os = "windows")]
|
||||
use self::winapi_terminal::WinApiTerminal;
|
||||
|
||||
pub use self::terminal::Terminal;
|
||||
use super::{functions, ScreenManager};
|
||||
pub use self::terminal::{terminal, Terminal};
|
||||
use super::{functions, Stdout};
|
||||
use std::sync::Arc;
|
||||
use Screen;
|
||||
|
||||
/// Enum that specifies a way of clearing.
|
||||
pub enum ClearType {
|
||||
@ -32,15 +34,15 @@ pub enum ClearType {
|
||||
/// so that color related actions can be preformed on both unix and windows systems.
|
||||
pub trait ITerminal {
|
||||
/// Clear the current cursor by specifying the clear type
|
||||
fn clear(&self, clear_type: ClearType, screen_manager: &ScreenManager);
|
||||
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>);
|
||||
/// Get the terminal size (x,y)
|
||||
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16);
|
||||
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16);
|
||||
/// Scroll `n` lines up in the current terminal.
|
||||
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager);
|
||||
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>);
|
||||
/// Scroll `n` lines down in the current terminal.
|
||||
fn scroll_down(&self, count: i16, screen_manager: &ScreenManager);
|
||||
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>);
|
||||
/// Resize terminal to the given width and height.
|
||||
fn set_size(&self, width: i16, height: i16, screen_manager: &ScreenManager);
|
||||
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>);
|
||||
/// Close the current terminal
|
||||
fn exit(&self);
|
||||
}
|
||||
|
@ -22,14 +22,14 @@ use std::io::Write;
|
||||
/// let (with, height) = term.terminal_size();
|
||||
///
|
||||
/// ```
|
||||
pub struct Terminal<'terminal> {
|
||||
pub struct Terminal {
|
||||
terminal: Box<ITerminal>,
|
||||
screen_manager: &'terminal ScreenManager,
|
||||
screen: Arc<Stdout>,
|
||||
}
|
||||
|
||||
impl<'terminal> Terminal<'terminal> {
|
||||
impl Terminal {
|
||||
/// Create new terminal instance whereon terminal related actions can be performed.
|
||||
pub fn new(screen_manager: &'terminal ScreenManager) -> Terminal<'terminal> {
|
||||
pub fn new(screen: &Arc<Stdout>) -> Terminal {
|
||||
#[cfg(target_os = "windows")]
|
||||
let terminal = functions::get_module::<Box<ITerminal>>(
|
||||
Box::new(WinApiTerminal::new()),
|
||||
@ -41,7 +41,7 @@ impl<'terminal> Terminal<'terminal> {
|
||||
|
||||
Terminal {
|
||||
terminal,
|
||||
screen_manager: screen_manager,
|
||||
screen: screen.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,8 +66,8 @@ impl<'terminal> Terminal<'terminal> {
|
||||
/// term.clear(terminal::ClearType::UntilNewLine);
|
||||
///
|
||||
/// ```
|
||||
pub fn clear(&mut self, clear_type: ClearType) {
|
||||
self.terminal.clear(clear_type, &mut self.screen_manager);
|
||||
pub fn clear(&self, clear_type: ClearType) {
|
||||
self.terminal.clear(clear_type, &self.screen);
|
||||
}
|
||||
|
||||
/// Get the terminal size (x,y).
|
||||
@ -88,7 +88,7 @@ impl<'terminal> Terminal<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn terminal_size(&self) -> (u16, u16) {
|
||||
return self.terminal.terminal_size(&self.screen_manager);
|
||||
return self.terminal.terminal_size(&self.screen);
|
||||
}
|
||||
|
||||
/// Scroll `n` lines up in the current terminal.
|
||||
@ -105,7 +105,7 @@ impl<'terminal> Terminal<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn scroll_up(&self, count: i16) {
|
||||
self.terminal.scroll_up(count, &self.screen_manager);
|
||||
self.terminal.scroll_up(count, &self.screen);
|
||||
}
|
||||
|
||||
/// Scroll `n` lines up in the current terminal.
|
||||
@ -122,7 +122,7 @@ impl<'terminal> Terminal<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn scroll_down(&self, count: i16) {
|
||||
self.terminal.scroll_down(count, &self.screen_manager);
|
||||
self.terminal.scroll_down(count, &self.screen);
|
||||
}
|
||||
|
||||
/// Set the terminal size. Note that not all terminals can be set to a very small scale.
|
||||
@ -139,7 +139,7 @@ impl<'terminal> Terminal<'terminal> {
|
||||
///
|
||||
/// ```
|
||||
pub fn set_size(&self, width: i16, height: i16) {
|
||||
self.terminal.set_size(width, height, &self.screen_manager);
|
||||
self.terminal.set_size(width, height, &self.screen);
|
||||
}
|
||||
|
||||
/// Exit the current process.
|
||||
@ -174,11 +174,11 @@ impl<'terminal> Terminal<'terminal> {
|
||||
use std::fmt::Write;
|
||||
let mut string = String::new();
|
||||
write!(string, "{}", value).unwrap();
|
||||
self.screen_manager.write_string(string);
|
||||
self.screen.write_string(string);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an terminal implementation whereon terminal related actions could performed
|
||||
pub fn terminal(screen_manager: &mut ScreenManager) -> Terminal {
|
||||
Terminal::new(screen_manager)
|
||||
pub fn terminal(screen: &Screen) -> Terminal {
|
||||
Terminal::new(&screen.stdout)
|
||||
}
|
||||
|
@ -3,8 +3,8 @@
|
||||
//!
|
||||
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
|
||||
|
||||
use super::super::super::cursor::cursor;
|
||||
use super::{functions, ClearType, ITerminal, ScreenManager};
|
||||
use super::super::super::cursor::TerminalCursor;
|
||||
use super::*;
|
||||
use kernel::windows_kernel::{csbi, kernel, terminal, writing};
|
||||
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
||||
|
||||
@ -18,9 +18,9 @@ impl WinApiTerminal {
|
||||
}
|
||||
|
||||
impl ITerminal for WinApiTerminal {
|
||||
fn clear(&self, clear_type: ClearType, screen_manager: &ScreenManager) {
|
||||
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>) {
|
||||
let csbi = csbi::get_csbi(screen_manager).unwrap();
|
||||
let pos = cursor(screen_manager).pos();
|
||||
let pos = TerminalCursor::new(screen_manager).pos();
|
||||
|
||||
match clear_type {
|
||||
ClearType::All => {
|
||||
@ -33,11 +33,11 @@ impl ITerminal for WinApiTerminal {
|
||||
};
|
||||
}
|
||||
|
||||
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16) {
|
||||
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
|
||||
terminal::terminal_size()
|
||||
}
|
||||
|
||||
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) {
|
||||
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>) {
|
||||
let csbi = csbi::get_csbi(&screen_manager).unwrap();
|
||||
|
||||
// Set srctWindow to the current window size and location.
|
||||
@ -55,7 +55,7 @@ impl ITerminal for WinApiTerminal {
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_down(&self, count: i16, screen_manager: &ScreenManager) {
|
||||
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>) {
|
||||
let csbi = csbi::get_csbi(&screen_manager).unwrap();
|
||||
// Set srctWindow to the current window size and location.
|
||||
let mut srct_window = csbi.srWindow;
|
||||
@ -76,7 +76,7 @@ impl ITerminal for WinApiTerminal {
|
||||
}
|
||||
|
||||
/// Set the current terminal size
|
||||
fn set_size(&self, width: i16, height: i16, screen_manager: &ScreenManager) {
|
||||
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>) {
|
||||
if width <= 0 {
|
||||
panic!("Cannot set the terminal width lower than 1");
|
||||
}
|
||||
@ -160,7 +160,7 @@ impl ITerminal for WinApiTerminal {
|
||||
pub fn clear_after_cursor(
|
||||
pos: (u16, u16),
|
||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
||||
screen_manager: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) {
|
||||
let (mut x, mut y) = pos;
|
||||
|
||||
@ -184,7 +184,7 @@ pub fn clear_after_cursor(
|
||||
pub fn clear_before_cursor(
|
||||
pos: (u16, u16),
|
||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
||||
screen_manager: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) {
|
||||
let (xpos, ypos) = pos;
|
||||
|
||||
@ -204,7 +204,7 @@ pub fn clear_before_cursor(
|
||||
clear(start_location, cells_to_write, screen_manager);
|
||||
}
|
||||
|
||||
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &ScreenManager) {
|
||||
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &Arc<Stdout>) {
|
||||
// position x at start
|
||||
let x = 0;
|
||||
// position y at start
|
||||
@ -222,13 +222,13 @@ pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &Sc
|
||||
clear(start_location, cells_to_write, &screen_manager);
|
||||
|
||||
// put the cursor back at (0, 0)
|
||||
cursor(screen_manager).goto(0, 0);
|
||||
TerminalCursor::new(screen_manager).goto(0, 0);
|
||||
}
|
||||
|
||||
pub fn clear_current_line(
|
||||
pos: (u16, u16),
|
||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
||||
screen_manager: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) {
|
||||
// position x at start
|
||||
let x = 0;
|
||||
@ -247,13 +247,13 @@ pub fn clear_current_line(
|
||||
clear(start_location, cells_to_write, screen_manager);
|
||||
|
||||
// put the cursor back at 1 cell on current row
|
||||
cursor(screen_manager).goto(0, y);
|
||||
TerminalCursor::new(screen_manager).goto(0, y);
|
||||
}
|
||||
|
||||
pub fn clear_until_line(
|
||||
pos: (u16, u16),
|
||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
||||
screen_manager: &ScreenManager,
|
||||
screen_manager: &Arc<Stdout>,
|
||||
) {
|
||||
let (x, y) = pos;
|
||||
|
||||
@ -268,10 +268,10 @@ pub fn clear_until_line(
|
||||
clear(start_location, cells_to_write, &screen_manager);
|
||||
|
||||
// put the cursor back at original cursor position
|
||||
cursor(screen_manager).goto(x, y);
|
||||
TerminalCursor::new(screen_manager).goto(x, y);
|
||||
}
|
||||
|
||||
fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &ScreenManager) {
|
||||
fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &Arc<Stdout>) {
|
||||
let mut cells_written = 0;
|
||||
let mut success = false;
|
||||
|
||||
|
55
src/modules/write/ansi_stdout.rs
Normal file
55
src/modules/write/ansi_stdout.rs
Normal file
@ -0,0 +1,55 @@
|
||||
//! This is an ANSI specific implementation for the screen write
|
||||
//! This module is used for windows 10 terminals and unix terminals by default.
|
||||
//! This module uses the stdout to write to the console.
|
||||
|
||||
use super::IStdout;
|
||||
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::{Arc,Mutex};
|
||||
use std::io::{self, Read, Write,Stdout, stdout};
|
||||
use std::str::from_utf8;
|
||||
|
||||
/// This struct is an ANSI escape code implementation for screen related actions.
|
||||
pub struct AnsiStdout {
|
||||
pub handle: Stdout,
|
||||
}
|
||||
|
||||
impl IStdout for AnsiStdout {
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
let out = &self.handle;
|
||||
let mut handle = out.lock();
|
||||
write!(handle, "{}", string)?;
|
||||
handle.flush();
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
let out = &self.handle;
|
||||
let mut handle = out.lock();
|
||||
handle.write(buf)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn flush(&self) -> io::Result<()> {
|
||||
let out = &self.handle;
|
||||
let mut handle = out.lock();
|
||||
handle.flush();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl AnsiStdout {
|
||||
pub fn new() -> Self {
|
||||
AnsiStdout { handle: stdout() }
|
||||
}
|
||||
}
|
@ -18,22 +18,23 @@
|
||||
//!
|
||||
//! This is the reason why this module exits: it is to provide access to the current terminal screen whether it will be the alternate screen and main screen.
|
||||
|
||||
mod manager;
|
||||
mod stdout;
|
||||
|
||||
mod ansi_manager;
|
||||
mod ansi_stdout;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod win_manager;
|
||||
mod winapi_stdout;
|
||||
|
||||
pub use self::ansi_manager::AnsiScreenManager;
|
||||
pub use self::ansi_stdout::AnsiStdout;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use self::win_manager::WinApiScreenManager;
|
||||
pub use self::winapi_stdout::WinApiStdout;
|
||||
|
||||
pub use self::manager::ScreenManager;
|
||||
use super::functions;
|
||||
pub use self::stdout::Stdout;
|
||||
|
||||
use std::any::Any;
|
||||
use std::io;
|
||||
|
||||
use super::{functions};
|
||||
|
||||
/// This trait defines the actions that could be preformed on the current screen.
|
||||
/// This trait can be implemented so that an concrete implementation of the IScreenManager can forfill
|
||||
/// the wishes to work on an specific platform.
|
||||
@ -42,21 +43,15 @@ use std::io;
|
||||
///
|
||||
/// This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
|
||||
/// so that color related actions can be preformed on both unix and windows systems.
|
||||
pub trait IScreenManager {
|
||||
fn set_is_raw_screen(&mut self, value: bool);
|
||||
fn set_is_alternate_screen(&mut self, value: bool);
|
||||
|
||||
fn is_raw_screen(&self) -> bool;
|
||||
fn is_alternate_screen(&self) -> bool;
|
||||
|
||||
pub trait IStdout {
|
||||
/// Write a &str to the current stdout.
|
||||
fn write_str(&self, string: &str) -> io::Result<usize>;
|
||||
fn write_str(&self, string: &str ) -> io::Result<usize>;
|
||||
/// Write [u8] buffer to console.
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize>;
|
||||
/// Flush the current output.
|
||||
fn flush(&self) -> io::Result<()>;
|
||||
/// Can be used to convert to an specific IScreenManager implementation.
|
||||
|
||||
fn as_any(&self) -> &Any;
|
||||
/// Can be used to convert to an specific mutable IScreenManager implementation.
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut Any;
|
||||
}
|
@ -27,45 +27,31 @@ use std::io::{self, Write};
|
||||
#[cfg(target_os = "windows")]
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Struct that stores an specific platform implementation for screen related actions.
|
||||
pub struct ScreenManager {
|
||||
screen_manager: Box<IScreenManager + Send>,
|
||||
pub struct Stdout {
|
||||
screen_manager: Box<IStdout + Send>,
|
||||
pub is_in_raw_mode:bool,
|
||||
}
|
||||
|
||||
impl ScreenManager {
|
||||
/// Create new screen manager instance whereon screen related actions can be performed.
|
||||
pub fn new() -> ScreenManager {
|
||||
// todo: impl Default for stdout
|
||||
|
||||
impl Stdout {
|
||||
/// 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 = functions::get_module::<Box<IScreenManager + Send>>(
|
||||
Box::from(WinApiScreenManager::new()),
|
||||
Box::from(AnsiScreenManager::new()),
|
||||
let screen_manager = functions::get_module::<Box<IStdout + Send>>(
|
||||
Box::from(WinApiStdout::new()),
|
||||
Box::from(AnsiStdout::new()),
|
||||
).unwrap();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let screen_manager = Box::from(AnsiScreenManager::new()) as Box<IScreenManager + Send>;
|
||||
let screen_manager = Box::from(AnsiStdout::new()) as Box<IStdout + Send>;
|
||||
|
||||
ScreenManager { screen_manager }
|
||||
Stdout { screen_manager , is_in_raw_mode}
|
||||
}
|
||||
|
||||
/// Set whether screen is raw screen.
|
||||
pub fn set_is_raw_screen(&mut self, value: bool) {
|
||||
self.screen_manager.set_is_raw_screen(value);
|
||||
}
|
||||
|
||||
/// Set whether the current screen is alternate screen.
|
||||
pub fn set_is_alternate_screen(&mut self, value: bool) {
|
||||
self.screen_manager.set_is_alternate_screen(value);
|
||||
}
|
||||
|
||||
/// Check if the current screen is in rawscreen modes
|
||||
pub fn is_raw_screen(&self) -> bool {
|
||||
self.screen_manager.is_raw_screen()
|
||||
}
|
||||
|
||||
/// Check if the current screen is in alternate modes.
|
||||
pub fn is_alternate_screen(&self) -> bool {
|
||||
self.screen_manager.is_alternate_screen()
|
||||
}
|
||||
|
||||
/// Write String to the current screen.
|
||||
pub fn write_string(&self, string: String) -> io::Result<usize> {
|
||||
@ -86,12 +72,10 @@ impl ScreenManager {
|
||||
self.screen_manager.write(buf)
|
||||
}
|
||||
|
||||
/// Can be used to get an reference to an specific implementation used for the current platform.
|
||||
pub fn as_any(&self) -> &Any {
|
||||
self.screen_manager.as_any()
|
||||
}
|
||||
|
||||
/// Can be used to get an mutable reference to an specific implementation used for the current platform.
|
||||
pub fn as_any_mut(&mut self) -> &mut Any {
|
||||
self.screen_manager.as_any_mut()
|
||||
}
|
56
src/modules/write/winapi_stdout.rs
Normal file
56
src/modules/write/winapi_stdout.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use super::IStdout;
|
||||
use kernel::windows_kernel::{handle, kernel, writing};
|
||||
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use std::ptr::NonNull;
|
||||
use std::any::Any;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// This struct is an WINAPI implementation for screen related actions.
|
||||
pub struct WinApiStdout {
|
||||
pub handle: HANDLE,
|
||||
}
|
||||
|
||||
impl IStdout for WinApiStdout {
|
||||
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
self.write(string.as_bytes())
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
writing::write_char_buffer(&self.handle, buf)
|
||||
}
|
||||
|
||||
fn flush(&self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_any_mut(&mut self) -> &mut Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl WinApiStdout {
|
||||
pub fn new() -> Self {
|
||||
WinApiStdout { handle: handle::get_output_handle().unwrap() }
|
||||
}
|
||||
|
||||
pub fn set(&mut self, handle: HANDLE)
|
||||
{
|
||||
self.handle = handle;
|
||||
}
|
||||
|
||||
pub fn get_handle(&self) -> &HANDLE
|
||||
{
|
||||
return &self.handle;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for WinApiStdout {}
|
||||
|
@ -1,6 +0,0 @@
|
||||
[package]
|
||||
name = "write_test"
|
||||
version = "0.1.0"
|
||||
authors = ["TimonPost <timonpost@hotmail.nl>"]
|
||||
|
||||
[dependencies]
|
@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
Loading…
Reference in New Issue
Block a user