some examples fixed added multy threaded logging example and tested input and changed styling system

This commit is contained in:
TimonPost 2018-08-11 17:58:15 +02:00
parent f6b1955cae
commit e1bbf1689f
56 changed files with 976 additions and 865 deletions

View File

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

View File

@ -1,26 +1,26 @@
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();
if let Ok(raw) = screen.enable_raw_modes()
{
// init some modules we use for this demo
let input = crossterm.input();
let terminal = crossterm.terminal();
let mut cursor = crossterm.cursor();
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 {
@ -43,11 +43,11 @@ pub fn read_async_until() {
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,22 +106,23 @@ 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());
if let Ok(alternate) = screen.enable_alternate_modes()
{
// 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(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();
// loop until the enter key (\r) is pressed.
loop {
terminal.clear(ClearType::All);
@ -141,3 +142,5 @@ pub fn async_reading_on_alternate_screen() {
thread::sleep(Duration::from_millis(200));
}
}
}
}

View File

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

View File

@ -29,7 +29,8 @@ use std::time::Duration;
use std::thread;
fn main() {
}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();
@ -64,7 +65,6 @@ fn main() {
}
}
}
}
pub fn swap_write(terminal: &mut Crossterm, msg: &str, input_buf: &String) {
let (term_width, term_height) = terminal.terminal().terminal_size();

View File

@ -4,7 +4,7 @@ use super::messages::END_MESSAGE;
use super::map::Map;
use crossterm::style::Color;
use crossterm::Crossterm;
use crossterm::{Crossterm, Screen};
use super::rand;
use super::rand::distributions::{IndependentSample, Range};
@ -12,19 +12,19 @@ use super::rand::distributions::{IndependentSample, Range};
use std::io::{stdout, Write};
use std::{thread, time};
pub struct FirstDepthSearch<'crossterm>
pub struct FirstDepthSearch<'screen>
{
direction: Direction,
map: Map,
stack: Vec<Position>,
root_pos: Position,
is_terminated: bool,
crossterm: &'crossterm Crossterm
screen: &'screen Screen
}
impl<'crossterm> FirstDepthSearch<'crossterm>
impl<'screen> FirstDepthSearch<'screen>
{
pub fn new(map: Map, start_pos: Position, crossterm: &'crossterm Crossterm) -> FirstDepthSearch<'crossterm>
pub fn new(map: Map, start_pos: Position, crossterm: &'screen Screen) -> FirstDepthSearch<'screen>
{
FirstDepthSearch
{
@ -33,7 +33,7 @@ impl<'crossterm> FirstDepthSearch<'crossterm>
stack: Vec::new(),
root_pos: start_pos,
is_terminated: false,
crossterm: crossterm,
screen: crossterm,
}
}
@ -44,7 +44,8 @@ impl<'crossterm> FirstDepthSearch<'crossterm>
// push first position on the stack
self.stack.push(self.root_pos);
let mut cursor = self.crossterm.cursor();
let crossterm = Crossterm::new();
let mut cursor = crossterm.cursor(&self.screen);
cursor.hide();
// loop until there are now items left in the stack.
@ -63,15 +64,16 @@ impl<'crossterm> FirstDepthSearch<'crossterm>
self.update_position();
let cell = self.crossterm.paint(" ").on(Color::Blue);
let cell = crossterm.style(" ").on(Color::Blue);
let pos = self.root_pos.clone();
let x = pos.x as u16;
let y = pos.y as u16;
cursor.goto(x,y).print(cell);
::std::io::stdout().flush();
cursor.goto(x,y);
cell.paint(&self.screen);
self.screen.stdout.flush();
thread::sleep(time::Duration::from_millis(2));
}

View File

@ -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,48 +25,45 @@ 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);
// 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);
map.render_map(&alternate_screen.screen);
// create the algorithm and start the
let mut algorithm = algorithm::FirstDepthSearch::new(map, start_pos, &crossterm);
// 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.
crossterm.enable_raw_mode();
let mut terminal = crossterm.terminal();
let mut cursor = crossterm.cursor();
if let Ok(raw) = screen.enable_raw_modes()
{
let crossterm = Crossterm::new();
let terminal = crossterm.terminal(&screen);
let cursor = crossterm.cursor(&raw.screen);
let input = crossterm.input(&raw.screen);
// clear the screen and print the welcome message.
terminal.clear(ClearType::All);
@ -80,12 +77,10 @@ fn print_welcome_screen(crossterm: &mut Crossterm)
Press `q` to abort the program"
);
let input = crossterm.input();
let mut stdin = input.read_async().bytes();
// print some progress example.
for i in (1..5).rev() {
let a = stdin.next();
if let Some(Ok(b'q')) = a {
@ -93,11 +88,11 @@ fn print_welcome_screen(crossterm: &mut Crossterm)
}
// 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));
cursor.goto(48, 10);
crossterm.style(format!("{}", i)).with(Color::Red).on(Color::Blue).paint(&screen);
// 1 second delay
thread::sleep(time::Duration::from_secs(1));
}
}
}

View File

@ -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;
@ -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()
{
@ -49,9 +51,9 @@ 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);
}
}
}

View File

