From 406f2046f965f660d96537a1f3789e58c9face6a Mon Sep 17 00:00:00 2001 From: TimonPost Date: Tue, 31 Jul 2018 23:05:45 +0200 Subject: [PATCH] maked crossterm sendable for threads --- src/common/commands/mod.rs | 8 +++--- src/common/commands/unix_command.rs | 2 +- src/common/commands/win_commands.rs | 4 +-- src/common/crossterm.rs | 34 +++++++++++++++++++---- src/common/functions.rs | 2 +- src/common/screen/alternate.rs | 4 +-- src/common/screen/mod.rs | 2 +- src/common/screen/raw.rs | 43 +++++++++++++---------------- src/kernel/windows_kernel/handle.rs | 19 +++++++------ src/modules/manager/ansi_manager.rs | 24 ++++++++++------ src/modules/manager/manager.rs | 4 +-- src/modules/manager/win_manager.rs | 9 ++++-- src/modules/terminal/terminal.rs | 4 +-- 13 files changed, 94 insertions(+), 65 deletions(-) diff --git a/src/common/commands/mod.rs b/src/common/commands/mod.rs index 44c5991..9b9a2a2 100644 --- a/src/common/commands/mod.rs +++ b/src/common/commands/mod.rs @@ -22,13 +22,13 @@ pub trait IEnableAnsiCommand { fn disable(&mut self) -> bool; } -/// This trait provides an interface for switching to alternate screen and back. -/*pub trait IAlternateScreenCommand: Send{ +// 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<()>; -}*/ +} -/// 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{ fn enable(&mut self) -> Result<()>; fn disable(&mut self) -> Result<()>; diff --git a/src/common/commands/unix_command.rs b/src/common/commands/unix_command.rs index 6f2cbad..b988027 100644 --- a/src/common/commands/unix_command.rs +++ b/src/common/commands/unix_command.rs @@ -1,6 +1,6 @@ //! This module contains the commands that can be used for unix systems. -use super::{IRawScreenCommand, IStateCommand}; +use super::{ IStateCommand}; use kernel::unix_kernel::terminal; use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH}; diff --git a/src/common/commands/win_commands.rs b/src/common/commands/win_commands.rs index 541b172..7d8f969 100644 --- a/src/common/commands/win_commands.rs +++ b/src/common/commands/win_commands.rs @@ -1,6 +1,6 @@ //! 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 std::mem; @@ -142,7 +142,7 @@ impl ToAlternateScreenCommand { } } -impl IAlternateScreenCommand for ToAlternateScreenCommand { +impl IAlternateScreenCommand for ToAlternateScreenCommand { fn enable(&self, screen_manager: &mut ScreenManager) -> Result<()> { use super::super::super::manager::WinApiScreenManager; diff --git a/src/common/crossterm.rs b/src/common/crossterm.rs index 41801e1..b86cd21 100644 --- a/src/common/crossterm.rs +++ b/src/common/crossterm.rs @@ -1,7 +1,6 @@ -use super::commands::{IAlternateScreenCommand, IRawScreenCommand}; +use super::commands::{IAlternateScreenCommand}; use super::screen::AlternateScreen; -use super::screen::RawScreen; use super::super::cursor; use super::super::input; @@ -14,12 +13,23 @@ use std::io::Write; use std::io::Result; +#[cfg(not(windows))] +use common::commands::unix_command; + +#[cfg(windows)] +use common::commands::win_commands; + pub struct Crossterm { pub active_screen: manager::ScreenManager, - raw_terminal: Option, + + #[cfg(not(windows))] + raw_terminal: Option, + + #[cfg(windows)] + raw_terminal: Option, // Would be cool to figure out a way to have multiple screens instead of just only the main and alternate screen. // For windows this would be easy but for unix I have no idea. - alternate_screen: Option, + alternate_screen: Option>, } impl<'a> Crossterm { @@ -34,7 +44,13 @@ impl<'a> Crossterm { pub fn enable_raw_mode(&mut self) -> Result<()> { match self.raw_terminal { 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(); } Some(ref mut raw_terminal) => { @@ -48,7 +64,13 @@ impl<'a> Crossterm { pub fn disable_raw_mode(&mut self) -> Result<()> { match self.raw_terminal { 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(); } Some(ref mut raw_terminal) => { diff --git a/src/common/functions.rs b/src/common/functions.rs index 343179d..e74e752 100644 --- a/src/common/functions.rs +++ b/src/common/functions.rs @@ -53,7 +53,7 @@ pub fn get_module(winapi_impl: T, unix_impl: T) -> Option { // Try to enable ansi on windows if not than use WINAPI. does_support = try_enable_ansi_support(); - // does_support = false; +// does_support = false; if !does_support { term = Some(winapi_impl); } diff --git a/src/common/screen/alternate.rs b/src/common/screen/alternate.rs index dc67d4c..f80545d 100644 --- a/src/common/screen/alternate.rs +++ b/src/common/screen/alternate.rs @@ -32,9 +32,9 @@ pub struct AlternateScreen; impl AlternateScreen { /// Create an new alternate screen type. - pub fn new() -> Box { + pub fn new() -> Box { #[cfg(target_os = "windows")] - let command = functions::get_module::>( + let command = functions::get_module::>( Box::from(commands::win_commands::ToAlternateScreenCommand::new()), Box::from(commands::shared_commands::ToAlternateScreenCommand::new()), ).unwrap(); diff --git a/src/common/screen/mod.rs b/src/common/screen/mod.rs index f0db9bc..9e9933d 100644 --- a/src/common/screen/mod.rs +++ b/src/common/screen/mod.rs @@ -6,4 +6,4 @@ mod raw; use super::{commands, functions, ScreenManager}; pub use self::alternate::AlternateScreen; -pub use self::raw::RawScreen; +//pub use self::raw::RawScreen; diff --git a/src/common/screen/raw.rs b/src/common/screen/raw.rs index 742a238..522ffe9 100644 --- a/src/common/screen/raw.rs +++ b/src/common/screen/raw.rs @@ -12,28 +12,23 @@ //! //! With these modes you can easier design the terminal screen. -#[cfg(not(windows))] -use common::commands::unix_command::EnableRawModeCommand; - -#[cfg(windows)] -use common::commands::win_commands::EnableRawModeCommand; - -use super::commands; -use super::{functions, ScreenManager}; - -use std::io::{self, Write}; - -/// A wrapper for the raw terminal state. Which can be used to write to. -pub struct RawScreen; - -impl RawScreen { - /// Create a new RawScreen type. - pub fn new() -> Box { - Box::from(EnableRawModeCommand::new()) - } -} - -///// Trait withs contains a method for switching into raw mode. -//pub trait IntoRawMode: Write + Sized { -// fn into_raw_mode(&self, context: Rc) -> io::Result; +// +//use super::commands; +//use super::{functions, ScreenManager}; +// +//use std::io::{self, Write}; +// +///// A wrapper for the raw terminal state. Which can be used to write to. +//pub struct RawScreen; +// +//impl RawScreen { +// /// Create a new RawScreen type. +// pub fn new() -> Box { +// Box::from(EnableRawModeCommand::new()) +// } //} +// +/////// Trait withs contains a method for switching into raw mode. +////pub trait IntoRawMode: Write + Sized { +//// fn into_raw_mode(&self, context: Rc) -> io::Result; +////} diff --git a/src/kernel/windows_kernel/handle.rs b/src/kernel/windows_kernel/handle.rs index 635485f..a66bb92 100644 --- a/src/kernel/windows_kernel/handle.rs +++ b/src/kernel/windows_kernel/handle.rs @@ -4,11 +4,9 @@ use winapi::um::handleapi::INVALID_HANDLE_VALUE; 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 std::io::{self, ErrorKind, Result}; - /// Get the global stored handle whits provides access to the current screen. pub fn get_current_handle(screen_manager: &ScreenManager) -> Result { let mut mutex = screen_manager; @@ -16,18 +14,21 @@ pub fn get_current_handle(screen_manager: &ScreenManager) -> Result { let handle: Result; let winapi_screen_manager: &WinApiScreenManager = match screen_manager - .as_any() - .downcast_ref::() - { - Some(win_api) => win_api, - None => return Err(io::Error::new(io::ErrorKind::Other,"Could not convert to winapi screen manager, this could happen when the user has an ANSI screen manager and is calling the platform specific operations 'get_cursor_pos' or 'get_terminal_size'")) - }; + .as_any() + .downcast_ref::() + { + Some(win_api) => win_api, + None => return Err(io::Error::new(io::ErrorKind::Other,"Could not convert to winapi screen manager, this could happen when the user has an ANSI screen manager and is calling the platform specific operations 'get_cursor_pos' or 'get_terminal_size'")) + }; + handle = Ok(*winapi_screen_manager.get_handle()); return handle; } +use std::io::{self, ErrorKind, Result}; + /// Get the std_output_handle of the console pub fn get_output_handle() -> Result { unsafe { diff --git a/src/modules/manager/ansi_manager.rs b/src/modules/manager/ansi_manager.rs index e5091f3..a2f8b8f 100644 --- a/src/modules/manager/ansi_manager.rs +++ b/src/modules/manager/ansi_manager.rs @@ -6,14 +6,15 @@ use super::IScreenManager; use std::any::Any; 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; /// This struct is an ANSI escape code implementation for screen related actions. pub struct AnsiScreenManager { is_alternate_screen: bool, is_raw_screen: bool, - output: RefCell>, + output: Box, } impl IScreenManager for AnsiScreenManager { @@ -34,22 +35,27 @@ impl IScreenManager for AnsiScreenManager { } fn write_str(&self, string: &str) -> io::Result { - let mut output = self.output.borrow_mut(); - write!(output, "{}", string)?; + let out = &self.output; + let mut handle = out.lock(); + write!(handle, "{}", string)?; Ok(0) } fn write(&self, buf: &[u8]) -> io::Result { { - let mut output = self.output.borrow_mut(); - output.write(buf)?; + let out = &self.output; + let mut handle = out.lock(); + handle.write(buf)?; } Ok(0) } fn flush(&self) -> io::Result<()> { - let mut output = self.output.borrow_mut(); - output.flush() + let out = &self.output; + let mut handle = out.lock(); + handle.flush(); + + Ok(()) } fn as_any(&self) -> &Any { @@ -64,7 +70,7 @@ impl IScreenManager for AnsiScreenManager { impl AnsiScreenManager { pub fn new() -> Self { AnsiScreenManager { - output: RefCell::new(Box::from(io::stdout()) as Box), + output: Box::from(io::stdout()), is_alternate_screen: false, is_raw_screen: false, } diff --git a/src/modules/manager/manager.rs b/src/modules/manager/manager.rs index 200e2f9..5103e3e 100644 --- a/src/modules/manager/manager.rs +++ b/src/modules/manager/manager.rs @@ -36,13 +36,13 @@ impl ScreenManager { /// Create new screen manager instance whereon screen related actions can be performed. pub fn new() -> ScreenManager { #[cfg(target_os = "windows")] - let screen_manager = functions::get_module::>( + let screen_manager = functions::get_module::>( Box::from(WinApiScreenManager::new()), Box::from(AnsiScreenManager::new()), ).unwrap(); #[cfg(not(target_os = "windows"))] - let screen_manager = Box::from(AnsiScreenManager::new()) as Box; + let screen_manager = Box::from(AnsiScreenManager::new()) as Box; ScreenManager { screen_manager } } diff --git a/src/modules/manager/win_manager.rs b/src/modules/manager/win_manager.rs index f25f7af..31a16c4 100644 --- a/src/modules/manager/win_manager.rs +++ b/src/modules/manager/win_manager.rs @@ -3,8 +3,10 @@ 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 { @@ -59,11 +61,12 @@ impl IScreenManager for WinApiScreenManager { impl WinApiScreenManager { /// Create a new instance. pub fn new() -> Self { + 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_raw_screen: false, - alternate_handle: handle::get_output_handle().unwrap(), } } @@ -83,3 +86,5 @@ impl WinApiScreenManager { } } } + +unsafe impl Send for WinApiScreenManager {} diff --git a/src/modules/terminal/terminal.rs b/src/modules/terminal/terminal.rs index a6f31c4..46f4821 100644 --- a/src/modules/terminal/terminal.rs +++ b/src/modules/terminal/terminal.rs @@ -66,8 +66,8 @@ impl<'terminal> Terminal<'terminal> { /// term.clear(terminal::ClearType::UntilNewLine); /// /// ``` - pub fn clear(&self, clear_type: ClearType) { - self.terminal.clear(clear_type, &self.screen_manager); + pub fn clear(&mut self, clear_type: ClearType) { + self.terminal.clear(clear_type, &mut self.screen_manager); } /// Get the terminal size (x,y).