maked crossterm sendable for threads

This commit is contained in:
TimonPost 2018-07-31 23:05:45 +02:00
parent 14ecd33f11
commit 406f2046f9
13 changed files with 94 additions and 65 deletions

View File

@ -22,13 +22,13 @@ pub trait IEnableAnsiCommand {
fn disable(&mut self) -> bool; fn disable(&mut self) -> bool;
} }
/// This trait provides an interface for switching to alternate screen and back. // This trait provides an interface for switching to alternate screen and back.
/*pub trait IAlternateScreenCommand: Send{ pub trait IAlternateScreenCommand: Send {
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()>; fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()>;
fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()>; fn disable(&self, screen_manager: &mut ScreenManager) -> Result<()>;
}*/ }
/// This trait provides an interface for switching to raw mode and back. // This trait provides an interface for switching to raw mode and back.
/*pub trait IRawScreenCommand: Send{ /*pub trait IRawScreenCommand: Send{
fn enable(&mut self) -> Result<()>; fn enable(&mut self) -> Result<()>;
fn disable(&mut self) -> Result<()>; fn disable(&mut self) -> Result<()>;

View File

@ -1,6 +1,6 @@
//! This module contains the commands that can be used for unix systems. //! This module contains the commands that can be used for unix systems.
use super::{IRawScreenCommand, IStateCommand}; use super::{ IStateCommand};
use kernel::unix_kernel::terminal; use kernel::unix_kernel::terminal;
use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH}; use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH};

View File

@ -1,6 +1,6 @@
//! This module contains the commands that can be used for windows systems. //! This module contains the commands that can be used for windows systems.
use super::{IAlternateScreenCommand, IEnableAnsiCommand, IRawScreenCommand, ScreenManager}; use super::{IAlternateScreenCommand, IEnableAnsiCommand, ScreenManager};
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel}; use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
use std::mem; use std::mem;
@ -142,7 +142,7 @@ impl ToAlternateScreenCommand {
} }
} }
impl IAlternateScreenCommand for ToAlternateScreenCommand { impl IAlternateScreenCommand for ToAlternateScreenCommand {
fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> { fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> {
use super::super::super::manager::WinApiScreenManager; use super::super::super::manager::WinApiScreenManager;

View File

@ -1,7 +1,6 @@
use super::commands::{IAlternateScreenCommand, IRawScreenCommand}; use super::commands::{IAlternateScreenCommand};
use super::screen::AlternateScreen; use super::screen::AlternateScreen;
use super::screen::RawScreen;
use super::super::cursor; use super::super::cursor;
use super::super::input; use super::super::input;
@ -14,12 +13,23 @@ use std::io::Write;
use std::io::Result; use std::io::Result;
#[cfg(not(windows))]
use common::commands::unix_command;
#[cfg(windows)]
use common::commands::win_commands;
pub struct Crossterm { pub struct Crossterm {
pub active_screen: manager::ScreenManager, pub active_screen: manager::ScreenManager,
raw_terminal: Option<RawScreenCommand>,
#[cfg(not(windows))]
raw_terminal: Option<unix_command::RawModeCommand>,
#[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. // 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. // For windows this would be easy but for unix I have no idea.
alternate_screen: Option<AlternateScreenCommand>, alternate_screen: Option<Box<IAlternateScreenCommand + Send>>,
} }
impl<'a> Crossterm { impl<'a> Crossterm {
@ -34,7 +44,13 @@ impl<'a> Crossterm {
pub fn enable_raw_mode(&mut self) -> Result<()> { pub fn enable_raw_mode(&mut self) -> Result<()> {
match self.raw_terminal { match self.raw_terminal {
None => { None => {
self.raw_terminal = Some(RawScreen::new()); #[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(); return self.enable_raw_mode();
} }
Some(ref mut raw_terminal) => { Some(ref mut raw_terminal) => {
@ -48,7 +64,13 @@ impl<'a> Crossterm {
pub fn disable_raw_mode(&mut self) -> Result<()> { pub fn disable_raw_mode(&mut self) -> Result<()> {
match self.raw_terminal { match self.raw_terminal {
None => { None => {
self.raw_terminal = Some(RawScreen::new());
#[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(); return self.disable_raw_mode();
} }
Some(ref mut raw_terminal) => { Some(ref mut raw_terminal) => {

View File

@ -53,7 +53,7 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
// Try to enable ansi on windows if not than use WINAPI. // Try to enable ansi on windows if not than use WINAPI.
does_support = try_enable_ansi_support(); does_support = try_enable_ansi_support();
// does_support = false; // does_support = false;
if !does_support { if !does_support {
term = Some(winapi_impl); term = Some(winapi_impl);
} }

View File

@ -32,9 +32,9 @@ pub struct AlternateScreen;
impl AlternateScreen { impl AlternateScreen {
/// Create an new alternate screen type. /// Create an new alternate screen type.
pub fn new() -> Box<commands::IAlternateScreenCommand> { pub fn new() -> Box<commands::IAlternateScreenCommand + Send> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let command = functions::get_module::<Box<commands::IAlternateScreenCommand>>( let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Send>>(
Box::from(commands::win_commands::ToAlternateScreenCommand::new()), Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
Box::from(commands::shared_commands::ToAlternateScreenCommand::new()), Box::from(commands::shared_commands::ToAlternateScreenCommand::new()),
).unwrap(); ).unwrap();

View File

@ -6,4 +6,4 @@ mod raw;
use super::{commands, functions, ScreenManager}; use super::{commands, functions, ScreenManager};
pub use self::alternate::AlternateScreen; pub use self::alternate::AlternateScreen;
pub use self::raw::RawScreen; //pub use self::raw::RawScreen;

View File

@ -12,28 +12,23 @@
//! //!
//! With these modes you can easier design the terminal screen. //! With these modes you can easier design the terminal screen.
#[cfg(not(windows))] //
use common::commands::unix_command::EnableRawModeCommand; //use super::commands;
//use super::{functions, ScreenManager};
#[cfg(windows)] //
use common::commands::win_commands::EnableRawModeCommand; //use std::io::{self, Write};
//
use super::commands; ///// A wrapper for the raw terminal state. Which can be used to write to.
use super::{functions, ScreenManager}; //pub struct RawScreen;
//
use std::io::{self, Write}; //impl RawScreen {
// /// Create a new RawScreen type.
/// A wrapper for the raw terminal state. Which can be used to write to. // pub fn new() -> Box<commands::IRawScreenCommand> {
pub struct RawScreen; // Box::from(EnableRawModeCommand::new())
// }
impl RawScreen {
/// Create a new RawScreen type.
pub fn new() -> Box<commands::IRawScreenCommand> {
Box::from(EnableRawModeCommand::new())
}
}
///// Trait withs contains a method for switching into raw mode.
//pub trait IntoRawMode: Write + Sized {
// fn into_raw_mode(&self, context: Rc<Context>) -> io::Result<RawTerminal>;
//} //}
//
/////// Trait withs contains a method for switching into raw mode.
////pub trait IntoRawMode: Write + Sized {
//// fn into_raw_mode(&self, context: Rc<Context>) -> io::Result<RawTerminal>;
////}

View File

@ -4,11 +4,9 @@ use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processenv::GetStdHandle; use winapi::um::processenv::GetStdHandle;
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE}; use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
use winapi::um::winnt::HANDLE; use winapi::um::winnt::HANDLE;
use std::sync::Arc;
use super::super::super::manager::{ScreenManager, WinApiScreenManager}; use super::super::super::manager::{ScreenManager, WinApiScreenManager};
use std::io::{self, ErrorKind, Result};
/// Get the global stored handle whits provides access to the current screen. /// 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: &ScreenManager) -> Result<HANDLE> {
let mut mutex = screen_manager; let mut mutex = screen_manager;
@ -16,18 +14,21 @@ pub fn get_current_handle(screen_manager: &ScreenManager) -> Result<HANDLE> {
let handle: Result<HANDLE>; let handle: Result<HANDLE>;
let winapi_screen_manager: &WinApiScreenManager = match screen_manager let winapi_screen_manager: &WinApiScreenManager = match screen_manager
.as_any() .as_any()
.downcast_ref::<WinApiScreenManager>() .downcast_ref::<WinApiScreenManager>()
{ {
Some(win_api) => win_api, 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 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'"))
}; };
handle = Ok(*winapi_screen_manager.get_handle()); handle = Ok(*winapi_screen_manager.get_handle());
return handle; return handle;
} }
use std::io::{self, ErrorKind, Result};
/// Get the std_output_handle of the console /// Get the std_output_handle of the console
pub fn get_output_handle() -> Result<HANDLE> { pub fn get_output_handle() -> Result<HANDLE> {
unsafe { unsafe {

View File

@ -6,14 +6,15 @@ use super::IScreenManager;
use std::any::Any; use std::any::Any;
use std::cell::RefCell; use std::cell::RefCell;
use std::io::{self, Read, Write}; use std::sync::{Arc,Mutex};
use std::io::{self, Read, Write,Stdout};
use std::str::from_utf8; use std::str::from_utf8;
/// This struct is an ANSI escape code implementation for screen related actions. /// This struct is an ANSI escape code implementation for screen related actions.
pub struct AnsiScreenManager { pub struct AnsiScreenManager {
is_alternate_screen: bool, is_alternate_screen: bool,
is_raw_screen: bool, is_raw_screen: bool,
output: RefCell<Box<Write>>, output: Box<Stdout>,
} }
impl IScreenManager for AnsiScreenManager { impl IScreenManager for AnsiScreenManager {
@ -34,22 +35,27 @@ impl IScreenManager for AnsiScreenManager {
} }
fn write_str(&self, string: &str) -> io::Result<usize> { fn write_str(&self, string: &str) -> io::Result<usize> {
let mut output = self.output.borrow_mut(); let out = &self.output;
write!(output, "{}", string)?; let mut handle = out.lock();
write!(handle, "{}", string)?;
Ok(0) Ok(0)
} }
fn write(&self, buf: &[u8]) -> io::Result<usize> { fn write(&self, buf: &[u8]) -> io::Result<usize> {
{ {
let mut output = self.output.borrow_mut(); let out = &self.output;
output.write(buf)?; let mut handle = out.lock();
handle.write(buf)?;
} }
Ok(0) Ok(0)
} }
fn flush(&self) -> io::Result<()> { fn flush(&self) -> io::Result<()> {
let mut output = self.output.borrow_mut(); let out = &self.output;
output.flush() let mut handle = out.lock();
handle.flush();
Ok(())
} }
fn as_any(&self) -> &Any { fn as_any(&self) -> &Any {
@ -64,7 +70,7 @@ impl IScreenManager for AnsiScreenManager {
impl AnsiScreenManager { impl AnsiScreenManager {
pub fn new() -> Self { pub fn new() -> Self {
AnsiScreenManager { AnsiScreenManager {
output: RefCell::new(Box::from(io::stdout()) as Box<Write>), output: Box::from(io::stdout()),
is_alternate_screen: false, is_alternate_screen: false,
is_raw_screen: false, is_raw_screen: false,
} }

View File

@ -36,13 +36,13 @@ impl ScreenManager {
/// Create new screen manager instance whereon screen related actions can be performed. /// Create new screen manager instance whereon screen related actions can be performed.
pub fn new() -> ScreenManager { pub fn new() -> ScreenManager {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let screen_manager = functions::get_module::<Box<IScreenManager>>( let screen_manager = functions::get_module::<Box<IScreenManager + Send>>(
Box::from(WinApiScreenManager::new()), Box::from(WinApiScreenManager::new()),
Box::from(AnsiScreenManager::new()), Box::from(AnsiScreenManager::new()),
).unwrap(); ).unwrap();
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let screen_manager = Box::from(AnsiScreenManager::new()) as Box<IScreenManager>; let screen_manager = Box::from(AnsiScreenManager::new()) as Box<IScreenManager + Send>;
ScreenManager { screen_manager } ScreenManager { screen_manager }
} }

View File

@ -3,8 +3,10 @@ use kernel::windows_kernel::{handle, kernel, writing};
use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT; use winapi::um::wincon::ENABLE_PROCESSED_OUTPUT;
use winapi::um::winnt::HANDLE; use winapi::um::winnt::HANDLE;
use std::ptr::NonNull;
use std::any::Any; use std::any::Any;
use std::io::{self, Write}; use std::io::{self, Write};
use std::sync::Arc;
/// This struct is an WINAPI implementation for screen related actions. /// This struct is an WINAPI implementation for screen related actions.
pub struct WinApiScreenManager { pub struct WinApiScreenManager {
@ -59,11 +61,12 @@ impl IScreenManager for WinApiScreenManager {
impl WinApiScreenManager { impl WinApiScreenManager {
/// Create a new instance. /// Create a new instance.
pub fn new() -> Self { pub fn new() -> Self {
WinApiScreenManager { WinApiScreenManager {
output: handle::get_output_handle().unwrap(), output: handle::get_output_handle().unwrap(),
alternate_handle: handle::get_output_handle().unwrap(),
is_alternate_screen: false, is_alternate_screen: false,
is_raw_screen: false, is_raw_screen: false,
alternate_handle: handle::get_output_handle().unwrap(),
} }
} }
@ -83,3 +86,5 @@ impl WinApiScreenManager {
} }
} }
} }
unsafe impl Send for WinApiScreenManager {}

View File

@ -66,8 +66,8 @@ impl<'terminal> Terminal<'terminal> {
/// term.clear(terminal::ClearType::UntilNewLine); /// term.clear(terminal::ClearType::UntilNewLine);
/// ///
/// ``` /// ```
pub fn clear(&self, clear_type: ClearType) { pub fn clear(&mut self, clear_type: ClearType) {
self.terminal.clear(clear_type, &self.screen_manager); self.terminal.clear(clear_type, &mut self.screen_manager);
} }
/// Get the terminal size (x,y). /// Get the terminal size (x,y).