@ -0,0 +1,149 @@
extern crate crossterm;
use crossterm::Screen;
use std::sync::Mutex;
use std::collections::VecDeque;
use std::sync::Arc;
use std::io::Write;
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread::{JoinHandle, self};
/// This is an que that could be shared between threads safely.
#[derive(Clone)]
struct WorkQueue<T: Send + Clone> {
inner: Arc<Mutex<VecDeque<T>>>,
}
impl<T: Send + Clone> WorkQueue<T> {
fn new() -> Self {
Self { inner: Arc::new(Mutex::new(VecDeque::new())) }
}
// get an item from the que if exists
fn get_work(&self) -> Option<T> {
let maybe_queue = self.inner.lock();
if let Ok(mut queue) = maybe_queue {
queue.pop_front()
} else {
panic!("WorkQueue::get_work() tried to lock a poisoned mutex");
}
}
// add an item to the que
fn add_work(&self, work: T) -> usize {
if let Ok(mut queue) = self.inner.lock() {
queue.push_back(work);
queue.len()
} else {
panic!("WorkQueue::add_work() tried to lock a poisoned mutex");
}
}
}
#[derive(Clone)]
struct SyncFlagTx {
inner: Arc<Mutex<bool>>,
}
impl SyncFlagTx {
pub fn set(&mut self, state: bool) -> Result<(), ()> {
if let Ok(mut v) = self.inner.lock() {
*v = state;
Ok(())
} else {
Err(())
}
}
}
#[derive(Clone)]
struct SyncFlagRx {
inner: Arc<Mutex<bool>>,
}
impl SyncFlagRx {
pub fn get(&self) -> Result<bool, ()> {
if let Ok(v) = self.inner.lock() {
Ok(*v)
} else {
Err(())
}
}
}
fn new_sync_flag(initial_state: bool) -> (SyncFlagTx, SyncFlagRx) {
let state = Arc::new(Mutex::new(initial_state));
let tx = SyncFlagTx { inner: state.clone() };
let rx = SyncFlagRx { inner: state.clone() };
return (tx, rx);
}
fn main()
{
let (results_tx, results_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
let (mut more_jobs_tx, more_jobs_rx) = new_sync_flag(true);
// queue with all log entry's.
let queue = WorkQueue::new();
// queue x logs with different threads.
let thread_handles = log_with_different_threads(more_jobs_tx.clone(), queue.clone());
// a thread that will log all logs in the queue.
handle_incoming_logs(more_jobs_rx.clone(), queue.clone());
for handle in thread_handles
{
handle.join();
}
}
fn handle_incoming_logs(more_jobs_rx: SyncFlagRx, queue: WorkQueue<String>)
{
thread::spawn( move || {
let mut screen: Screen = Screen::new();
// Loop while there's expected to be work, looking for work.
while more_jobs_rx.get().unwrap() {
// If work is available, do that work.
if let Some(work) = queue.get_work() {
// write the log
write!(screen, "{}\n", work);
screen.flush();
}
std::thread::yield_now();
}
}).join();
}
// start different threads that log contiguously.
fn log_with_different_threads(more_jobs_tx: SyncFlagTx, queue: WorkQueue<String>) -> Vec<JoinHandle<()>>
{
// one vector that will have the thread handles in it.
let mut threads = Vec::new();
for thread_num in 1..5
{
let mut more_jobs = more_jobs_tx.clone();
let thread_queue = queue.clone();
// create new thread
let thread = thread::spawn(move || {
// log 400 messages
for log_entry_count in 1..400
{
thread_queue.add_work(format!("Log {} from thread {} ",log_entry_count, thread_num));
more_jobs.set(true);
}
});
threads.push(thread);
}
println!("All logging threads started");
return threads;
}

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
//! This module contains the commands that can be used for unix systems.
use super::{ IStateCommand};
use super::{ IStateCommand, IRawScreenCommand};
use kernel::unix_kernel::terminal;
use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH};
@ -60,15 +60,18 @@ pub struct RawModeCommand {
original_mode: Result<Termios>,
}
impl RawModeCommand {
impl RawModeCommand
{
pub fn new() -> Self {
RawModeCommand {
original_mode: terminal::get_terminal_mode(),
}
}
}
impl RawModeCommand {
/// Enables raw mode.
pub fn enable(&mut self) -> Result<()> {
fn enable(&mut self) -> Result<()> {
if let Ok(original_mode) = self.original_mode {
let mut new_mode = original_mode;
terminal::make_raw(&mut new_mode);
@ -83,7 +86,7 @@ impl RawModeCommand {
}
/// Disables raw mode.
pub fn disable(&mut self) -> Result<()> {
fn disable(&self) -> Result<()> {
if let Ok(ref original_mode) = self.original_mode {
let result = terminal::set_terminal_mode(&original_mode)?;
} else {

View File

@ -1,14 +1,16 @@
//! This module contains the commands that can be used for windows systems.
use super::{IAlternateScreenCommand, IEnableAnsiCommand, ScreenManager};
use super::{IAlternateScreenCommand, IEnableAnsiCommand, IRawScreenCommand, Stdout};
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
use modules::write::IStdout;
use std::mem;
use winapi::shared::minwindef::DWORD;
use winapi::um::wincon;
use winapi::um::wincon::{CHAR_INFO, COORD, ENABLE_VIRTUAL_TERMINAL_PROCESSING, SMALL_RECT};
use std::io::{Error, ErrorKind, Result};
use std::sync::Mutex;
/// This command is used for enabling and disabling ANSI code support for windows systems,
/// For more info check: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences.
@ -27,7 +29,7 @@ impl EnableAnsiCommand {
}
impl IEnableAnsiCommand for EnableAnsiCommand {
fn enable(&mut self) -> bool {
fn enable(&self) -> bool {
// we need to check whether we tried to enable ansi before. If we have we can just return if that had succeeded.
if ansi_support::has_been_tried_to_enable_ansi() && ansi_support::ansi_enabled() {
return ansi_support::windows_supportable();
@ -47,7 +49,7 @@ impl IEnableAnsiCommand for EnableAnsiCommand {
}
}
fn disable(&mut self) -> bool {
fn disable(&self) -> bool {
if ansi_support::ansi_enabled() {
let output_handle = handle::get_output_handle().unwrap();
@ -74,7 +76,8 @@ pub struct RawModeCommand {
mask: DWORD,
}
impl RawModeCommand {
impl RawModeCommand
{
pub fn new() -> Self {
use self::wincon::{ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT};
@ -82,9 +85,11 @@ impl RawModeCommand {
mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT,
}
}
}
impl IRawScreenCommand for RawModeCommand {
/// Enables raw mode.
pub fn enable(&mut self) -> Result<()> {
fn enable(&mut self) -> Result<()> {
let input_handle = handle::get_input_handle()?;
let mut dw_mode: DWORD = 0;
@ -108,7 +113,7 @@ impl RawModeCommand {
}
/// Disables raw mode.
pub fn disable(&mut self) -> Result<()> {
fn disable(&self) -> Result<()> {
let output_handle = handle::get_input_handle()?;
let mut dw_mode: DWORD = 0;
@ -143,8 +148,8 @@ impl ToAlternateScreenCommand {
}
impl IAlternateScreenCommand for ToAlternateScreenCommand {
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
use super::super::super::manager::WinApiScreenManager;
fn enable(&self, screen_manager: &mut Stdout) -> Result<()> {
use super::super::super::modules::write::WinApiStdout;
let handle = handle::get_output_handle()?;
@ -154,28 +159,20 @@ impl IAlternateScreenCommand for ToAlternateScreenCommand {
// Make the new screen buffer the active screen buffer.
csbi::set_active_screen_buffer(new_handle)?;
match screen_manager
let b: &mut WinApiStdout = match screen_manager
.as_any_mut()
.downcast_mut::<WinApiScreenManager>()
{
Some(b) => b.set_alternate_handle(new_handle),
None => return Err(Error::new(ErrorKind::Other, "Invalid cast exception")),
};
let b: &mut WinApiScreenManager = match screen_manager
.as_any_mut()
.downcast_mut::<WinApiScreenManager>()
.downcast_mut::<WinApiStdout>()
{
Some(b) => b,
None => return Err(Error::new(ErrorKind::Other, "Invalid cast exception")),
};
b.set_alternate_handle(new_handle);
b.set(new_handle);
Ok(())
}
fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
fn disable(&self, screen_manager: &Stdout) -> Result<()> {
let handle = handle::get_output_handle()?;
csbi::set_active_screen_buffer(handle);

View File

@ -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 std::fmt::Display;
use std::io::Write;
use std::sync::RwLock;
use std::io::Result;
use std::sync::Arc;
#[cfg(not(windows))]
use common::commands::unix_command;
@ -19,143 +20,58 @@ use common::commands::unix_command;
#[cfg(windows)]
use common::commands::win_commands;
pub struct Crossterm {
pub active_screen: manager::ScreenManager,
use write::Stdout;
#[cfg(not(windows))]
raw_terminal: Option<unix_command::RawModeCommand>,
pub struct Crossterm { }
#[cfg(windows)]
raw_terminal: Option<win_commands::RawModeCommand>,
// Would be cool to figure out a way to have multiple screens instead of just only the main and alternate screen.
// For windows this would be easy but for unix I have no idea.
alternate_screen: Option<Box<IAlternateScreenCommand + Send>>,
}
impl<'a> Crossterm {
impl<'crossterm> Crossterm {
pub fn new() -> Crossterm {
Crossterm {
active_screen: manager::ScreenManager::new(),
raw_terminal: None,
alternate_screen: None,
}
Crossterm {}
}
pub fn enable_raw_mode(&mut self) -> Result<()> {
match self.raw_terminal {
None => {
#[cfg(not(target_os = "windows"))]
let raw_terminal = Some(unix_command::RawModeCommand::new());
#[cfg(target_os = "windows")]
let raw_terminal = Some(win_commands::RawModeCommand::new());
self.raw_terminal = raw_terminal;
return self.enable_raw_mode();
}
Some(ref mut raw_terminal) => {
raw_terminal.enable()?;
self.active_screen.set_is_raw_screen(true);
}
}
Ok(())
pub fn cursor(&self, screen: &'crossterm Screen) -> cursor::TerminalCursor {
cursor::TerminalCursor::new(&screen.stdout.clone())
}
pub fn disable_raw_mode(&mut self) -> Result<()> {
match self.raw_terminal {
None => {
#[cfg(not(target_os = "windows"))]
let raw_terminal = Some(unix_command::RawModeCommand::new());
#[cfg(target_os = "windows")]
let raw_terminal = Some(win_commands::RawModeCommand::new());
self.raw_terminal = raw_terminal;
return self.disable_raw_mode();
}
Some(ref mut raw_terminal) => {
raw_terminal.disable()?;
self.active_screen.set_is_raw_screen(false);
}
}
Ok(())
pub fn input(&self, screen: &'crossterm Screen) -> input::TerminalInput {
return input::TerminalInput::new(&screen.stdout);
}
pub fn to_alternate_screen(&mut self) -> Result<()> {
match self.alternate_screen {
None => {
self.alternate_screen = Some(AlternateScreen::new());
return self.to_alternate_screen();
}
Some(ref mut alternate_screen) => {
alternate_screen.enable(&mut self.active_screen)?;
self.active_screen.set_is_alternate_screen(true);
}
pub fn terminal(&self, screen: &'crossterm Screen) -> terminal::Terminal {
return terminal::Terminal::new(&screen.stdout);
}
return Ok(());
}
pub fn 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);
pub fn color(&self, screen: &'crossterm Screen) -> style::TerminalColor {
return style::TerminalColor::new(&screen.stdout);
}
// Wraps an displayable object so it can be formatted with colors and attributes.
//
// Check `/examples/color` in the libary for more spesific examples.
//
pub fn paint<D>(&self, val: D) -> style::StyledObject<D>
pub fn style<D>(&self, val: D) -> style::StyledObject<D>
where
D: Display,
{
style::ObjectStyle::new().apply_to(val, &self.active_screen)
D: Display, {
style::ObjectStyle::new().apply_to(val)
}
}
impl Write for Crossterm {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.active_screen.write_buf(buf)
}
fn flush(&mut self) -> Result<()> {
self.active_screen.flush()
}
}
impl Drop for Crossterm {
fn drop(&mut self) {
if let Some(ref mut screen) = self.alternate_screen {
screen.disable(&mut self.active_screen);
}
if let Some(ref mut raw_terminal) = self.raw_terminal {
raw_terminal.disable();
}
}
}
//impl Write for Crossterm {M
// fn write(&mut self, buf: &[u8]) -> Result<usize> {
// self.active_screen.write_buf(buf)
// }
//
// fn flush(&mut self) -> Result<()> {
// self.active_screen.flush()
// }
//}
//
//impl Drop for Crossterm {
// fn drop(&mut self) {
// if let Some(ref mut screen) = self.alternate_screen {
// screen.disable(&mut self.active_screen);
// }
// if let Some(ref mut raw_terminal) = self.raw_terminal {
// raw_terminal.disable();
// }
// }
//}

View File

@ -1,6 +1,7 @@
//! Some actions need to preformed platform independently since they can not be solved `ANSI escape codes`.
use super::ScreenManager;
use super::Stdout;
use std::sync::Arc;
#[cfg(windows)]
use kernel::windows_kernel::terminal::{buffer_size, exit, terminal_size};
@ -21,12 +22,12 @@ pub fn get_terminal_size() -> (u16, u16) {
}
/// Get the cursor position based on the current platform.
pub fn get_cursor_position(screen_manager: &ScreenManager) -> (u16, u16) {
pub fn get_cursor_position(stdout: &Arc<Stdout>) -> (u16, u16) {
#[cfg(unix)]
return pos();
return pos(stdout);
#[cfg(windows)]
return pos(screen_manager);
return pos(stdout);
}
/// exit the current terminal.

View File

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

View File

@ -22,17 +22,27 @@
//! Todo: example
//!
use super::commands;
use super::{functions, ScreenManager};
use super::commands::{self, IAlternateScreenCommand};
use super::{functions, Screen, Stdout, RawScreen};
use std::convert::From;
use std::io::{self, Write};
use std::sync::Mutex;
pub struct AlternateScreen;
pub struct AlternateScreen
{
command: Box<IAlternateScreenCommand + Send>,
pub screen: Screen,
}
impl AlternateScreen {
/// Create an new alternate screen type.
pub fn new() -> Box<commands::IAlternateScreenCommand + Send> {
pub fn new(command: Box<IAlternateScreenCommand + Send>, screen: Screen) -> Self
{
return AlternateScreen { command, screen }
}
pub fn to_alternate_screen(screen_manager: Stdout) -> io::Result<AlternateScreen> {
#[cfg(target_os = "windows")]
let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Send>>(
Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
@ -42,6 +52,25 @@ impl AlternateScreen {
#[cfg(not(target_os = "windows"))]
let command = Box::from(commands::shared_commands::ToAlternateScreenCommand::new());
command
let mut stdout = screen_manager;
command.enable(&mut stdout)?;
return Ok(AlternateScreen::new(command, Screen::from(stdout)));
}
pub fn to_main_screen(&self) -> io::Result<()> {
self.command.disable(&self.screen.stdout)?;
Ok(())
}
pub fn enable_raw_modes(&self) -> io::Result<RawScreen>
{
return self.screen.enable_raw_modes();
}
}
impl Drop for AlternateScreen
{
fn drop(&mut self) {
self.to_main_screen();
}
}

View File

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

View File

@ -12,21 +12,47 @@
//!
//! With these modes you can easier design the terminal screen.
//
//use super::commands;
//use super::{functions, ScreenManager};
//
//use std::io::{self, Write};
//
///// A wrapper for the raw terminal state. Which can be used to write to.
//pub struct RawScreen;
//
//impl RawScreen {
// /// Create a new RawScreen type.
// pub fn new() -> Box<commands::IRawScreenCommand> {
// Box::from(EnableRawModeCommand::new())
// }
//}
use super::commands::*;
use super::{functions, Screen};
use std::io::{self, Write};
/// A wrapper for the raw terminal state. Which can be used to write to.
pub struct RawScreen
{
#[cfg(not(target_os = "windows"))]
command: unix_command::RawModeCommand,
#[cfg(target_os = "windows")]
command: win_commands::RawModeCommand,
pub screen: Screen,
}
impl RawScreen {
pub fn into_raw_mode(screen: Screen) -> io::Result<RawScreen>
{
#[cfg(not(target_os = "windows"))]
let command = unix_command::RawModeCommand::new();
#[cfg(target_os = "windows")]
let command = win_commands::RawModeCommand::new();
Ok(RawScreen { command: command, screen})
}
pub fn disable_raw_modes(&self) -> io::Result<()>
{
self.command.disable()?;
return Ok(())
}
}
impl Drop for RawScreen
{
fn drop(&mut self) {
self.disable_raw_modes();
}
}
//
/////// Trait withs contains a method for switching into raw mode.
////pub trait IntoRawMode: Write + Sized {

View File

@ -0,0 +1,58 @@
#[cfg(not(windows))]
use common::commands::unix_command;
#[cfg(windows)]
use common::commands::win_commands;
use common::commands::IAlternateScreenCommand;
use super::{AlternateScreen,RawScreen};
use super::super::super::modules::write::Stdout;
use std::io::Write;
use std::io::Result;
use std::sync::Arc;
pub struct Screen
{
buffer: Vec<u8>,
pub stdout: Arc<Stdout>,
}
impl Screen
{
pub fn new() -> Screen
{
return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() };
}
pub fn from(stdout: Stdout) -> Screen
{
return Screen { stdout: Arc::new(stdout), buffer: Vec::new() };
}
pub fn enable_raw_modes(&self) -> Result<RawScreen> {
let mut screen = Screen::from(Stdout::new(true));
let raw_screen = RawScreen::into_raw_mode(screen)?;
return Ok(raw_screen)
}
pub fn enable_alternate_modes(&self) -> Result<AlternateScreen> {
let mut stdout = Stdout::new(true);
let alternate_screen = AlternateScreen::to_alternate_screen(stdout)?;
return Ok(alternate_screen);
}
}
impl Write for Screen
{
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.buffer.write(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
self.stdout.write_buf(&self.buffer);
self.stdout.flush()
}
}

View File

@ -2,15 +2,14 @@
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ};
use common::commands::unix_command::{EnableRawModeCommand, NoncanonicalModeCommand};
use libc;
use {libc, Stdout};
pub use libc::termios;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Read;
use std::sync::Arc;
use std::io::{self, Error, ErrorKind, Read};
use std::os::unix::io::AsRawFd;
use std::time::{Duration, SystemTime};
use std::{fs, io, mem};
use std::{fs, mem};
use termios::{cfmakeraw, tcsetattr, Termios, TCSADRAIN};
use Crossterm;
@ -46,9 +45,9 @@ pub fn terminal_size() -> (u16, u16) {
}
/// Get the current cursor position.
pub fn pos() -> (u16, u16) {
pub fn pos(stdout: &Arc<Stdout>) -> (u16, u16) {
let mut crossterm = Crossterm::new();
let input = crossterm.input();
let input = crossterm.input(stdout);
let delimiter = b'R';
let mut stdin = input.read_until_async(delimiter);

View File

@ -10,12 +10,13 @@ use winapi::um::wincon::{
use winapi::um::winnt::HANDLE;
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
use super::{handle, kernel, Empty, ScreenManager};
use super::{handle, kernel, Empty, Stdout};
use std::io::{self, ErrorKind, Result};
use std::mem::size_of;
use std::sync::Arc;
/// Create a new console screen buffer info struct.
pub fn get_csbi(screen_manager: &ScreenManager) -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
pub fn get_csbi(screen_manager: &Arc<Stdout>) -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
let success;
@ -35,7 +36,7 @@ pub fn get_csbi(screen_manager: &ScreenManager) -> Result<CONSOLE_SCREEN_BUFFER_
/// Get buffer info and handle of the current screen.
pub fn get_csbi_and_handle(
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) -> Result<(CONSOLE_SCREEN_BUFFER_INFO, HANDLE)> {
let handle = handle::get_current_handle(screen_manager)?;
let csbi = get_csbi_by_handle(&handle)?;
@ -60,7 +61,7 @@ pub fn get_csbi_by_handle(handle: &HANDLE) -> Result<CONSOLE_SCREEN_BUFFER_INFO>
}
/// Set the console screen buffer size
pub fn set_console_screen_buffer_size(size: COORD, screen_manager: &ScreenManager) -> bool {
pub fn set_console_screen_buffer_size(size: COORD, screen_manager: &Arc<Stdout>) -> bool {
let handle = handle::get_current_handle(screen_manager).unwrap();
unsafe {

View File

@ -5,16 +5,17 @@ use winapi::um::wincon::{
SetConsoleCursorInfo, SetConsoleCursorPosition, CONSOLE_CURSOR_INFO, COORD,
};
use super::super::super::manager::{ScreenManager, WinApiScreenManager};
use super::super::super::modules::write::{Stdout, WinApiStdout};
use super::{csbi, handle, kernel};
use std::io::{self, ErrorKind, Result};
use std::sync::Arc;
/// This stores the cursor pos, at program level. So it can be recalled later.
static mut SAVED_CURSOR_POS: (u16, u16) = (0, 0);
/// Reset to saved cursor position
pub fn reset_to_saved_position(screen_manager: &ScreenManager) {
pub fn reset_to_saved_position(screen_manager: &Arc<Stdout>) {
unsafe {
set_console_cursor_position(
SAVED_CURSOR_POS.0 as i16,
@ -25,7 +26,7 @@ pub fn reset_to_saved_position(screen_manager: &ScreenManager) {
}
/// Save current cursor position to recall later.
pub fn save_cursor_pos(screen_manager: &ScreenManager) {
pub fn save_cursor_pos(screen_manager: &Arc<Stdout>) {
let position = pos(screen_manager);
unsafe {
@ -34,7 +35,7 @@ pub fn save_cursor_pos(screen_manager: &ScreenManager) {
}
/// get the current cursor position.
pub fn pos(screen_manager: &ScreenManager) -> (u16, u16) {
pub fn pos(screen_manager: &Arc<Stdout>) -> (u16, u16) {
let handle = handle::get_current_handle(screen_manager).unwrap();
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
@ -48,7 +49,7 @@ pub fn pos(screen_manager: &ScreenManager) -> (u16, u16) {
}
/// Set the cursor position to the given x and y. Note that this is 0 based.
pub fn set_console_cursor_position(x: i16, y: i16, screen_manager: &ScreenManager) {
pub fn set_console_cursor_position(x: i16, y: i16, screen_manager: &Arc<Stdout>) {
if x < 0 || x >= <i16>::max_value() {
panic!(
"Argument Out of Range Exception when setting cursor position to X: {}",
@ -77,7 +78,7 @@ pub fn set_console_cursor_position(x: i16, y: i16, screen_manager: &ScreenManage
}
/// change the cursor visibility.
pub fn cursor_visibility(visable: bool, screen_manager: &ScreenManager) -> Result<()> {
pub fn cursor_visibility(visable: bool, screen_manager: &Arc<Stdout>) -> Result<()> {
let handle = handle::get_current_handle(screen_manager).unwrap();
let cursor_info = CONSOLE_CURSOR_INFO {

View File

@ -5,20 +5,20 @@ use winapi::um::processenv::GetStdHandle;
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
use winapi::um::winnt::HANDLE;
use std::sync::Arc;
use super::super::super::manager::{ScreenManager, WinApiScreenManager};
use super::super::super::modules::write::{Stdout, WinApiStdout};
/// Get the global stored handle whits provides access to the current screen.
pub fn get_current_handle(screen_manager: &ScreenManager) -> Result<HANDLE> {
pub fn get_current_handle(screen_manager: &Arc<Stdout>) -> Result<HANDLE> {
let mut mutex = screen_manager;
let handle: Result<HANDLE>;
let winapi_screen_manager: &WinApiScreenManager = match screen_manager
let winapi_screen_manager: &WinApiStdout = match screen_manager
.as_any()
.downcast_ref::<WinApiScreenManager>()
.downcast_ref::<WinApiStdout>()
{
Some(win_api) => win_api,
None => return Err(io::Error::new(io::ErrorKind::Other,"Could not convert to winapi screen manager, this could happen when the user has an ANSI screen manager and is calling the platform specific operations 'get_cursor_pos' or 'get_terminal_size'"))
None => return Err(io::Error::new(io::ErrorKind::Other,"Could not convert to winapi screen write, this could happen when the user has an ANSI screen write and is calling the platform specific operations 'get_cursor_pos' or 'get_terminal_size'"))
};

View File

@ -6,10 +6,11 @@ use winapi::um::wincon::{
};
use winapi::um::winnt::HANDLE;
use super::super::super::manager::ScreenManager;
use super::super::super::modules::Stdout;
use super::{handle, Empty};
use std::io::{ErrorKind, Result};
use std::sync::Arc;
/// Get the largest console window size possible.
pub fn get_largest_console_window_size() -> COORD {
@ -33,7 +34,7 @@ pub fn get_console_mode(handle: &HANDLE, current_mode: &mut u32) -> bool {
}
/// Change the console text attribute.
pub fn set_console_text_attribute(value: u16, screen_manager: &ScreenManager) -> bool {
pub fn set_console_text_attribute(value: u16, screen_manager: &Arc<Stdout>) -> bool {
let handle = handle::get_current_handle(screen_manager).unwrap();
unsafe {
@ -42,7 +43,7 @@ pub fn set_console_text_attribute(value: u16, screen_manager: &ScreenManager) ->
}
/// Change console info.
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT, screen_manager: &ScreenManager) -> bool {
pub fn set_console_info(absolute: bool, rect: &SMALL_RECT, screen_manager: &Arc<Stdout>) -> bool {
let handle = handle::get_current_handle(screen_manager).unwrap();
let absolute = match absolute {

View File

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

View File

@ -1,6 +1,8 @@
//! This module contains terminal specific logic.
use super::{csbi, handle, ScreenManager};
use super::{csbi, handle, Stdout};
use std::sync::Arc;
/// Get the terminal size
pub fn terminal_size() -> (u16, u16) {
@ -16,7 +18,7 @@ pub fn terminal_size() -> (u16, u16) {
}
}
pub fn buffer_size(screen_manager: &ScreenManager) -> (u16, u16) {
pub fn buffer_size(screen_manager: &Arc<Stdout>) -> (u16, u16) {
let handle = handle::get_output_handle().unwrap();
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {

View File

@ -9,17 +9,18 @@ use winapi::um::wincon::{
};
use winapi::um::winnt::HANDLE;
use super::{csbi, handle, kernel, ScreenManager};
use super::{csbi, handle, kernel, Stdout};
use std::io::{self, ErrorKind, Result};
use std::str;
use std::sync::Arc;
/// Fill a certain block with characters.
pub fn fill_console_output_character(
cells_written: &mut u32,
start_location: COORD,
cells_to_write: u32,
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) -> bool {
let handle = handle::get_current_handle(screen_manager).unwrap();
@ -41,7 +42,7 @@ pub fn fill_console_output_attribute(
cells_written: &mut u32,
start_location: COORD,
cells_to_write: u32,
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) -> bool {
// Get the position of the current console window

View File

@ -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 common::Crossterm;
pub use write::{IStdout, Stdout};
pub use common::screen::Screen;
#[cfg(unix)]
extern crate libc;
#[cfg(unix)]

View File

@ -2,7 +2,10 @@
//! This module is used for windows 10 terminals and unix terminals by default.
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
use super::{functions, ITerminalCursor, ScreenManager};
use super::{functions, ITerminalCursor, Stdout};
use std::sync::Arc;
/// This struct is an ansi implementation for cursor related actions.
pub struct AnsiCursor;
@ -14,47 +17,47 @@ impl AnsiCursor {
}
impl ITerminalCursor for AnsiCursor {
fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager) {
fn goto(&self, x: u16, y: u16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{};{}H"), y + 1, x + 1));
}
fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16) {
fn pos(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
functions::get_cursor_position(screen_manager)
}
fn move_up(&self, count: u16, screen_manager: &ScreenManager) {
fn move_up(&self, count: u16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{}A"), count));
}
fn move_right(&self, count: u16, screen_manager: &ScreenManager) {
fn move_right(&self, count: u16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{}C"), count));
}
fn move_down(&self, count: u16, screen_manager: &ScreenManager) {
fn move_down(&self, count: u16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{}B"), count));
}
fn move_left(&self, count: u16, screen_manager: &ScreenManager) {
fn move_left(&self, count: u16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{}D"), count));
}
fn save_position(&self, screen_manager: &ScreenManager) {
fn save_position(&self, screen_manager: &Arc<Stdout>) {
screen_manager.write_str(csi!("s"));
}
fn reset_position(&self, screen_manager: &ScreenManager) {
fn reset_position(&self, screen_manager: &Arc<Stdout>) {
screen_manager.write_str(csi!("u"));
}
fn hide(&self, screen_manager: &ScreenManager) {
fn hide(&self, screen_manager: &Arc<Stdout>) {
screen_manager.write_str(csi!("?25l"));
}
fn show(&self, screen_manager: &ScreenManager) {
fn show(&self, screen_manager: &Arc<Stdout>) {
screen_manager.write_str(csi!("?25h"));
}
fn blink(&self, blink: bool, screen_manager: &ScreenManager) {
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>) {
if blink {
screen_manager.write_str(csi!("?12h"));
} else {

View File

@ -8,6 +8,7 @@ use super::*;
use std::fmt::Display;
use std::io::Write;
use std::sync::Arc;
/// Struct that stores an specific platform implementation for cursor related actions.
///
/// Check `/examples/version/cursor` in the library for more specific examples.
@ -33,14 +34,14 @@ use std::io::Write;
/// // or in one line
/// cursor.goto(5,5).move_left(2).move_right(2).print("10");
/// ```
pub struct TerminalCursor<'cursor> {
screen_manager: &'cursor ScreenManager,
pub struct TerminalCursor {
screen: Arc<Stdout>,
terminal_cursor: Box<ITerminalCursor>,
}
impl<'cursor> TerminalCursor<'cursor> {
impl TerminalCursor {
/// Create new cursor instance whereon cursor related actions can be performed.
pub fn new(screen_manager: &'cursor ScreenManager) -> TerminalCursor<'cursor> {
pub fn new(screen: &Arc<Stdout>) -> TerminalCursor {
#[cfg(target_os = "windows")]
let cursor =
functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new())
@ -51,7 +52,7 @@ impl<'cursor> TerminalCursor<'cursor> {
TerminalCursor {
terminal_cursor: cursor,
screen_manager: screen_manager,
screen: screen.clone(),
}
}
@ -68,9 +69,8 @@ impl<'cursor> TerminalCursor<'cursor> {
/// cursor.goto(4,5);
///
/// ```
pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor<'cursor> {
self.terminal_cursor.goto(x, y, &self.screen_manager);
self
pub fn goto(&self, x: u16, y: u16) {
self.terminal_cursor.goto(x, y, &self.screen);
}
/// Get current cursor position (x,y) in the terminal.
@ -87,7 +87,7 @@ impl<'cursor> TerminalCursor<'cursor> {
///
/// ```
pub fn pos(&self) -> (u16, u16) {
self.terminal_cursor.pos(&self.screen_manager)
self.terminal_cursor.pos(&self.screen)
}
/// Move the current cursor position `n` times up.
@ -102,8 +102,8 @@ impl<'cursor> TerminalCursor<'cursor> {
/// cursor.move_up(3);
///
/// ```
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
self.terminal_cursor.move_up(count, &self.screen_manager);
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor {
self.terminal_cursor.move_up(count, &self.screen);
self
}
@ -119,8 +119,8 @@ impl<'cursor> TerminalCursor<'cursor> {
/// cursor.move_right(3);
///
/// ```
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
self.terminal_cursor.move_right(count, &self.screen_manager);
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor {
self.terminal_cursor.move_right(count, &self.screen);
self
}
@ -137,8 +137,8 @@ impl<'cursor> TerminalCursor<'cursor> {
/// cursor.move_down(3);
///
/// ```
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
self.terminal_cursor.move_down(count, &self.screen_manager);
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor {
self.terminal_cursor.move_down(count, &self.screen);
self
}
@ -155,8 +155,8 @@ impl<'cursor> TerminalCursor<'cursor> {
/// cursor.move_left(3);
///
/// ```
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'cursor> {
self.terminal_cursor.move_left(count, &self.screen_manager);
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor {
self.terminal_cursor.move_left(count, &self.screen);
self
}
@ -197,13 +197,13 @@ impl<'cursor> TerminalCursor<'cursor> {
/// .print("@");
///
/// ```
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor<'cursor> {
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor {
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", value).unwrap();
&self.screen_manager.write_string(string);
&self.screen_manager.flush();
&self.screen.write_string(string);
&self.screen.flush();
self
}
@ -222,7 +222,7 @@ impl<'cursor> TerminalCursor<'cursor> {
///
/// ```
pub fn save_position(&self) {
self.terminal_cursor.save_position(&self.screen_manager);
self.terminal_cursor.save_position(&self.screen);
}
/// Return to saved cursor position
@ -240,7 +240,7 @@ impl<'cursor> TerminalCursor<'cursor> {
///
/// ```
pub fn reset_position(&self) {
self.terminal_cursor.reset_position(&self.screen_manager);
self.terminal_cursor.reset_position(&self.screen);
}
/// Hide de cursor in the console.
@ -256,7 +256,7 @@ impl<'cursor> TerminalCursor<'cursor> {
///
/// ```
pub fn hide(&self) {
self.terminal_cursor.hide(&self.screen_manager);
self.terminal_cursor.hide(&self.screen);
}
/// Show the cursor in the console.
@ -272,7 +272,7 @@ impl<'cursor> TerminalCursor<'cursor> {
///
/// ```
pub fn show(&self) {
self.terminal_cursor.show(&self.screen_manager);
self.terminal_cursor.show(&self.screen);
}
/// Enable or disable blinking of the terminal.
@ -291,11 +291,11 @@ impl<'cursor> TerminalCursor<'cursor> {
///
/// ```
pub fn blink(&self, blink: bool) {
self.terminal_cursor.blink(blink, &self.screen_manager);
self.terminal_cursor.blink(blink, &self.screen);
}
}
/// Get an TerminalCursor implementation whereon cursor related actions can be performed.
pub fn cursor(screen_manager: &ScreenManager) -> TerminalCursor {
TerminalCursor::new(screen_manager)
pub fn cursor(screen_manager: &Screen) -> TerminalCursor {
TerminalCursor::new(&screen_manager.stdout)
}

View File

@ -12,7 +12,9 @@ use self::ansi_cursor::AnsiCursor;
use self::winapi_cursor::WinApiCursor;
pub use self::cursor::{cursor, TerminalCursor};
use super::{functions, ScreenManager};
use super::{functions, Stdout, Screen};
use std::sync::Arc;
///! This trait defines the actions that can be preformed with the terminal cursor.
///! This trait can be implemented so that an concrete implementation of the ITerminalCursor can forfill
@ -24,25 +26,25 @@ use super::{functions, ScreenManager};
///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminalCursor {
/// Goto some location (x,y) in the context.
fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager);
fn goto(&self, x: u16, y: u16, screen_manager: &Arc<Stdout>);
/// Get the location (x,y) of the current cusror in the context
fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16);
fn pos(&self, screen_manager: &Arc<Stdout>) -> (u16, u16);
/// Move cursor n times up
fn move_up(&self, count: u16, screen_manager: &ScreenManager);
fn move_up(&self, count: u16, screen_manager: &Arc<Stdout>);
/// Move the cursor `n` times to the right.
fn move_right(&self, count: u16, screen_manager: &ScreenManager);
fn move_right(&self, count: u16, screen_manager: &Arc<Stdout>);
/// Move the cursor `n` times down.
fn move_down(&self, count: u16, screen_manager: &ScreenManager);
fn move_down(&self, count: u16, screen_manager: &Arc<Stdout>);
/// Move the cursor `n` times left.
fn move_left(&self, count: u16, screen_manager: &ScreenManager);
fn move_left(&self, count: u16, screen_manager: &Arc<Stdout>);
/// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct.
fn save_position(&self, screen_manager: &ScreenManager);
fn save_position(&self, screen_manager: &Arc<Stdout>);
/// Return to saved cursor position
fn reset_position(&self, screen_manager: &ScreenManager);
fn reset_position(&self, screen_manager: &Arc<Stdout>);
/// Hide the terminal cursor.
fn hide(&self, screen_manager: &ScreenManager);
fn hide(&self, screen_manager: &Arc<Stdout>);
/// Show the terminal cursor
fn show(&self, screen_manager: &ScreenManager);
fn show(&self, screen_manager: &Arc<Stdout>);
/// enable or disable the blinking of the cursor.
fn blink(&self, blink: bool, screen_manager: &ScreenManager);
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>);
}

View File

@ -2,11 +2,14 @@
//! This module is used for windows terminals that do not support ANSI escape codes.
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
use super::super::manager::{ScreenManager, WinApiScreenManager};
use super::super::super::write::{Stdout, WinApiStdout};
use super::ITerminalCursor;
use kernel::windows_kernel::{cursor, kernel};
use std::sync::Arc;
/// This struct is an windows implementation for cursor related actions.
pub struct WinApiCursor;
@ -17,48 +20,48 @@ impl WinApiCursor {
}
impl ITerminalCursor for WinApiCursor {
fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager) {
fn goto(&self, x: u16, y: u16, screen_manager: &Arc<Stdout>) {
cursor::set_console_cursor_position(x as i16, y as i16, screen_manager);
}
fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16) {
fn pos(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
cursor::pos(screen_manager)
}
fn move_up(&self, count: u16, screen_manager: &ScreenManager) {
fn move_up(&self, count: u16, screen_manager: &Arc<Stdout>) {
let (xpos, ypos) = self.pos(screen_manager);
self.goto(xpos, ypos - count, screen_manager);
}
fn move_right(&self, count: u16, screen_manager: &ScreenManager) {
fn move_right(&self, count: u16, screen_manager: &Arc<Stdout>) {
let (xpos, ypos) = self.pos(screen_manager);
self.goto(xpos + count, ypos, screen_manager);
}
fn move_down(&self, count: u16, screen_manager: &ScreenManager) {
fn move_down(&self, count: u16, screen_manager: &Arc<Stdout>) {
let (xpos, ypos) = self.pos(screen_manager);
self.goto(xpos, ypos + count, screen_manager);
}
fn move_left(&self, count: u16, screen_manager: &ScreenManager) {
fn move_left(&self, count: u16, screen_manager: &Arc<Stdout>) {
let (xpos, ypos) = self.pos(screen_manager);
self.goto(xpos - count, ypos, screen_manager);
}
fn save_position(&self, screen_manager: &ScreenManager) {
fn save_position(&self, screen_manager: &Arc<Stdout>) {
cursor::save_cursor_pos(screen_manager);
}
fn reset_position(&self, screen_manager: &ScreenManager) {
fn reset_position(&self, screen_manager: &Arc<Stdout>) {
cursor::reset_to_saved_position(screen_manager);
}
fn hide(&self, screen_manager: &ScreenManager) {
fn hide(&self, screen_manager: &Arc<Stdout>) {
cursor::cursor_visibility(false, screen_manager);
}
fn show(&self, screen_manager: &ScreenManager) {
fn show(&self, screen_manager: &Arc<Stdout>) {
cursor::cursor_visibility(true, screen_manager);
}
fn blink(&self, blink: bool, screen_manager: &ScreenManager) {}
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>) {}
}

View File

@ -2,7 +2,7 @@
//! Like reading a line, reading a character and reading asynchronously.
use std::io;
use std::sync::Arc;
use super::*;
/// Struct that stores an specific platform implementation for input related actions.
@ -23,14 +23,14 @@ use super::*;
/// let pressed_char = input.read_char();
///
/// ```
pub struct TerminalInput<'terminal> {
pub struct TerminalInput {
terminal_input: Box<ITerminalInput>,
screen_manager: &'terminal ScreenManager,
stdout: Arc<Stdout>,
}
impl<'terminal> TerminalInput<'terminal> {
impl TerminalInput{
/// Create new instance of TerminalInput whereon input related actions could be preformed.
pub fn new(screen_manager: &'terminal ScreenManager) -> TerminalInput<'terminal> {
pub fn new(stdout: &Arc<Stdout>) -> TerminalInput {
#[cfg(target_os = "windows")]
let input = Box::from(WindowsInput::new());
@ -39,7 +39,7 @@ impl<'terminal> TerminalInput<'terminal> {
TerminalInput {
terminal_input: input,
screen_manager: screen_manager,
stdout: stdout.clone(),
}
}
@ -56,7 +56,7 @@ impl<'terminal> TerminalInput<'terminal> {
///
/// ```
pub fn read_line(&self) -> io::Result<String> {
self.terminal_input.read_line(&self.screen_manager)
self.terminal_input.read_line(&self.stdout)
}
/// Read one character from the user input
@ -72,7 +72,7 @@ impl<'terminal> TerminalInput<'terminal> {
///
/// ```
pub fn read_char(&self) -> io::Result<char> {
return self.terminal_input.read_char(&self.screen_manager);
return self.terminal_input.read_char(&self.stdout);
}
/// Read the input asynchronously from the user.
@ -104,7 +104,7 @@ impl<'terminal> TerminalInput<'terminal> {
///
/// ```
pub fn read_async(&self) -> AsyncReader {
self.terminal_input.read_async(&self.screen_manager)
self.terminal_input.read_async(&self.stdout)
}
/// Read the input asynchronously until a certain character is hit.
@ -144,11 +144,11 @@ impl<'terminal> TerminalInput<'terminal> {
/// ```
pub fn read_until_async(&self, delimiter: u8) -> AsyncReader {
self.terminal_input
.read_until_async(delimiter, &self.screen_manager)
.read_until_async(delimiter, &self.stdout)
}
}
/// Get an Terminal Input implementation whereon input related actions can be performed.
pub fn input(screen_manager: &ScreenManager) -> TerminalInput {
return TerminalInput::new(screen_manager);
pub fn input(stdout: &Screen) -> TerminalInput {
return TerminalInput::new(&stdout.stdout);
}

View File

@ -14,10 +14,11 @@ use self::unix_input::UnixInput;
use self::windows_input::WindowsInput;
pub use self::input::{input, TerminalInput};
use super::ScreenManager;
use super::Stdout;
use std::io::{self, Read};
use std::sync::mpsc;
use std::sync::{mpsc, Arc};
use Screen;
/// This trait defines the actions that can be preformed with the terminal color.
/// This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
@ -29,13 +30,13 @@ use std::sync::mpsc;
/// Unix is using the tty and windows is using libc C functions to read the input.
trait ITerminalInput {
/// Read one line from the user input
fn read_line(&self, screen_manger: &ScreenManager) -> io::Result<String>;
fn read_line(&self, screen_manger: &Arc<Stdout>) -> io::Result<String>;
/// Read one character from the user input
fn read_char(&self, screen_manger: &ScreenManager) -> io::Result<char>;
fn read_char(&self, screen_manger: &Arc<Stdout>) -> io::Result<char>;
/// Read the input asynchronously from the user.
fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader;
fn read_async(&self, screen_manger: &Arc<Stdout>) -> AsyncReader;
/// Read the input asynchronously until a certain character is hit.
fn read_until_async(&self, delimiter: u8, screen_manger: &ScreenManager) -> AsyncReader;
fn read_until_async(&self, delimiter: u8, screen_manger: &Arc<Stdout>) -> AsyncReader;
}
/// This is a wrapper for reading from the input asynchronously.

View File

@ -2,10 +2,10 @@
use std::char;
use std::io::{self, Read, Write};
use std::sync::mpsc;
use std::sync::{mpsc, Arc};
use std::thread;
use super::{AsyncReader, ITerminalInput, ScreenManager};
use super::{AsyncReader, ITerminalInput, Stdout};
use kernel::unix_kernel::terminal::{get_tty, read_char};
pub struct UnixInput;
@ -17,7 +17,7 @@ impl UnixInput {
}
impl ITerminalInput for UnixInput {
fn read_line(&self, screen_manger: &ScreenManager) -> io::Result<String> {
fn read_line(&self, screen_manger: &Stdout) -> io::Result<String> {
let mut rv = String::new();
io::stdin().read_line(&mut rv)?;
let len = rv.trim_right_matches(&['\r', '\n'][..]).len();
@ -25,11 +25,11 @@ impl ITerminalInput for UnixInput {
Ok(rv)
}
fn read_char(&self, screen_manger: &ScreenManager) -> io::Result<char> {
fn read_char(&self, screen_manger: &Arc<Stdout>) -> io::Result<char> {
read_char()
}
fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader {
fn read_async(&self, screen_manger: &Arc<Stdout>) -> AsyncReader {
let (send, recv) = mpsc::channel();
thread::spawn(move || {
@ -43,7 +43,7 @@ impl ITerminalInput for UnixInput {
AsyncReader { recv: recv }
}
fn read_until_async(&self, delimiter: u8, screen_manger: &ScreenManager) -> AsyncReader {
fn read_until_async(&self, delimiter: u8, screen_manger: &Arc<Stdout>) -> AsyncReader {
let (send, recv) = mpsc::channel();
thread::spawn(move || {

View File

@ -2,10 +2,10 @@
use std::char;
use std::io::{self, Write};
use std::sync::mpsc;
use std::sync::{mpsc, Arc};
use std::thread;
use super::{AsyncReader, ITerminalInput, ScreenManager};
use super::{AsyncReader, ITerminalInput, Stdout};
use winapi::um::winnt::INT;
use winapi::um::winuser;
@ -19,11 +19,11 @@ impl WindowsInput {
}
impl ITerminalInput for WindowsInput {
fn read_line(&self, screen_manger: &ScreenManager) -> io::Result<String> {
fn read_line(&self, screen_manger: &Arc<Stdout>) -> io::Result<String> {
let mut chars: Vec<char> = Vec::new();
loop {
let is_raw_screen = screen_manger.is_raw_screen();
let is_raw_screen = screen_manger.is_in_raw_mode;
// _getwch is without echo and _getwche is with echo
let pressed_char = unsafe {
@ -52,8 +52,8 @@ impl ITerminalInput for WindowsInput {
return Ok(chars.into_iter().collect());
}
fn read_char(&self, screen_manger: &ScreenManager) -> io::Result<char> {
let is_raw_screen = screen_manger.is_raw_screen();
fn read_char(&self, screen_manger: &Arc<Stdout>) -> io::Result<char> {
let is_raw_screen = screen_manger.is_in_raw_mode;
// _getwch is without echo and _getwche is with echo
let pressed_char = unsafe {
@ -83,10 +83,10 @@ impl ITerminalInput for WindowsInput {
}
}
fn read_async(&self, screen_manger: &ScreenManager) -> AsyncReader {
fn read_async(&self, screen_manger: &Arc<Stdout>) -> AsyncReader {
let (tx, rx) = mpsc::channel();
let is_raw_screen = screen_manger.is_raw_screen();
let is_raw_screen = screen_manger.is_in_raw_mode;
thread::spawn(move || {
loop {
@ -115,10 +115,10 @@ impl ITerminalInput for WindowsInput {
AsyncReader { recv: rx }
}
fn read_until_async(&self, delimiter: u8, screen_manger: &ScreenManager) -> AsyncReader {
fn read_until_async(&self, delimiter: u8, screen_manger: &Arc<Stdout>) -> AsyncReader {
let (tx, rx) = mpsc::channel();
let is_raw_screen = screen_manger.is_raw_screen();
let is_raw_screen = screen_manger.is_in_raw_mode;
thread::spawn(move || {
loop {

View File

@ -1,78 +0,0 @@
//! This is an ANSI specific implementation for the screen manager
//! This module is used for windows 10 terminals and unix terminals by default.
//! This module uses the stdout to write to the console.
use super::IScreenManager;
use std::any::Any;
use std::cell::RefCell;
use std::sync::{Arc,Mutex};
use std::io::{self, Read, Write,Stdout};
use std::str::from_utf8;
/// This struct is an ANSI escape code implementation for screen related actions.
pub struct AnsiScreenManager {
is_alternate_screen: bool,
is_raw_screen: bool,
output: Box<Stdout>,
}
impl IScreenManager for AnsiScreenManager {
fn set_is_raw_screen(&mut self, value: bool) {
self.is_raw_screen = value;
}
fn set_is_alternate_screen(&mut self, value: bool) {
self.is_alternate_screen = value;
}
fn is_raw_screen(&self) -> bool {
self.is_raw_screen
}
fn is_alternate_screen(&self) -> bool {
self.is_alternate_screen
}
fn write_str(&self, string: &str) -> io::Result<usize> {
let out = &self.output;
let mut handle = out.lock();
write!(handle, "{}", string)?;
Ok(0)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
{
let out = &self.output;
let mut handle = out.lock();
handle.write(buf)?;
}
Ok(0)
}
fn flush(&self) -> io::Result<()> {
let out = &self.output;
let mut handle = out.lock();
handle.flush();
Ok(())
}
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
impl AnsiScreenManager {
pub fn new() -> Self {
AnsiScreenManager {
output: Box::from(io::stdout()),
is_alternate_screen: false,
is_raw_screen: false,
}
}
}

View File

@ -1,90 +0,0 @@
use super::IScreenManager;
use kernel::windows_kernel::{handle, kernel, writing};
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
use winapi::um::winnt::HANDLE;
use std::ptr::NonNull;
use std::any::Any;
use std::io::{self, Write};
use std::sync::Arc;
/// This struct is an WINAPI implementation for screen related actions.
pub struct WinApiScreenManager {
is_alternate_screen: bool,
is_raw_screen: bool,
output: HANDLE,
alternate_handle: HANDLE,
}
impl IScreenManager for WinApiScreenManager {
fn set_is_raw_screen(&mut self, value: bool) {
self.is_raw_screen = value;
}
fn set_is_alternate_screen(&mut self, value: bool) {
self.is_alternate_screen = value;
}
fn is_raw_screen(&self) -> bool {
self.is_raw_screen
}
fn is_alternate_screen(&self) -> bool {
self.is_alternate_screen
}
fn write_str(&self, string: &str) -> io::Result<usize> {
self.write(string.as_bytes())
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
if self.is_alternate_screen {
writing::write_char_buffer(&self.alternate_handle, buf)
} else {
writing::write_char_buffer(&self.output, buf)
}
}
fn flush(&self) -> io::Result<()> {
Ok(())
}
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
// for winapi we have some custom implementation that will be used by windows only. You can get a reference to this implementation by using the `as_any()` and that cast it to this struct.
impl WinApiScreenManager {
/// Create a new instance.
pub fn new() -> Self {
WinApiScreenManager {
output: handle::get_output_handle().unwrap(),
alternate_handle: handle::get_output_handle().unwrap(),
is_alternate_screen: false,
is_raw_screen: false,
}
}
/// Set the alternate handle to the given handle.
pub fn set_alternate_handle(&mut self, alternate_handle: HANDLE) {
self.alternate_handle = alternate_handle;
// needs to be turned on so that escape characters like \n and \t will be processed.
kernel::set_console_mode(&self.alternate_handle, ENABLE_PROCESSED_OUTPUT as u32);
}
/// get the current screen handle.
pub fn get_handle(&self) -> &HANDLE {
if self.is_alternate_screen {
return &self.alternate_handle;
} else {
return &self.output;
}
}
}
unsafe impl Send for WinApiScreenManager {}

View File

@ -1,10 +1,12 @@
pub mod cursor;
pub mod input;
pub mod manager;
pub mod write;
pub mod style;
//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;

View File

@ -1,7 +1,7 @@
//! This is an ANSI specific implementation for styling related action.
//! This module is used for windows 10 terminals and unix terminals by default.
use super::{Color, ColorType, ITerminalColor, ScreenManager};
use std::sync::Arc;
use super::{Color, ColorType, ITerminalColor, Stdout};
/// This struct is an ANSI escape code implementation for color related actions.
pub struct AnsiColor;
@ -13,22 +13,22 @@ impl AnsiColor {
}
impl ITerminalColor for AnsiColor {
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager) {
screen_manager.write_string(format!(
fn set_fg(&self, fg_color: Color, stdout: &Arc<Stdout>) {
stdout.write_string(format!(
csi!("{}m"),
self.color_value(fg_color, ColorType::Foreground)
));
}
fn set_bg(&self, bg_color: Color, screen_manager: &ScreenManager) {
screen_manager.write_string(format!(
fn set_bg(&self, bg_color: Color, stdout: &Arc<Stdout>) {
stdout.write_string(format!(
csi!("{}m"),
self.color_value(bg_color, ColorType::Background)
));
}
fn reset(&self, screen_manager: &ScreenManager) {
screen_manager.write_str(csi!("0m"));
fn reset(&self, stdout: &Arc<Stdout>) {
stdout.write_str(csi!("0m"));
}
fn color_value(&self, color: Color, color_type: ColorType) -> String {

View File

@ -23,14 +23,14 @@ use std::io;
/// colored_terminal.reset();
///
/// ```
pub struct TerminalColor<'terminal> {
pub struct TerminalColor {
color: Box<ITerminalColor>,
screen_manager: &'terminal ScreenManager,
stdout: Arc<Stdout>,
}
impl<'terminal> TerminalColor<'terminal> {
impl<'terminal> TerminalColor {
/// Create new instance whereon color related actions can be performed.
pub fn new(screen_manager: &'terminal ScreenManager) -> TerminalColor<'terminal> {
pub fn new(stdout: &Arc<Stdout>) -> TerminalColor {
#[cfg(target_os = "windows")]
let color = functions::get_module::<Box<ITerminalColor>>(
Box::from(WinApiColor::new()),
@ -42,7 +42,7 @@ impl<'terminal> TerminalColor<'terminal> {
TerminalColor {
color,
screen_manager,
stdout: stdout.clone(),
}
}
@ -61,7 +61,7 @@ impl<'terminal> TerminalColor<'terminal> {
///
/// ```
pub fn set_fg(&self, color: Color) {
self.color.set_fg(color, &self.screen_manager);
self.color.set_fg(color, &self.stdout);
}
/// Set the background color to the given color.
@ -80,7 +80,7 @@ impl<'terminal> TerminalColor<'terminal> {
///
/// ```
pub fn set_bg(&self, color: Color) {
self.color.set_bg(color, &self.screen_manager);
self.color.set_bg(color, &self.stdout);
}
/// Reset the terminal colors and attributes to default.
@ -95,7 +95,7 @@ impl<'terminal> TerminalColor<'terminal> {
///
/// ```
pub fn reset(&self) {
self.color.reset(&self.screen_manager);
self.color.reset(&self.stdout);
}
/// Get available color count.
@ -116,6 +116,6 @@ impl<'terminal> TerminalColor<'terminal> {
}
/// Get an Terminal Color implementation whereon color related actions can be performed.
pub fn color(screen_manager: &ScreenManager) -> TerminalColor {
TerminalColor::new(screen_manager)
pub fn color(stdout: &Arc<Stdout>) -> TerminalColor {
TerminalColor::new(stdout)
}

View File

@ -14,11 +14,12 @@ use self::winapi_color::WinApiColor;
use std::convert::From;
use std::str::FromStr;
use std::sync::Arc;
pub use self::color::TerminalColor;
pub use self::objectstyle::ObjectStyle;
pub use self::styledobject::StyledObject;
use super::{functions, ScreenManager};
use super::{functions, Stdout};
/// This trait defines the actions that can be preformed with the terminal color.
/// This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
@ -30,11 +31,11 @@ use super::{functions, ScreenManager};
/// so that color related actions can be preformed on both unix and windows systems.
pub trait ITerminalColor {
/// Set the foreground color to the given color.
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager);
fn set_fg(&self, fg_color: Color, stdout: &Arc<Stdout>);
/// Set the background color to the given color.
fn set_bg(&self, fg_color: Color, screen_manager: &ScreenManager);
fn set_bg(&self, fg_color: Color, stdout: &Arc<Stdout>);
/// Reset the terminal color to default.
fn reset(&self, screen_manager: &ScreenManager);
fn reset(&self, stdout: &Arc<Stdout>);
/// Gets an value that represents an color from the given `Color` and `ColorType`.
fn color_value(&self, color: Color, color_type: ColorType) -> String;
}

View File

@ -1,8 +1,9 @@
//! This module contains the `object style` that can be applied to an `styled object`.
use super::{Color, ScreenManager, StyledObject};
use super::{Color, Stdout, StyledObject};
use std::fmt::Display;
use std::sync::Arc;
#[cfg(unix)]
use super::Attribute;
@ -30,14 +31,12 @@ impl Default for ObjectStyle {
impl ObjectStyle {
/// Apply an `StyledObject` to the passed displayable object.
pub fn apply_to<'style, D: Display>(
pub fn apply_to<D: Display>(
&self,
val: D,
screen_manager: &'style ScreenManager,
) -> StyledObject<'style, D> {
) -> StyledObject<D> {
StyledObject {
object_style: self.clone(),
screen_manager: screen_manager,
content: val,
}
}

View File

@ -1,6 +1,7 @@
//! This module contains the logic to style an object that contains some state witch can be styled.
use super::{Color, ObjectStyle, ScreenManager};
use super::{Color, ObjectStyle, Stdout};
use Screen;
use std::fmt::{self, Display};
use std::io::Write;
@ -9,16 +10,15 @@ use std::io::Write;
use super::Attribute;
#[cfg(windows)]
use super::super::super::manager::WinApiScreenManager;
use super::super::super::write::WinApiStdout;
/// Struct that contains both the style and the content wits can be styled.
pub struct StyledObject<'terminal, D: Display> {
pub struct StyledObject<D: Display> {
pub object_style: ObjectStyle,
pub content: D,
pub screen_manager: &'terminal ScreenManager,
}
impl<'terminal, D: Display> StyledObject<'terminal, D> {
impl<D: Display> StyledObject<D> {
/// Set the foreground of the styled object to the passed `Color`
///
/// #Example
@ -39,7 +39,7 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
/// println!("{}", paint("I am colored green").with(Color::Green));
///
/// ```
pub fn with(mut self, foreground_color: Color) -> StyledObject<'terminal, D> {
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.fg(foreground_color);
self
}
@ -64,7 +64,7 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
/// println!("{}", paint("I am colored green").on(Color::Green))
///
/// ```
pub fn on(mut self, background_color: Color) -> StyledObject<'terminal, D> {
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.bg(background_color);
self
}
@ -82,7 +82,7 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
///
/// ```
#[cfg(unix)]
pub fn attr(mut self, attr: Attribute) -> StyledObject<'terminal, D> {
pub fn attr(mut self, attr: Attribute) -> StyledObject<D> {
&self.object_style.add_attr(attr);
self
}
@ -90,62 +90,61 @@ impl<'terminal, D: Display> StyledObject<'terminal, D> {
/// Increase the font intensity.
#[cfg(unix)]
#[inline(always)]
pub fn bold(self) -> StyledObject<'terminal, D> {
pub fn bold(self) -> StyledObject<D> {
self.attr(Attribute::Bold)
}
/// Faint (decreased intensity) (Not widely supported).
#[cfg(unix)]
#[inline(always)]
pub fn dim(self) -> StyledObject<'terminal, D> {
pub fn dim(self) -> StyledObject<D> {
self.attr(Attribute::Dim)
}
/// Make the font italic (Not widely supported; Sometimes treated as inverse).
#[cfg(unix)]
#[inline(always)]
pub fn italic(self) -> StyledObject<'terminal, D> {
pub fn italic(self) -> StyledObject<D> {
self.attr(Attribute::Italic)
}
/// Underline font.
#[cfg(unix)]
#[inline(always)]
pub fn underlined(self) -> StyledObject<'terminal, D> {
pub fn underlined(self) -> StyledObject<D> {
self.attr(Attribute::Underlined)
}
/// Slow Blink (less than 150 per minute; not widely supported).
#[cfg(unix)]
#[inline(always)]
pub fn slow_blink(self) -> StyledObject<'terminal, D> {
pub fn slow_blink(self) -> StyledObject<D> {
self.attr(Attribute::SlowBlink)
}
/// Rapid Blink (MS-DOS ANSI.SYS; 150+ per minute; not widely supported).
#[cfg(unix)]
#[inline(always)]
pub fn rapid_blink(self) -> StyledObject<'terminal, D> {
pub fn rapid_blink(self) -> StyledObject<D> {
self.attr(Attribute::RapidBlink)
}
/// Swap foreground and background colors.
#[cfg(unix)]
#[inline(always)]
pub fn reverse(self) -> StyledObject<'terminal, D> {
pub fn reverse(self) -> StyledObject<D> {
self.attr(Attribute::Reverse)
}
/// Hide text (Not widely supported).
#[cfg(unix)]
#[inline(always)]
pub fn hidden(self) -> StyledObject<'terminal, D> {
pub fn hidden(self) -> StyledObject<D> {
self.attr(Attribute::Hidden)
}
/// Characters legible, but marked for deletion. Not widely supported.
#[cfg(unix)]
#[inline(always)]
pub fn crossed_out(self) -> StyledObject<'terminal, D> {
pub fn crossed_out(self) -> StyledObject<D> {
self.attr(Attribute::CrossedOut)
}
}
impl<'terminal, D: Display> Display for StyledObject<'terminal, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut colored_terminal = super::super::super::style::color::color(self.screen_manager);
pub fn paint(&self, screen: &Screen)
{
let mut colored_terminal = super::super::super::style::color::color(&screen.stdout);
let mut reset = true;
if let Some(bg) = self.object_style.bg_color {
@ -160,21 +159,19 @@ impl<'terminal, D: Display> Display for StyledObject<'terminal, D> {
#[cfg(unix)]
for attr in self.object_style.attrs.iter() {
self.screen_manager
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(())
}
}

View File

@ -3,11 +3,13 @@
//!
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
use super::super::super::manager::WinApiScreenManager;
use super::{Color, ColorType, ITerminalColor, ScreenManager};
use super::super::super::write::WinApiStdout;
use super::{Color, ColorType, ITerminalColor, Stdout};
use kernel::windows_kernel::{csbi, kernel};
use winapi::um::wincon;
use std::sync::Arc;
/// This struct is an windows implementation for color related actions.
pub struct WinApiColor;
@ -18,10 +20,10 @@ impl WinApiColor {
}
impl ITerminalColor for WinApiColor {
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager) {
fn set_fg(&self, fg_color: Color, stdout: &Arc<Stdout>) {
let color_value = &self.color_value(fg_color, ColorType::Foreground);
let csbi = csbi::get_csbi(screen_manager).unwrap();
let csbi = csbi::get_csbi(stdout).unwrap();
// Notice that the color values are stored in wAttribute.
// So we need to use bitwise operators to check if the values exists or to get current console colors.
@ -36,13 +38,13 @@ impl ITerminalColor for WinApiColor {
color = color | wincon::BACKGROUND_INTENSITY as u16;
}
kernel::set_console_text_attribute(color, screen_manager);
kernel::set_console_text_attribute(color, stdout);
}
fn set_bg(&self, bg_color: Color, screen_manager: &ScreenManager) {
fn set_bg(&self, bg_color: Color, stdout: &Arc<Stdout>) {
let color_value = &self.color_value(bg_color, ColorType::Background);
let (csbi, handle) = csbi::get_csbi_and_handle(screen_manager).unwrap();
let (csbi, handle) = csbi::get_csbi_and_handle(stdout).unwrap();
// Notice that the color values are stored in wAttribute.
// So wee need to use bitwise operators to check if the values exists or to get current console colors.
@ -57,12 +59,12 @@ impl ITerminalColor for WinApiColor {
color = color | wincon::FOREGROUND_INTENSITY as u16;
}
kernel::set_console_text_attribute(color, screen_manager);
kernel::set_console_text_attribute(color, stdout);
}
fn reset(&self, screen_manager: &ScreenManager) {
self.set_bg(Color::Black, screen_manager);
self.set_fg(Color::White, screen_manager);
fn reset(&self, stdout: &Arc<Stdout>) {
self.set_bg(Color::Black, stdout);
self.set_fg(Color::White, stdout);
}
/// This will get the winapi color value from the Color and ColorType struct

View File

@ -2,7 +2,7 @@
//! This module is used for windows 10 terminals and unix terminals by default.
use super::super::cursor::cursor;
use super::{functions, ClearType, ITerminal, ScreenManager};
use super::*;
/// This struct is an ansi escape code implementation for terminal related actions.
pub struct AnsiTerminal;
@ -14,7 +14,7 @@ impl AnsiTerminal {
}
impl ITerminal for AnsiTerminal {
fn clear(&self, clear_type: ClearType, screen_manager: &ScreenManager) {
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>) {
match clear_type {
ClearType::All => {
screen_manager.write_str(csi!("2J"));
@ -34,19 +34,19 @@ impl ITerminal for AnsiTerminal {
};
}
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16) {
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
functions::get_terminal_size()
}
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) {
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{}S"), count));
}
fn scroll_down(&self, count: i16, screen_manager: &ScreenManager) {
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("{}T"), count));
}
fn set_size(&self, width: i16, height: i16, screen_manager: &ScreenManager) {
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>) {
screen_manager.write_string(format!(csi!("8;{};{}t"), width, height));
}

View File

@ -10,8 +10,10 @@ use self::ansi_terminal::AnsiTerminal;
#[cfg(target_os = "windows")]
use self::winapi_terminal::WinApiTerminal;
pub use self::terminal::Terminal;
use super::{functions, ScreenManager};
pub use self::terminal::{terminal, Terminal};
use super::{functions, Stdout};
use std::sync::Arc;
use Screen;
/// Enum that specifies a way of clearing.
pub enum ClearType {
@ -32,15 +34,15 @@ pub enum ClearType {
/// so that color related actions can be preformed on both unix and windows systems.
pub trait ITerminal {
/// Clear the current cursor by specifying the clear type
fn clear(&self, clear_type: ClearType, screen_manager: &ScreenManager);
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>);
/// Get the terminal size (x,y)
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16);
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16);
/// Scroll `n` lines up in the current terminal.
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager);
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>);
/// Scroll `n` lines down in the current terminal.
fn scroll_down(&self, count: i16, screen_manager: &ScreenManager);
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>);
/// Resize terminal to the given width and height.
fn set_size(&self, width: i16, height: i16, screen_manager: &ScreenManager);
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>);
/// Close the current terminal
fn exit(&self);
}

View File

@ -22,14 +22,14 @@ use std::io::Write;
/// let (with, height) = term.terminal_size();
///
/// ```
pub struct Terminal<'terminal> {
pub struct Terminal {
terminal: Box<ITerminal>,
screen_manager: &'terminal ScreenManager,
screen: Arc<Stdout>,
}
impl<'terminal> Terminal<'terminal> {
impl Terminal {
/// Create new terminal instance whereon terminal related actions can be performed.
pub fn new(screen_manager: &'terminal ScreenManager) -> Terminal<'terminal> {
pub fn new(screen: &Arc<Stdout>) -> Terminal {
#[cfg(target_os = "windows")]
let terminal = functions::get_module::<Box<ITerminal>>(
Box::new(WinApiTerminal::new()),
@ -41,7 +41,7 @@ impl<'terminal> Terminal<'terminal> {
Terminal {
terminal,
screen_manager: screen_manager,
screen: screen.clone(),
}
}
@ -66,8 +66,8 @@ impl<'terminal> Terminal<'terminal> {
/// term.clear(terminal::ClearType::UntilNewLine);
///
/// ```
pub fn clear(&mut self, clear_type: ClearType) {
self.terminal.clear(clear_type, &mut self.screen_manager);
pub fn clear(&self, clear_type: ClearType) {
self.terminal.clear(clear_type, &self.screen);
}
/// Get the terminal size (x,y).
@ -88,7 +88,7 @@ impl<'terminal> Terminal<'terminal> {
///
/// ```
pub fn terminal_size(&self) -> (u16, u16) {
return self.terminal.terminal_size(&self.screen_manager);
return self.terminal.terminal_size(&self.screen);
}
/// Scroll `n` lines up in the current terminal.
@ -105,7 +105,7 @@ impl<'terminal> Terminal<'terminal> {
///
/// ```
pub fn scroll_up(&self, count: i16) {
self.terminal.scroll_up(count, &self.screen_manager);
self.terminal.scroll_up(count, &self.screen);
}
/// Scroll `n` lines up in the current terminal.
@ -122,7 +122,7 @@ impl<'terminal> Terminal<'terminal> {
///
/// ```
pub fn scroll_down(&self, count: i16) {
self.terminal.scroll_down(count, &self.screen_manager);
self.terminal.scroll_down(count, &self.screen);
}
/// Set the terminal size. Note that not all terminals can be set to a very small scale.
@ -139,7 +139,7 @@ impl<'terminal> Terminal<'terminal> {
///
/// ```
pub fn set_size(&self, width: i16, height: i16) {
self.terminal.set_size(width, height, &self.screen_manager);
self.terminal.set_size(width, height, &self.screen);
}
/// Exit the current process.
@ -174,11 +174,11 @@ impl<'terminal> Terminal<'terminal> {
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", value).unwrap();
self.screen_manager.write_string(string);
self.screen.write_string(string);
}
}
/// Get an terminal implementation whereon terminal related actions could performed
pub fn terminal(screen_manager: &mut ScreenManager) -> Terminal {
Terminal::new(screen_manager)
pub fn terminal(screen: &Screen) -> Terminal {
Terminal::new(&screen.stdout)
}

View File

@ -3,8 +3,8 @@
//!
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
use super::super::super::cursor::cursor;
use super::{functions, ClearType, ITerminal, ScreenManager};
use super::super::super::cursor::TerminalCursor;
use super::*;
use kernel::windows_kernel::{csbi, kernel, terminal, writing};
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
@ -18,9 +18,9 @@ impl WinApiTerminal {
}
impl ITerminal for WinApiTerminal {
fn clear(&self, clear_type: ClearType, screen_manager: &ScreenManager) {
fn clear(&self, clear_type: ClearType, screen_manager: &Arc<Stdout>) {
let csbi = csbi::get_csbi(screen_manager).unwrap();
let pos = cursor(screen_manager).pos();
let pos = TerminalCursor::new(screen_manager).pos();
match clear_type {
ClearType::All => {
@ -33,11 +33,11 @@ impl ITerminal for WinApiTerminal {
};
}
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16) {
fn terminal_size(&self, screen_manager: &Arc<Stdout>) -> (u16, u16) {
terminal::terminal_size()
}
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) {
fn scroll_up(&self, count: i16, screen_manager: &Arc<Stdout>) {
let csbi = csbi::get_csbi(&screen_manager).unwrap();
// Set srctWindow to the current window size and location.
@ -55,7 +55,7 @@ impl ITerminal for WinApiTerminal {
}
}
fn scroll_down(&self, count: i16, screen_manager: &ScreenManager) {
fn scroll_down(&self, count: i16, screen_manager: &Arc<Stdout>) {
let csbi = csbi::get_csbi(&screen_manager).unwrap();
// Set srctWindow to the current window size and location.
let mut srct_window = csbi.srWindow;
@ -76,7 +76,7 @@ impl ITerminal for WinApiTerminal {
}
/// Set the current terminal size
fn set_size(&self, width: i16, height: i16, screen_manager: &ScreenManager) {
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>) {
if width <= 0 {
panic!("Cannot set the terminal width lower than 1");
}
@ -160,7 +160,7 @@ impl ITerminal for WinApiTerminal {
pub fn clear_after_cursor(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) {
let (mut x, mut y) = pos;
@ -184,7 +184,7 @@ pub fn clear_after_cursor(
pub fn clear_before_cursor(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) {
let (xpos, ypos) = pos;
@ -204,7 +204,7 @@ pub fn clear_before_cursor(
clear(start_location, cells_to_write, screen_manager);
}
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &ScreenManager) {
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &Arc<Stdout>) {
// position x at start
let x = 0;
// position y at start
@ -222,13 +222,13 @@ pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, screen_manager: &Sc
clear(start_location, cells_to_write, &screen_manager);
// put the cursor back at (0, 0)
cursor(screen_manager).goto(0, 0);
TerminalCursor::new(screen_manager).goto(0, 0);
}
pub fn clear_current_line(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) {
// position x at start
let x = 0;
@ -247,13 +247,13 @@ pub fn clear_current_line(
clear(start_location, cells_to_write, screen_manager);
// put the cursor back at 1 cell on current row
cursor(screen_manager).goto(0, y);
TerminalCursor::new(screen_manager).goto(0, y);
}
pub fn clear_until_line(
pos: (u16, u16),
csbi: CONSOLE_SCREEN_BUFFER_INFO,
screen_manager: &ScreenManager,
screen_manager: &Arc<Stdout>,
) {
let (x, y) = pos;
@ -268,10 +268,10 @@ pub fn clear_until_line(
clear(start_location, cells_to_write, &screen_manager);
// put the cursor back at original cursor position
cursor(screen_manager).goto(x, y);
TerminalCursor::new(screen_manager).goto(x, y);
}
fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &ScreenManager) {
fn clear(start_loaction: COORD, cells_to_write: u32, screen_manager: &Arc<Stdout>) {
let mut cells_written = 0;
let mut success = false;

View File

@ -0,0 +1,55 @@
//! This is an ANSI specific implementation for the screen write
//! This module is used for windows 10 terminals and unix terminals by default.
//! This module uses the stdout to write to the console.
use super::IStdout;
use std::any::Any;
use std::cell::RefCell;
use std::sync::{Arc,Mutex};
use std::io::{self, Read, Write,Stdout, stdout};
use std::str::from_utf8;
/// This struct is an ANSI escape code implementation for screen related actions.
pub struct AnsiStdout {
pub handle: Stdout,
}
impl IStdout for AnsiStdout {
fn write_str(&self, string: &str) -> io::Result<usize> {
let out = &self.handle;
let mut handle = out.lock();
write!(handle, "{}", string)?;
handle.flush();
Ok(0)
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
let out = &self.handle;
let mut handle = out.lock();
handle.write(buf)?;
Ok(0)
}
fn flush(&self) -> io::Result<()> {
let out = &self.handle;
let mut handle = out.lock();
handle.flush();
Ok(())
}
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
impl AnsiStdout {
pub fn new() -> Self {
AnsiStdout { handle: stdout() }
}
}

View File

@ -18,22 +18,23 @@
//!
//! This is the reason why this module exits: it is to provide access to the current terminal screen whether it will be the alternate screen and main screen.
mod manager;
mod stdout;
mod ansi_manager;
mod ansi_stdout;
#[cfg(target_os = "windows")]
mod win_manager;
mod winapi_stdout;
pub use self::ansi_manager::AnsiScreenManager;
pub use self::ansi_stdout::AnsiStdout;
#[cfg(target_os = "windows")]
pub use self::win_manager::WinApiScreenManager;
pub use self::winapi_stdout::WinApiStdout;
pub use self::manager::ScreenManager;
use super::functions;
pub use self::stdout::Stdout;
use std::any::Any;
use std::io;
use super::{functions};
/// This trait defines the actions that could be preformed on the current screen.
/// This trait can be implemented so that an concrete implementation of the IScreenManager can forfill
/// the wishes to work on an specific platform.
@ -42,21 +43,15 @@ use std::io;
///
/// This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
/// so that color related actions can be preformed on both unix and windows systems.
pub trait IScreenManager {
fn set_is_raw_screen(&mut self, value: bool);
fn set_is_alternate_screen(&mut self, value: bool);
fn is_raw_screen(&self) -> bool;
fn is_alternate_screen(&self) -> bool;
pub trait IStdout {
/// Write a &str to the current stdout.
fn write_str(&self, string: &str ) -> io::Result<usize>;
/// Write [u8] buffer to console.
fn write(&self, buf: &[u8]) -> io::Result<usize>;
/// Flush the current output.
fn flush(&self) -> io::Result<()>;
/// Can be used to convert to an specific IScreenManager implementation.
fn as_any(&self) -> &Any;
/// Can be used to convert to an specific mutable IScreenManager implementation.
fn as_any_mut(&mut self) -> &mut Any;
}

View File

@ -27,45 +27,31 @@ use std::io::{self, Write};
#[cfg(target_os = "windows")]
use winapi::um::winnt::HANDLE;
use std::sync::Arc;
/// Struct that stores an specific platform implementation for screen related actions.
pub struct ScreenManager {
screen_manager: Box<IScreenManager + Send>,
pub struct Stdout {
screen_manager: Box<IStdout + Send>,
pub is_in_raw_mode:bool,
}
impl ScreenManager {
/// Create new screen manager instance whereon screen related actions can be performed.
pub fn new() -> ScreenManager {
// todo: impl Default for stdout
impl Stdout {
/// Create new screen write instance whereon screen related actions can be performed.
pub fn new(is_in_raw_mode: bool) -> Self {
#[cfg(target_os = "windows")]
let screen_manager = functions::get_module::<Box<IScreenManager + Send>>(
Box::from(WinApiScreenManager::new()),
Box::from(AnsiScreenManager::new()),
let screen_manager = functions::get_module::<Box<IStdout + Send>>(
Box::from(WinApiStdout::new()),
Box::from(AnsiStdout::new()),
).unwrap();
#[cfg(not(target_os = "windows"))]
let screen_manager = Box::from(AnsiScreenManager::new()) as Box<IScreenManager + Send>;
let screen_manager = Box::from(AnsiStdout::new()) as Box<IStdout + Send>;
ScreenManager { screen_manager }
Stdout { screen_manager , is_in_raw_mode}
}
/// Set whether screen is raw screen.
pub fn set_is_raw_screen(&mut self, value: bool) {
self.screen_manager.set_is_raw_screen(value);
}
/// Set whether the current screen is alternate screen.
pub fn set_is_alternate_screen(&mut self, value: bool) {
self.screen_manager.set_is_alternate_screen(value);
}
/// Check if the current screen is in rawscreen modes
pub fn is_raw_screen(&self) -> bool {
self.screen_manager.is_raw_screen()
}
/// Check if the current screen is in alternate modes.
pub fn is_alternate_screen(&self) -> bool {
self.screen_manager.is_alternate_screen()
}
/// Write String to the current screen.
pub fn write_string(&self, string: String) -> io::Result<usize> {
@ -86,12 +72,10 @@ impl ScreenManager {
self.screen_manager.write(buf)
}
/// Can be used to get an reference to an specific implementation used for the current platform.
pub fn as_any(&self) -> &Any {
self.screen_manager.as_any()
}
/// Can be used to get an mutable reference to an specific implementation used for the current platform.
pub fn as_any_mut(&mut self) -> &mut Any {
self.screen_manager.as_any_mut()
}

View File

@ -0,0 +1,56 @@
use super::IStdout;
use kernel::windows_kernel::{handle, kernel, writing};
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
use winapi::um::winnt::HANDLE;
use std::ptr::NonNull;
use std::any::Any;
use std::io::{self, Write};
use std::sync::Arc;
/// This struct is an WINAPI implementation for screen related actions.
pub struct WinApiStdout {
pub handle: HANDLE,
}
impl IStdout for WinApiStdout {
fn write_str(&self, string: &str) -> io::Result<usize> {
self.write(string.as_bytes())
}
fn write(&self, buf: &[u8]) -> io::Result<usize> {
writing::write_char_buffer(&self.handle, buf)
}
fn flush(&self) -> io::Result<()> {
Ok(())
}
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
impl WinApiStdout {
pub fn new() -> Self {
WinApiStdout { handle: handle::get_output_handle().unwrap() }
}
pub fn set(&mut self, handle: HANDLE)
{
self.handle = handle;
}
pub fn get_handle(&self) -> &HANDLE
{
return &self.handle;
}
}
unsafe impl Send for WinApiStdout {}

View File

@ -1,6 +0,0 @@
[package]
name = "write_test"
version = "0.1.0"
authors = ["TimonPost <timonpost@hotmail.nl>"]
[dependencies]

View File

@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}