diff --git a/examples/Crossterm 0.3.1/bin.rs b/examples/Crossterm 0.3.1/bin.rs index cf4caef..88221a3 100644 --- a/examples/Crossterm 0.3.1/bin.rs +++ b/examples/Crossterm 0.3.1/bin.rs @@ -12,86 +12,17 @@ //! - Run program with: `cargo run` extern crate crossterm; -use crossterm::Context; +use crossterm::Terminal; // mod terminal; // mod color; // mod cursor; // mod crossterm_type; -mod input; +// mod input; -use input::keyboard::{async_input, input as stdin}; - -use crossterm::raw::IntoRawMode; +//use input::keyboard::{async_input, input as stdin}; use std::{thread, time}; fn main() { - async_input::read_async_until(); } - -use crossterm::raw::RawTerminal; -use crossterm::Crossterm; - - -use crossterm::cursor::cursor::TerminalCursor; -use crossterm::terminal::terminal::Terminal; -use crossterm::terminal::ClearType; -use std::io::Read; - -pub fn crossterm() { - let crossterm = Crossterm::new(); - let mut term = crossterm.terminal(); - let mut cursor = crossterm.cursor(); - let input = crossterm.input(); - - // clear screen - term.clear(ClearType::All); - - let mut raw_screen = RawTerminal::new(&crossterm.context()); - raw_screen.enable(); - - let mut stdin = input.read_async().bytes(); - - let mut buf = String::new(); -// -// let (term_x, term_y) = term.terminal_size(); -// -// let mut command_bar_y = term_y; -// let (curs_x, curs_y) = cursor.pos(); -// - let mut counter: u16 = 0; - loop { -// cursor.goto(0, counter); -// -// let (curs_x, curs_y) = cursor.pos(); -// term.write(format!("cursor pos {} term pos: {} command pos: {}", curs_y, term_y, command_bar_y)); -// -// cursor.goto(0, counter + 1); -// -// if (curs_y >= term_y - 1 ) -// { -// cursor.goto(0, counter + 1); -// term.clear(ClearType::CurrentLine); -// cursor.goto(0, counter + 2); -// term.write(format!("> {}", buf)); -// term.scroll_up(1); -// } -// - term.write(format!("> {}", buf)); - - while let Some(b) = stdin.next() { - if let Ok(b) = b { - if b == 3 { - term.exit(); - } else if b == 13 { - buf.clear(); - } else { - buf.push(b as char); - } - } - } - counter += 1; - thread::sleep(time::Duration::from_millis(100)); - } -} \ No newline at end of file diff --git a/src/cursor/cursor.rs b/src/cursor/cursor.rs index bc32910..e3f86d6 100644 --- a/src/cursor/cursor.rs +++ b/src/cursor/cursor.rs @@ -6,20 +6,20 @@ use super::super::shared::functions; use super::*; use std::io::Write; -use Context; +use {Context, ScreenManager}; use std::fmt::Display; use std::rc::Rc; /// Struct that stores an specific platform implementation for cursor related actions. -pub struct TerminalCursor { - context: Rc, +pub struct TerminalCursor<'cursor> { + context: &'cursor ScreenManager, terminal_cursor: Box, } -impl TerminalCursor { +impl<'cursor> TerminalCursor<'cursor> { /// Create new cursor instance whereon cursor related actions can be performed. - pub fn new(context: Rc) -> TerminalCursor { + pub fn new(context: &'cursor ScreenManager) -> TerminalCursor<'cursor> { #[cfg(target_os = "windows")] let cursor = functions::get_module::>( WinApiCursor::new(context.screen_manager.clone()), diff --git a/src/cursor/mod.rs b/src/cursor/mod.rs index 6285902..efed75c 100644 --- a/src/cursor/mod.rs +++ b/src/cursor/mod.rs @@ -31,25 +31,25 @@ use std::rc::Rc; ///! 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); + fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager); /// Get the location (x,y) of the current cusror in the context - fn pos(&self) -> (u16, u16); + fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16); /// Move cursor n times up - fn move_up(&self, count: u16); + fn move_up(&self, count: u16, screen_manager: &ScreenManager); /// Move the cursor `n` times to the right. - fn move_right(&self, count: u16); + fn move_right(&self, count: u16, screen_manager: &ScreenManager); /// Move the cursor `n` times down. - fn move_down(&self, count: u16); + fn move_down(&self, count: u16, screen_manager: &ScreenManager); /// Move the cursor `n` times left. - fn move_left(&self, count: u16); + fn move_left(&self, count: u16, screen_manager: &ScreenManager); /// 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); + fn save_position(&self, screen_manager: &ScreenManager); /// Return to saved cursor position - fn reset_position(&self); + fn reset_position(&self, screen_manager: &ScreenManager); /// Hide the terminal cursor. - fn hide(&self); + fn hide(&self, screen_manager: &ScreenManager); /// Show the terminal cursor - fn show(&self); + fn show(&self, screen_manager: &ScreenManager); /// enable or disable the blinking of the cursor. - fn blink(&self, blink: bool); + fn blink(&self, blink: bool, screen_manager: &ScreenManager); } diff --git a/src/cursor/winapi_cursor.rs b/src/cursor/winapi_cursor.rs index 0488306..18d6d25 100644 --- a/src/cursor/winapi_cursor.rs +++ b/src/cursor/winapi_cursor.rs @@ -10,60 +10,58 @@ use std::rc::Rc; use std::sync::Mutex; /// This struct is an windows implementation for cursor related actions. -pub struct WinApiCursor { - screen_manager: Rc>, -} +pub struct WinApiCursor; impl WinApiCursor { - pub fn new(screen_manager: Rc>) -> Box { - Box::from(WinApiCursor { screen_manager }) + pub fn new() -> Box { + Box::from(WinApiCursor { }) } } impl ITerminalCursor for WinApiCursor { - fn goto(&self, x: u16, y: u16) { + fn goto(&self, x: u16, y: u16, screen_manager: &ScreenManager) { cursor::set_console_cursor_position(x as i16, y as i16, &self.screen_manager); } - fn pos(&self) -> (u16, u16) { + fn pos(&self, screen_manager: &ScreenManager) -> (u16, u16) { cursor::pos(&self.screen_manager) } - fn move_up(&self, count: u16) { + fn move_up(&self, count: u16, screen_manager: &ScreenManager) { let (xpos, ypos) = self.pos(); self.goto(xpos, ypos - count); } - fn move_right(&self, count: u16) { + fn move_right(&self, count: u16, screen_manager: &ScreenManager) { let (xpos, ypos) = self.pos(); self.goto(xpos + count, ypos); } - fn move_down(&self, count: u16) { + fn move_down(&self, count: u16, screen_manager: &ScreenManager) { let (xpos, ypos) = self.pos(); self.goto(xpos, ypos + count); } - fn move_left(&self, count: u16) { + fn move_left(&self, count: u16, screen_manager: &ScreenManager) { let (xpos, ypos) = self.pos(); self.goto(xpos - count, ypos); } - fn save_position(&self) { + fn save_position(&self, screen_manager: &ScreenManager) { cursor::save_cursor_pos(&self.screen_manager); } - fn reset_position(&self) { + fn reset_position(&self, screen_manager: &ScreenManager) { cursor::reset_to_saved_position(&self.screen_manager); } - fn hide(&self) { + fn hide(&self, screen_manager: &ScreenManager) { cursor::cursor_visibility(false, &self.screen_manager); } - fn show(&self) { + fn show(&self, screen_manager: &ScreenManager) { cursor::cursor_visibility(true, &self.screen_manager); } - fn blink(&self, blink: bool) {} + fn blink(&self, blink: bool, screen_manager: &ScreenManager) {} } diff --git a/src/lib.rs b/src/lib.rs index ef4d9f9..2040558 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ pub mod manager; pub mod style; pub mod terminal; +pub use shared::Terminal::Terminal; pub use shared::crossterm::Crossterm; pub use shared::raw; pub use shared::screen; diff --git a/src/shared/Terminal.rs b/src/shared/Terminal.rs new file mode 100644 index 0000000..a7d35fc --- /dev/null +++ b/src/shared/Terminal.rs @@ -0,0 +1,110 @@ +use {StateManager, ScreenManager}; +use super::super::state::commands::*; +use super::raw::RawTerminal; +use super::screen::AlternateScreen; +use std::collections::HashMap; + +use std::io::Result; + +pub struct Terminal{ + raw_mode: bool, + alternate_mode: bool, + active_screen: ScreenManager, + raw_terminal: Option>, + alternate_screen: Option> +} + +impl Terminal{ + pub fn new() -> Terminal + { + Terminal + { + raw_mode: false, + alternate_mode: false, + active_screen: ScreenManager::new(), + raw_terminal: None, + alternate_screen: None, + } + } + + pub fn enable_raw_mode(&mut self) -> Result<()> { + match self.raw_terminal + { + None => { + self.raw_terminal = Some(RawTerminal::new()); + return self.enable_raw_mode(); + }, + Some(ref mut raw_terminal) => { + raw_terminal.enable()?; + self.raw_mode = true; + }, + } + + return Ok(()) + } + + pub fn disable_raw_mode(&mut self) -> Result<()> + { + match self.raw_terminal + { + None => { + self.raw_terminal = Some(RawTerminal::new()); + return self.disable_raw_mode(); + }, + Some(ref mut raw_terminal) => { + raw_terminal.disable()?; + self.raw_mode = false; + }, + } + + return Ok(()) + } + + pub fn enable_alternate_screen(&mut self) -> Result<()> + { + match self.alternate_screen + { + None => { + self.alternate_screen = Some(AlternateScreen::new()); + return self.enable_alternate_screen(); + }, + Some(ref mut alternate_screen) => { + alternate_screen.to_alternate_screen(&mut self.active_screen)?; + self.alternate_mode = true; + }, + } + + return Ok(()) + } + + pub fn disable_alternate_screen(&mut self) -> Result<()> + { + match self.alternate_screen + { + None => { + self.alternate_screen = Some(AlternateScreen::new()); + return self.disable_alternate_screen(); + }, + Some(ref mut alternate_screen) => { + alternate_screen.to_main_screen(&mut self.active_screen)?; + self.alternate_mode = false; + }, + } + + return Ok(()) + } +} + +impl Drop for Terminal +{ + fn drop(&mut self) { + if let Some(ref mut screen) = self.alternate_screen + { + screen.to_main_screen(&mut self.active_screen); + } + if let Some(ref mut raw_terminal) = self.raw_terminal + { + raw_terminal.disable(); + } + } +} \ No newline at end of file diff --git a/src/shared/mod.rs b/src/shared/mod.rs index a13c985..40c6202 100644 --- a/src/shared/mod.rs +++ b/src/shared/mod.rs @@ -8,3 +8,4 @@ pub mod traits; pub mod raw; pub mod screen; +pub mod Terminal; diff --git a/src/shared/raw.rs b/src/shared/raw.rs index 54acd08..86e4085 100644 --- a/src/shared/raw.rs +++ b/src/shared/raw.rs @@ -17,99 +17,39 @@ use super::super::state::commands::unix_command::EnableRawModeCommand; #[cfg(windows)] use state::commands::win_commands::EnableRawModeCommand; -use state::commands::IStateCommand; -use {CommandManager, Context}; +use state::commands::IRawScreenCommand; +use {CommandManager, Context, ScreenManager }; use std::io::{self, Write}; use std::rc::Rc; /// A wrapper for the raw terminal state. Which can be used to write to. -pub struct RawTerminal { - context: Rc, - command_id: u16, -} +pub struct RawTerminal; impl RawTerminal { - pub fn new(context: &Rc) -> RawTerminal { - let command_id = EnableRawModeCommand::new(&context.state_manager); - - RawTerminal { - context: context.clone(), - command_id: command_id, - } - } - - pub fn enable(&self) -> bool { - { - let mutex = &self.context.screen_manager; - let mut screen = mutex.lock().unwrap(); - screen.set_is_raw_screen(true); - } - - CommandManager::execute(self.context.clone(), self.command_id) - } - - pub fn disable(&self) -> bool { - { - let mutex = &self.context.screen_manager; - let mut screen = mutex.lock().unwrap(); - screen.set_is_raw_screen(false); - } - - CommandManager::undo(self.context.clone(), self.command_id) + 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; +//} +// +//impl IntoRawMode for W { +// /// Raw mode means that input (stdin) won't be printed it will instead have to be written manually by +// /// the program. The input isn't canonicalised or line buffered (that is, you can +// /// read from input(stdin) one byte of a time). +// fn into_raw_mode(&self, context: Rc) -> io::Result { +// let raw_terminal = RawTerminal::new(); +// +// if raw_terminal.enable() +// { +// return Ok(raw_terminal); +// } +// +// return Err(io::Error::new(io::ErrorKind::Other, "Could not enter raw mode.")) +// } +//} -/// Trait withs contains a method for switching into raw mode. -pub trait IntoRawMode: Write + Sized { - fn into_raw_mode(&self, context: Rc) -> io::Result; -} - -impl IntoRawMode for W { - /// Raw mode means that input (stdin) won't be printed it will instead have to be written manually by - /// the program. The input isn't canonicalised or line buffered (that is, you can - /// read from input(stdin) one byte of a time). - fn into_raw_mode(&self, context: Rc) -> io::Result { - let command_id = EnableRawModeCommand::new(&context.state_manager); - - { - let mutex = &context.screen_manager; - let mut screen = mutex.lock().unwrap(); - screen.set_is_raw_screen(true); - } - - let raw_terminal = RawTerminal { - context: context.clone(), - command_id: command_id, - }; - - if raw_terminal.enable() - { - return Ok(raw_terminal); - } - return Err(io::Error::new(io::ErrorKind::Other, "Could not enter raw mode.")) - } -} - -impl Write for RawTerminal { - fn write(&mut self, buf: &[u8]) -> io::Result { - let mut screen = self.context.screen_manager.lock().unwrap(); - { - screen.write(buf) - } - } - - fn flush(&mut self) -> io::Result<()> { - let mut screen = self.context.screen_manager.lock().unwrap(); - { - screen.flush() - } - } -} - -/// If an instance of `RawTerminal` will be dropped all terminal changes that are made will be undone. -impl Drop for RawTerminal { - fn drop(&mut self) { - let success = CommandManager::undo(self.context.clone(), self.command_id); - } -} diff --git a/src/shared/screen.rs b/src/shared/screen.rs index edd1617..3b5cfff 100644 --- a/src/shared/screen.rs +++ b/src/shared/screen.rs @@ -85,104 +85,43 @@ use shared::functions; use state::commands::*; -use {CommandManager, Context}; +use {CommandManager, Context,ScreenManager}; use std::convert::From; use std::io::{self, Write}; use std::rc::Rc; -pub struct AlternateScreen { - context: Rc, - command_id: u16, -} +pub struct AlternateScreen; impl AlternateScreen { /// Get the alternate screen from the context. /// By calling this method the current screen will be changed to the alternate screen. /// And you get back an handle for that screen. - pub fn from(context: Rc) -> Self { - let command_id = get_to_alternate_screen_command(context.clone()); + pub fn new() -> Box { + let command = functions::get_module::>( + win_commands::ToAlternateScreenBufferCommand::new(), + shared_commands::ToAlternateScreenBufferCommand::new(), + ).unwrap(); - let screen = AlternateScreen { - context: context.clone(), - command_id: command_id, - }; + #[cfg(not(target_os = "windows"))] + let command = shared_commands::ToAlternateScreenBufferCommand::new(); - screen.to_alternate(); - - return screen; - } - - /// Change the current screen to the mainscreen. - pub fn to_main(&self) { - { - let mutex = &self.context.screen_manager; - let mut screen = mutex.lock().unwrap(); - screen.set_is_alternate_screen(false); - } - - CommandManager::undo(self.context.clone(), self.command_id); - } - - /// Change the current screen to alternate screen. - pub fn to_alternate(&self) { - { - let mutex = &self.context.screen_manager; - let mut screen = mutex.lock().unwrap(); - screen.set_is_alternate_screen(true); - } - CommandManager::execute(self.context.clone(), self.command_id); - } -} - -impl Write for AlternateScreen { - fn write(&mut self, buf: &[u8]) -> io::Result { - let mut screen = self.context.screen_manager.lock().unwrap(); - { - screen.write(buf) - } - } - - fn flush(&mut self) -> io::Result<()> { - let mut screen = self.context.screen_manager.lock().unwrap(); - { - screen.flush() - } - } -} - -impl Drop for AlternateScreen { - fn drop(&mut self) { - use CommandManager; - CommandManager::undo(self.context.clone(), self.command_id); + command } } use super::super::shared::crossterm::Crossterm; -impl From for AlternateScreen { - fn from(crossterm: Crossterm) -> Self { - let command_id = get_to_alternate_screen_command(crossterm.context()); +//impl From for AlternateScreen { +// fn from(crossterm: Crossterm) -> Self { +// let command_id = get_to_alternate_screen_command(crossterm.context()); +// +// let screen = AlternateScreen { +// context: crossterm.context(), +// command_id: command_id, +// }; +// screen.to_alternate(); +// return screen; +// } +//} - let screen = AlternateScreen { - context: crossterm.context(), - command_id: command_id, - }; - screen.to_alternate(); - return screen; - } -} - -// Get the alternate screen command to enable and disable alternate screen based on the current platform -fn get_to_alternate_screen_command(context: Rc) -> u16 { - #[cfg(target_os = "windows")] - let command_id = functions::get_module::( - win_commands::ToAlternateScreenBufferCommand::new(context.clone()), - shared_commands::ToAlternateScreenBufferCommand::new(context.clone()), - ).unwrap(); - - #[cfg(not(target_os = "windows"))] - let command_id = shared_commands::ToAlternateScreenBufferCommand::new(context.clone()); - - return command_id; -} diff --git a/src/state/commands/mod.rs b/src/state/commands/mod.rs index 6d2f681..7586351 100644 --- a/src/state/commands/mod.rs +++ b/src/state/commands/mod.rs @@ -31,3 +31,18 @@ pub trait IStateCommand { fn execute(&mut self) -> bool; fn undo(&mut self) -> bool; } + +use ScreenManager; +use std::io::Result; + +pub trait IAlternateScreenCommand +{ + fn to_alternate_screen(&self,screen_manager: &mut ScreenManager) -> Result<()>; + fn to_main_screen(&self, screen_manager: &mut ScreenManager) -> Result<()>; +} + +pub trait IRawScreenCommand +{ + fn enable(&mut self) -> Result<()>; + fn disable(&mut self) -> Result<()>; +} diff --git a/src/state/commands/shared_commands.rs b/src/state/commands/shared_commands.rs index 924f8bd..fe82763 100644 --- a/src/state/commands/shared_commands.rs +++ b/src/state/commands/shared_commands.rs @@ -1,11 +1,13 @@ //! This module contains the commands that can be used for both unix and windows systems. Or else said terminals that support ansi codes. -use super::IStateCommand; +use super::{IStateCommand, IAlternateScreenCommand}; use Context; +use ScreenManager; use std::rc::Rc; - +use std::io::Result; pub struct EmptyCommand; + impl IStateCommand for EmptyCommand { fn execute(&mut self) -> bool { return false; @@ -17,39 +19,22 @@ impl IStateCommand for EmptyCommand { } /// This command is used for switching to alternate screen and back to main screen. -pub struct ToAlternateScreenBufferCommand { - context: Rc, -} +pub struct ToAlternateScreenBufferCommand; -impl ToAlternateScreenBufferCommand { - pub fn new(context: Rc) -> u16 { - let mut state = context.state_manager.lock().unwrap(); - { - let key = state.get_changes_count(); - let command = ToAlternateScreenBufferCommand { - context: context.clone(), - }; - - state.register_change(Box::from(command), key); - key - } +impl ToAlternateScreenBufferCommand { + pub fn new() -> Box { + return Box::new(ToAlternateScreenBufferCommand {}); } } -impl IStateCommand for ToAlternateScreenBufferCommand { - fn execute(&mut self) -> bool { - let mut screen = self.context.screen_manager.lock().unwrap(); - { - screen.write_str(csi!("?1049h")); - return true; - } +impl IAlternateScreenCommand for ToAlternateScreenBufferCommand { + fn to_alternate_screen(&self, screen_manager: &mut ScreenManager) -> Result<()> { + screen_manager.write_str(csi!("?1049h")); + Ok(()) } - fn undo(&mut self) -> bool { - let mut screen = self.context.screen_manager.lock().unwrap(); - { - screen.write_str(csi!("?1049l")); - return true; - } + fn to_main_screen(&self, screen_manager: &mut ScreenManager) -> Result<()> { + screen_manager.write_str(csi!("?1049l")); + Ok(()) } } diff --git a/src/state/commands/unix_command.rs b/src/state/commands/unix_command.rs index c17f2e2..570e11b 100644 --- a/src/state/commands/unix_command.rs +++ b/src/state/commands/unix_command.rs @@ -7,6 +7,7 @@ use {CommandManager, Context, StateManager}; const FD_STDIN: ::std::os::unix::io::RawFd = 1; +use std::io::Result; use std::rc::Rc; use std::sync::Mutex; @@ -66,32 +67,18 @@ impl IStateCommand for NoncanonicalModeCommand { /// This command is used for enabling and disabling raw mode for the terminal. pub struct EnableRawModeCommand { - original_mode: Option>, - command_id: u16, + original_mode: Result, } impl EnableRawModeCommand { - pub fn new(state_manager: &Mutex) -> u16 { - let mut state = state_manager.lock().unwrap(); - { - let key = state.get_changes_count(); - let command = EnableRawModeCommand { - original_mode: None, - command_id: key, - }; - - state.register_change(Box::from(command), key); - key - } + pub fn new() -> EnableRawModeCommand { + return EnableRawModeCommand { original_mode: terminal::get_terminal_mode(), } } } -impl IStateCommand for EnableRawModeCommand { +impl EnableRawModeCommand { fn execute(&mut self) -> bool { - let original_mode = terminal::get_terminal_mode(); - - if let Ok(original_mode) = original_mode { - self.original_mode = Some(Box::from(original_mode)); + if let Ok(original_mode) = self.original_mode { let mut new_mode = original_mode; terminal::make_raw(&mut new_mode); terminal::set_terminal_mode(&new_mode); diff --git a/src/state/commands/win_commands.rs b/src/state/commands/win_commands.rs index 7cb4e14..3111a25 100644 --- a/src/state/commands/win_commands.rs +++ b/src/state/commands/win_commands.rs @@ -1,6 +1,6 @@ //! This module contains the commands that can be used for windows systems. -use super::IStateCommand; +use super::{ IStateCommand, IAlternateScreenCommand, IRawScreenCommand}; use {Context, StateManager}; use kernel::windows_kernel::{ansi_support, csbi, handle, kernel}; @@ -11,6 +11,7 @@ use winapi::um::wincon::{CHAR_INFO, COORD, ENABLE_VIRTUAL_TERMINAL_PROCESSING, S use std::rc::Rc; use std::sync::Mutex; +use std::io::{Result, ErrorKind, Error }; /// 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. @@ -74,116 +75,95 @@ impl IStateCommand for EnableAnsiCommand { #[derive(Clone, Copy)] pub struct EnableRawModeCommand { mask: DWORD, - key: u16, } impl EnableRawModeCommand { - pub fn new(state_manager: &Mutex) -> u16 { + pub fn new() -> EnableRawModeCommand { use self::wincon::{ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT}; - let mut state = state_manager.lock().unwrap(); - { - let key = state.get_changes_count(); - let command = EnableRawModeCommand { - mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT, - key: key, - }; - state.register_change(Box::from(command), key); - key + EnableRawModeCommand { + mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT, } } } -impl IStateCommand for EnableRawModeCommand { - fn execute(&mut self) -> bool { - let input_handle = handle::get_input_handle().unwrap(); +impl IRawScreenCommand for EnableRawModeCommand { + fn enable(&mut self) -> Result<()> { + let input_handle = handle::get_input_handle()?; let mut dw_mode: DWORD = 0; if !kernel::get_console_mode(&input_handle, &mut dw_mode) { - return false; + return Err(Error::new(ErrorKind::Other,"Could not get console mode when enabling raw mode")) } let new_mode = dw_mode & !self.mask; if !kernel::set_console_mode(&input_handle, new_mode) { - return false; + return Err(Error::new(ErrorKind::Other,"Could not set console mode when enabling raw mode")) } - true + return Ok(()) } - fn undo(&mut self) -> bool { - let output_handle = handle::get_output_handle().unwrap(); + fn disable(&mut self) -> Result<()> { + let output_handle = handle::get_input_handle()?; let mut dw_mode: DWORD = 0; if !kernel::get_console_mode(&output_handle, &mut dw_mode) { - return false; + return Err(Error::new(ErrorKind::Other,"Could not get console mode when disabling raw mode")) } let new_mode = dw_mode | self.mask; if !kernel::set_console_mode(&output_handle, new_mode) { - return false; + return Err(Error::new(ErrorKind::Other,"Could not set console mode when disabling raw mode")) } - true + return Ok(()) } } +use ScreenManager; + /// This command is used for switching to alternate screen and back to main screen. /// check https://docs.microsoft.com/en-us/windows/console/reading-and-writing-blocks-of-characters-and-attributes for more info -pub struct ToAlternateScreenBufferCommand { - context: Rc, -} +pub struct ToAlternateScreenBufferCommand; impl ToAlternateScreenBufferCommand { - pub fn new(context: Rc) -> u16 { - let mut state = context.state_manager.lock().unwrap(); - { - let key = state.get_changes_count(); - let command = ToAlternateScreenBufferCommand { - context: context.clone(), - }; - - state.register_change(Box::from(command), key); - key - } + pub fn new() -> Box{ + return Box::from(ToAlternateScreenBufferCommand {}); } } -impl IStateCommand for ToAlternateScreenBufferCommand { - fn execute(&mut self) -> bool { +impl IAlternateScreenCommand for ToAlternateScreenBufferCommand { + fn to_alternate_screen(&self, screen_manager: &mut ScreenManager) -> Result<()>{ use super::super::super::manager::WinApiScreenManager; - let handle = handle::get_output_handle().unwrap(); + let handle = handle::get_output_handle()?; // create a new screen buffer to copy to. let new_handle = csbi::create_console_screen_buffer(); // Make the new screen buffer the active screen buffer. - csbi::set_active_screen_buffer(new_handle); + csbi::set_active_screen_buffer(new_handle)?; - { - let mutex = &self.context.screen_manager; - let mut screen = mutex.lock().unwrap(); + let b: &mut WinApiScreenManager = match screen_manager + .as_any() + .downcast_mut::() + { + Some(b) => b, + None => return Err(Error::new(ErrorKind::Other,"Invalid cast exception")), + }; - let b: &mut WinApiScreenManager = match screen - .as_any() - .downcast_mut::() - { - Some(b) => b, - None => panic!(""), - }; + b.set_alternate_handle(new_handle); - b.set_alternate_handle(new_handle); - } - true + Ok(()) } - fn undo(&mut self) -> bool { - let handle = handle::get_output_handle().unwrap(); + fn to_main_screen(&self, screen_manager: &mut ScreenManager) -> Result<()>{ + let handle = handle::get_output_handle()?; csbi::set_active_screen_buffer(handle); - true + Ok(()) } }