From e1bbf1689f21fedbceb52e69534f2ee1efe9e457 Mon Sep 17 00:00:00 2001 From: TimonPost Date: Sat, 11 Aug 2018 17:58:15 +0200 Subject: [PATCH] some examples fixed added multy threaded logging example and tested input and changed styling system --- Cargo.toml | 6 +- examples/input/keyboard/async_input.rs | 119 ++++++------ examples/input/keyboard/input.rs | 13 +- examples/program_examples/duplex.rs | 62 +++---- .../first_depth_search/src/algorithm.rs | 22 ++- .../first_depth_search/src/main.rs | 109 ++++++----- .../first_depth_search/src/map.rs | 32 ++-- examples/program_examples/logging.rs | 149 +++++++++++++++ examples/simple.rs | 25 +-- src/common/commands/mod.rs | 26 +-- src/common/commands/shared_commands.rs | 10 +- src/common/commands/unix_command.rs | 13 +- src/common/commands/win_commands.rs | 39 ++-- src/common/crossterm.rs | 172 +++++------------- src/common/functions.rs | 9 +- src/common/mod.rs | 3 +- src/common/screen/alternate.rs | 41 ++++- src/common/screen/mod.rs | 6 +- src/common/screen/raw.rs | 56 ++++-- src/common/screen/screen.rs | 58 ++++++ src/kernel/unix_kernel/terminal.rs | 13 +- src/kernel/windows_kernel/csbi.rs | 9 +- src/kernel/windows_kernel/cursor.rs | 13 +- src/kernel/windows_kernel/handle.rs | 10 +- src/kernel/windows_kernel/kernel.rs | 7 +- src/kernel/windows_kernel/mod.rs | 2 +- src/kernel/windows_kernel/terminal.rs | 6 +- src/kernel/windows_kernel/writing.rs | 7 +- src/lib.rs | 7 +- src/modules/cursor/ansi_cursor.rs | 27 +-- src/modules/cursor/cursor.rs | 54 +++--- src/modules/cursor/mod.rs | 26 +-- src/modules/cursor/winapi_cursor.rs | 27 +-- src/modules/input/input.rs | 24 +-- src/modules/input/mod.rs | 13 +- src/modules/input/unix_input.rs | 12 +- src/modules/input/windows_input.rs | 20 +- src/modules/manager/ansi_manager.rs | 78 -------- src/modules/manager/win_manager.rs | 90 --------- src/modules/mod.rs | 8 +- src/modules/style/ansi_color.rs | 16 +- src/modules/style/color.rs | 20 +- src/modules/style/mod.rs | 9 +- src/modules/style/objectstyle.rs | 9 +- src/modules/style/styledobject.rs | 55 +++--- src/modules/style/winapi_color.rs | 24 +-- src/modules/terminal/ansi_terminal.rs | 12 +- src/modules/terminal/mod.rs | 16 +- src/modules/terminal/terminal.rs | 28 +-- src/modules/terminal/winapi_terminal.rs | 34 ++-- src/modules/write/ansi_stdout.rs | 55 ++++++ src/modules/{manager => write}/mod.rs | 29 ++- .../{manager/manager.rs => write/stdout.rs} | 46 ++--- src/modules/write/winapi_stdout.rs | 56 ++++++ write_test/Cargo.toml | 6 - write_test/src/main.rs | 3 - 56 files changed, 976 insertions(+), 865 deletions(-) create mode 100644 examples/program_examples/logging.rs create mode 100644 src/common/screen/screen.rs delete mode 100644 src/modules/manager/ansi_manager.rs delete mode 100644 src/modules/manager/win_manager.rs create mode 100644 src/modules/write/ansi_stdout.rs rename src/modules/{manager => write}/mod.rs (76%) rename src/modules/{manager/manager.rs => write/stdout.rs} (62%) create mode 100644 src/modules/write/winapi_stdout.rs delete mode 100644 write_test/Cargo.toml delete mode 100644 write_test/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 1e58963..ea652db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/examples/input/keyboard/async_input.rs b/examples/input/keyboard/async_input.rs index fb2f881..9221c37 100644 --- a/examples/input/keyboard/async_input.rs +++ b/examples/input/keyboard/async_input.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)); } } diff --git a/examples/input/keyboard/input.rs b/examples/input/keyboard/input.rs index 0912931..df8dd8f 100644 --- a/examples/input/keyboard/input.rs +++ b/examples/input/keyboard/input.rs @@ -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), diff --git a/examples/program_examples/duplex.rs b/examples/program_examples/duplex.rs index 2c7e01d..7bd12d0 100644 --- a/examples/program_examples/duplex.rs +++ b/examples/program_examples/duplex.rs @@ -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); + } + } } } diff --git a/examples/program_examples/first_depth_search/src/algorithm.rs b/examples/program_examples/first_depth_search/src/algorithm.rs index f7b33db..608d1a6 100644 --- a/examples/program_examples/first_depth_search/src/algorithm.rs +++ b/examples/program_examples/first_depth_search/src/algorithm.rs @@ -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, 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)); } diff --git a/examples/program_examples/first_depth_search/src/main.rs b/examples/program_examples/first_depth_search/src/main.rs index f6f8f65..cfbde4c 100644 --- a/examples/program_examples/first_depth_search/src/main.rs +++ b/examples/program_examples/first_depth_search/src/main.rs @@ -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(); + // 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_end_screen(crossterm: &Crossterm) -{ - -} - -fn print_welcome_screen(crossterm: &mut Crossterm) +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); - 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")); - // 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" + ); - 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(); - 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(); - // print some progress example. - for i in (1..5).rev() { + if let Some(Ok(b'q')) = a { + terminal.exit(); + } - let a = stdin.next(); + // 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); - if let Some(Ok(b'q')) = a { - terminal.exit(); + // 1 second delay + thread::sleep(time::Duration::from_secs(1)); + } } - - // 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)); - } } \ No newline at end of file diff --git a/examples/program_examples/first_depth_search/src/map.rs b/examples/program_examples/first_depth_search/src/map.rs index 49ac529..6827da1 100644 --- a/examples/program_examples/first_depth_search/src/map.rs +++ b/examples/program_examples/first_depth_search/src/map.rs @@ -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 = 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); + } } } } diff --git a/examples/program_examples/logging.rs b/examples/program_examples/logging.rs new file mode 100644 index 0000000..ac92ecc --- /dev/null +++ b/examples/program_examples/logging.rs @@ -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 { + inner: Arc>>, +} + +impl WorkQueue { + fn new() -> Self { + Self { inner: Arc::new(Mutex::new(VecDeque::new())) } + } + + // get an item from the que if exists + fn get_work(&self) -> Option { + 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>, +} + +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>, +} + +impl SyncFlagRx { + pub fn get(&self) -> Result { + 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, Receiver) = 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) +{ + 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) -> Vec> +{ + // 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; +} diff --git a/examples/simple.rs b/examples/simple.rs index 79f6eee..b8611a1 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -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. -} - - - diff --git a/src/common/commands/mod.rs b/src/common/commands/mod.rs index 9b9a2a2..a361777 100644 --- a/src/common/commands/mod.rs +++ b/src/common/commands/mod.rs @@ -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<()>; +} diff --git a/src/common/commands/shared_commands.rs b/src/common/commands/shared_commands.rs index af64835..27626af 100644 --- a/src/common/commands/shared_commands.rs +++ b/src/common/commands/shared_commands.rs @@ -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(()) } diff --git a/src/common/commands/unix_command.rs b/src/common/commands/unix_command.rs index b988027..df4ca69 100644 --- a/src/common/commands/unix_command.rs +++ b/src/common/commands/unix_command.rs @@ -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, } -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 { diff --git a/src/common/commands/win_commands.rs b/src/common/commands/win_commands.rs index 7d8f969..6d59392 100644 --- a/src/common/commands/win_commands.rs +++ b/src/common/commands/win_commands.rs @@ -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::() - { - 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::() + .downcast_mut::() { 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); diff --git a/src/common/crossterm.rs b/src/common/crossterm.rs index b86cd21..463ce75 100644 --- a/src/common/crossterm.rs +++ b/src/common/crossterm.rs @@ -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, +pub struct Crossterm { } - #[cfg(windows)] - raw_terminal: Option, - // 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>, -} - -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(&self, val: D) -> style::StyledObject +// 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(&self, val: D) -> style::StyledObject 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 { - 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 { +// 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(); +// } +// } +//} diff --git a/src/common/functions.rs b/src/common/functions.rs index e74e752..18faa50 100644 --- a/src/common/functions.rs +++ b/src/common/functions.rs @@ -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) -> (u16, u16) { #[cfg(unix)] - return pos(); + return pos(stdout); #[cfg(windows)] - return pos(screen_manager); + return pos(stdout); } /// exit the current terminal. diff --git a/src/common/mod.rs b/src/common/mod.rs index 8730ded..80b4e92 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -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; diff --git a/src/common/screen/alternate.rs b/src/common/screen/alternate.rs index f80545d..78d9f0b 100644 --- a/src/common/screen/alternate.rs +++ b/src/common/screen/alternate.rs @@ -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, + pub screen: Screen, +} impl AlternateScreen { - /// Create an new alternate screen type. - pub fn new() -> Box { + + pub fn new(command: Box, screen: Screen) -> Self + { + return AlternateScreen { command, screen } + } + + pub fn to_alternate_screen(screen_manager: Stdout) -> io::Result { #[cfg(target_os = "windows")] let command = functions::get_module::>( 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 + { + return self.screen.enable_raw_modes(); + } +} + +impl Drop for AlternateScreen +{ + fn drop(&mut self) { + self.to_main_screen(); } } diff --git a/src/common/screen/mod.rs b/src/common/screen/mod.rs index 9e9933d..21878c1 100644 --- a/src/common/screen/mod.rs +++ b/src/common/screen/mod.rs @@ -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; diff --git a/src/common/screen/raw.rs b/src/common/screen/raw.rs index 522ffe9..8eca969 100644 --- a/src/common/screen/raw.rs +++ b/src/common/screen/raw.rs @@ -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 { -// 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 + { + #[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 { diff --git a/src/common/screen/screen.rs b/src/common/screen/screen.rs new file mode 100644 index 0000000..bab2b98 --- /dev/null +++ b/src/common/screen/screen.rs @@ -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, + pub stdout: Arc, +} + +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 { + 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 { + 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 { + self.buffer.write(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { + self.stdout.write_buf(&self.buffer); + self.stdout.flush() + } +} \ No newline at end of file diff --git a/src/kernel/unix_kernel/terminal.rs b/src/kernel/unix_kernel/terminal.rs index 1cd8d28..e3e8b71 100644 --- a/src/kernel/unix_kernel/terminal.rs +++ b/src/kernel/unix_kernel/terminal.rs @@ -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) -> (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); diff --git a/src/kernel/windows_kernel/csbi.rs b/src/kernel/windows_kernel/csbi.rs index aa7d966..26f4434 100644 --- a/src/kernel/windows_kernel/csbi.rs +++ b/src/kernel/windows_kernel/csbi.rs @@ -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 { +pub fn get_csbi(screen_manager: &Arc) -> Result { let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty(); let success; @@ -35,7 +36,7 @@ pub fn get_csbi(screen_manager: &ScreenManager) -> Result, ) -> 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 } /// 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) -> bool { let handle = handle::get_current_handle(screen_manager).unwrap(); unsafe { diff --git a/src/kernel/windows_kernel/cursor.rs b/src/kernel/windows_kernel/cursor.rs index ba8fe20..e31b8bc 100644 --- a/src/kernel/windows_kernel/cursor.rs +++ b/src/kernel/windows_kernel/cursor.rs @@ -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) { 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) { 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) -> (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) { if x < 0 || x >= ::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) -> Result<()> { let handle = handle::get_current_handle(screen_manager).unwrap(); let cursor_info = CONSOLE_CURSOR_INFO { diff --git a/src/kernel/windows_kernel/handle.rs b/src/kernel/windows_kernel/handle.rs index a66bb92..88988d7 100644 --- a/src/kernel/windows_kernel/handle.rs +++ b/src/kernel/windows_kernel/handle.rs @@ -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 { +pub fn get_current_handle(screen_manager: &Arc) -> Result { let mut mutex = screen_manager; let handle: Result; - let winapi_screen_manager: &WinApiScreenManager = match screen_manager + let winapi_screen_manager: &WinApiStdout = match screen_manager .as_any() - .downcast_ref::() + .downcast_ref::() { 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'")) }; diff --git a/src/kernel/windows_kernel/kernel.rs b/src/kernel/windows_kernel/kernel.rs index 8dcef56..65c5195 100644 --- a/src/kernel/windows_kernel/kernel.rs +++ b/src/kernel/windows_kernel/kernel.rs @@ -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) -> 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) -> bool { let handle = handle::get_current_handle(screen_manager).unwrap(); let absolute = match absolute { diff --git a/src/kernel/windows_kernel/mod.rs b/src/kernel/windows_kernel/mod.rs index 605746c..9bb91a4 100644 --- a/src/kernel/windows_kernel/mod.rs +++ b/src/kernel/windows_kernel/mod.rs @@ -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}; diff --git a/src/kernel/windows_kernel/terminal.rs b/src/kernel/windows_kernel/terminal.rs index 1d32673..5851507 100644 --- a/src/kernel/windows_kernel/terminal.rs +++ b/src/kernel/windows_kernel/terminal.rs @@ -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) -> (u16, u16) { let handle = handle::get_output_handle().unwrap(); if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) { diff --git a/src/kernel/windows_kernel/writing.rs b/src/kernel/windows_kernel/writing.rs index a4f0f56..75d46b1 100644 --- a/src/kernel/windows_kernel/writing.rs +++ b/src/kernel/windows_kernel/writing.rs @@ -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, ) -> 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, ) -> bool { // Get the position of the current console window diff --git a/src/lib.rs b/src/lib.rs index 978790e..d8f4f33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)] diff --git a/src/modules/cursor/ansi_cursor.rs b/src/modules/cursor/ansi_cursor.rs index a7548ae..3a87de0 100644 --- a/src/modules/cursor/ansi_cursor.rs +++ b/src/modules/cursor/ansi_cursor.rs @@ -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) { 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) -> (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) { 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) { 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) { 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) { screen_manager.write_string(format!(csi!("{}D"), count)); } - fn save_position(&self, screen_manager: &ScreenManager) { + fn save_position(&self, screen_manager: &Arc) { screen_manager.write_str(csi!("s")); } - fn reset_position(&self, screen_manager: &ScreenManager) { + fn reset_position(&self, screen_manager: &Arc) { screen_manager.write_str(csi!("u")); } - fn hide(&self, screen_manager: &ScreenManager) { + fn hide(&self, screen_manager: &Arc) { screen_manager.write_str(csi!("?25l")); } - fn show(&self, screen_manager: &ScreenManager) { + fn show(&self, screen_manager: &Arc) { screen_manager.write_str(csi!("?25h")); } - fn blink(&self, blink: bool, screen_manager: &ScreenManager) { + fn blink(&self, blink: bool, screen_manager: &Arc) { if blink { screen_manager.write_str(csi!("?12h")); } else { diff --git a/src/modules/cursor/cursor.rs b/src/modules/cursor/cursor.rs index 5ef627c..87e7391 100644 --- a/src/modules/cursor/cursor.rs +++ b/src/modules/cursor/cursor.rs @@ -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, terminal_cursor: Box, } -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) -> TerminalCursor { #[cfg(target_os = "windows")] let cursor = functions::get_module::>(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(&mut self, value: D) -> &mut TerminalCursor<'cursor> { + pub fn print(&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) } diff --git a/src/modules/cursor/mod.rs b/src/modules/cursor/mod.rs index 7241499..02e6a3c 100644 --- a/src/modules/cursor/mod.rs +++ b/src/modules/cursor/mod.rs @@ -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); /// 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) -> (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); /// 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); /// Move the cursor `n` times down. - fn move_down(&self, count: u16, screen_manager: &ScreenManager); + fn move_down(&self, count: u16, screen_manager: &Arc); /// Move the cursor `n` times left. - fn move_left(&self, count: u16, screen_manager: &ScreenManager); + fn move_left(&self, count: u16, screen_manager: &Arc); /// 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); /// Return to saved cursor position - fn reset_position(&self, screen_manager: &ScreenManager); + fn reset_position(&self, screen_manager: &Arc); /// Hide the terminal cursor. - fn hide(&self, screen_manager: &ScreenManager); + fn hide(&self, screen_manager: &Arc); /// Show the terminal cursor - fn show(&self, screen_manager: &ScreenManager); + fn show(&self, screen_manager: &Arc); /// enable or disable the blinking of the cursor. - fn blink(&self, blink: bool, screen_manager: &ScreenManager); + fn blink(&self, blink: bool, screen_manager: &Arc); } diff --git a/src/modules/cursor/winapi_cursor.rs b/src/modules/cursor/winapi_cursor.rs index 026d1fa..2a23e21 100644 --- a/src/modules/cursor/winapi_cursor.rs +++ b/src/modules/cursor/winapi_cursor.rs @@ -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) { 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) -> (u16, u16) { cursor::pos(screen_manager) } - fn move_up(&self, count: u16, screen_manager: &ScreenManager) { + fn move_up(&self, count: u16, screen_manager: &Arc) { 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) { 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) { 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) { 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) { cursor::save_cursor_pos(screen_manager); } - fn reset_position(&self, screen_manager: &ScreenManager) { + fn reset_position(&self, screen_manager: &Arc) { cursor::reset_to_saved_position(screen_manager); } - fn hide(&self, screen_manager: &ScreenManager) { + fn hide(&self, screen_manager: &Arc) { cursor::cursor_visibility(false, screen_manager); } - fn show(&self, screen_manager: &ScreenManager) { + fn show(&self, screen_manager: &Arc) { cursor::cursor_visibility(true, screen_manager); } - fn blink(&self, blink: bool, screen_manager: &ScreenManager) {} + fn blink(&self, blink: bool, screen_manager: &Arc) {} } diff --git a/src/modules/input/input.rs b/src/modules/input/input.rs index 1ec49fd..4c5bd3b 100644 --- a/src/modules/input/input.rs +++ b/src/modules/input/input.rs @@ -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, - screen_manager: &'terminal ScreenManager, + stdout: Arc, } -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) -> 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 { - 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 { - 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); } diff --git a/src/modules/input/mod.rs b/src/modules/input/mod.rs index 07ab4d6..b026e36 100644 --- a/src/modules/input/mod.rs +++ b/src/modules/input/mod.rs @@ -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; + fn read_line(&self, screen_manger: &Arc) -> io::Result; /// Read one character from the user input - fn read_char(&self, screen_manger: &ScreenManager) -> io::Result; + fn read_char(&self, screen_manger: &Arc) -> io::Result; /// Read the input asynchronously from the user. - fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader; + fn read_async(&self, screen_manger: &Arc) -> 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) -> AsyncReader; } /// This is a wrapper for reading from the input asynchronously. diff --git a/src/modules/input/unix_input.rs b/src/modules/input/unix_input.rs index ff7bf5d..69ff906 100644 --- a/src/modules/input/unix_input.rs +++ b/src/modules/input/unix_input.rs @@ -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 { + fn read_line(&self, screen_manger: &Stdout) -> io::Result { 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 { + fn read_char(&self, screen_manger: &Arc) -> io::Result { read_char() } - fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader { + fn read_async(&self, screen_manger: &Arc) -> 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) -> AsyncReader { let (send, recv) = mpsc::channel(); thread::spawn(move || { diff --git a/src/modules/input/windows_input.rs b/src/modules/input/windows_input.rs index ebfc229..fa57814 100644 --- a/src/modules/input/windows_input.rs +++ b/src/modules/input/windows_input.rs @@ -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 { + fn read_line(&self, screen_manger: &Arc) -> io::Result { let mut chars: Vec = 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 { - let is_raw_screen = screen_manger.is_raw_screen(); + fn read_char(&self, screen_manger: &Arc) -> io::Result { + 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) -> 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) -> 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 { diff --git a/src/modules/manager/ansi_manager.rs b/src/modules/manager/ansi_manager.rs deleted file mode 100644 index a2f8b8f..0000000 --- a/src/modules/manager/ansi_manager.rs +++ /dev/null @@ -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, -} - -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 { - let out = &self.output; - let mut handle = out.lock(); - write!(handle, "{}", string)?; - Ok(0) - } - - fn write(&self, buf: &[u8]) -> io::Result { - { - 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, - } - } -} diff --git a/src/modules/manager/win_manager.rs b/src/modules/manager/win_manager.rs deleted file mode 100644 index 31a16c4..0000000 --- a/src/modules/manager/win_manager.rs +++ /dev/null @@ -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 { - self.write(string.as_bytes()) - } - - fn write(&self, buf: &[u8]) -> io::Result { - 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 {} diff --git a/src/modules/mod.rs b/src/modules/mod.rs index b50c231..74ee5c6 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -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; \ No newline at end of file diff --git a/src/modules/style/ansi_color.rs b/src/modules/style/ansi_color.rs index d16f609..22dcb94 100644 --- a/src/modules/style/ansi_color.rs +++ b/src/modules/style/ansi_color.rs @@ -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.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.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.write_str(csi!("0m")); } fn color_value(&self, color: Color, color_type: ColorType) -> String { diff --git a/src/modules/style/color.rs b/src/modules/style/color.rs index b9389e3..ec9e891 100644 --- a/src/modules/style/color.rs +++ b/src/modules/style/color.rs @@ -23,14 +23,14 @@ use std::io; /// colored_terminal.reset(); /// /// ``` -pub struct TerminalColor<'terminal> { +pub struct TerminalColor { color: Box, - screen_manager: &'terminal ScreenManager, + stdout: Arc, } -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) -> TerminalColor { #[cfg(target_os = "windows")] let color = functions::get_module::>( 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) -> TerminalColor { + TerminalColor::new(stdout) } diff --git a/src/modules/style/mod.rs b/src/modules/style/mod.rs index 7c6c6f4..30fc4df 100644 --- a/src/modules/style/mod.rs +++ b/src/modules/style/mod.rs @@ -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); /// 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); /// Reset the terminal color to default. - fn reset(&self, screen_manager: &ScreenManager); + fn reset(&self, stdout: &Arc); /// Gets an value that represents an color from the given `Color` and `ColorType`. fn color_value(&self, color: Color, color_type: ColorType) -> String; } diff --git a/src/modules/style/objectstyle.rs b/src/modules/style/objectstyle.rs index 2e93e8b..a329a82 100644 --- a/src/modules/style/objectstyle.rs +++ b/src/modules/style/objectstyle.rs @@ -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( &self, val: D, - screen_manager: &'style ScreenManager, - ) -> StyledObject<'style, D> { + ) -> StyledObject { StyledObject { object_style: self.clone(), - screen_manager: screen_manager, content: val, } } diff --git a/src/modules/style/styledobject.rs b/src/modules/style/styledobject.rs index debd440..6381128 100644 --- a/src/modules/style/styledobject.rs +++ b/src/modules/style/styledobject.rs @@ -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 { pub object_style: ObjectStyle, pub content: D, - pub screen_manager: &'terminal ScreenManager, } -impl<'terminal, D: Display> StyledObject<'terminal, D> { +impl StyledObject { /// 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 { 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 { 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 { &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 { 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 { 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 { self.attr(Attribute::Italic) } /// Underline font. #[cfg(unix)] #[inline(always)] - pub fn underlined(self) -> StyledObject<'terminal, D> { + pub fn underlined(self) -> StyledObject { 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 { 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 { 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 { 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 { 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 { 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(()) } } diff --git a/src/modules/style/winapi_color.rs b/src/modules/style/winapi_color.rs index ac0372c..d2da9c4 100644 --- a/src/modules/style/winapi_color.rs +++ b/src/modules/style/winapi_color.rs @@ -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) { 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) { 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) { + 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 diff --git a/src/modules/terminal/ansi_terminal.rs b/src/modules/terminal/ansi_terminal.rs index 7e55cb5..556c1bf 100644 --- a/src/modules/terminal/ansi_terminal.rs +++ b/src/modules/terminal/ansi_terminal.rs @@ -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) { 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) -> (u16, u16) { functions::get_terminal_size() } - fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) { + fn scroll_up(&self, count: i16, screen_manager: &Arc) { 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) { 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) { screen_manager.write_string(format!(csi!("8;{};{}t"), width, height)); } diff --git a/src/modules/terminal/mod.rs b/src/modules/terminal/mod.rs index 73b6a15..df14431 100644 --- a/src/modules/terminal/mod.rs +++ b/src/modules/terminal/mod.rs @@ -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); /// Get the terminal size (x,y) - fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16); + fn terminal_size(&self, screen_manager: &Arc) -> (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); /// 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); /// 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); /// Close the current terminal fn exit(&self); } diff --git a/src/modules/terminal/terminal.rs b/src/modules/terminal/terminal.rs index 46f4821..c3423de 100644 --- a/src/modules/terminal/terminal.rs +++ b/src/modules/terminal/terminal.rs @@ -22,14 +22,14 @@ use std::io::Write; /// let (with, height) = term.terminal_size(); /// /// ``` -pub struct Terminal<'terminal> { +pub struct Terminal { terminal: Box, - screen_manager: &'terminal ScreenManager, + screen: Arc, } -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) -> Terminal { #[cfg(target_os = "windows")] let terminal = functions::get_module::>( 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) } diff --git a/src/modules/terminal/winapi_terminal.rs b/src/modules/terminal/winapi_terminal.rs index 27506cd..8fc073f 100644 --- a/src/modules/terminal/winapi_terminal.rs +++ b/src/modules/terminal/winapi_terminal.rs @@ -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) { 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) -> (u16, u16) { terminal::terminal_size() } - fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) { + fn scroll_up(&self, count: i16, screen_manager: &Arc) { 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) { 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) { 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, ) { 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, ) { 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) { // 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, ) { // 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, ) { 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) { let mut cells_written = 0; let mut success = false; diff --git a/src/modules/write/ansi_stdout.rs b/src/modules/write/ansi_stdout.rs new file mode 100644 index 0000000..8d880bf --- /dev/null +++ b/src/modules/write/ansi_stdout.rs @@ -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 { + let out = &self.handle; + let mut handle = out.lock(); + write!(handle, "{}", string)?; + handle.flush(); + Ok(0) + } + + fn write(&self, buf: &[u8]) -> io::Result { + 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() } + } +} diff --git a/src/modules/manager/mod.rs b/src/modules/write/mod.rs similarity index 76% rename from src/modules/manager/mod.rs rename to src/modules/write/mod.rs index cd42126..2fe75f3 100644 --- a/src/modules/manager/mod.rs +++ b/src/modules/write/mod.rs @@ -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; + fn write_str(&self, string: &str ) -> io::Result; /// Write [u8] buffer to console. fn write(&self, buf: &[u8]) -> io::Result; /// 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; } diff --git a/src/modules/manager/manager.rs b/src/modules/write/stdout.rs similarity index 62% rename from src/modules/manager/manager.rs rename to src/modules/write/stdout.rs index 5103e3e..1410327 100644 --- a/src/modules/manager/manager.rs +++ b/src/modules/write/stdout.rs @@ -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, +pub struct Stdout { + screen_manager: Box, + 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::from(WinApiScreenManager::new()), - Box::from(AnsiScreenManager::new()), + let screen_manager = functions::get_module::>( + Box::from(WinApiStdout::new()), + Box::from(AnsiStdout::new()), ).unwrap(); #[cfg(not(target_os = "windows"))] - let screen_manager = Box::from(AnsiScreenManager::new()) as Box; + let screen_manager = Box::from(AnsiStdout::new()) as Box; - 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 { @@ -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() } diff --git a/src/modules/write/winapi_stdout.rs b/src/modules/write/winapi_stdout.rs new file mode 100644 index 0000000..7f521bc --- /dev/null +++ b/src/modules/write/winapi_stdout.rs @@ -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 { + self.write(string.as_bytes()) + } + + fn write(&self, buf: &[u8]) -> io::Result { + 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 {} + diff --git a/write_test/Cargo.toml b/write_test/Cargo.toml deleted file mode 100644 index 0272728..0000000 --- a/write_test/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "write_test" -version = "0.1.0" -authors = ["TimonPost "] - -[dependencies] diff --git a/write_test/src/main.rs b/write_test/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/write_test/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -}