This commit is contained in:
TimonPost 2018-07-27 18:44:38 +02:00
parent 1499763054
commit d7387ed227
13 changed files with 266 additions and 379 deletions

View File

@ -12,86 +12,17 @@
//! - Run program with: `cargo run` //! - Run program with: `cargo run`
extern crate crossterm; extern crate crossterm;
use crossterm::Context; use crossterm::Terminal;
// mod terminal; // mod terminal;
// mod color; // mod color;
// mod cursor; // mod cursor;
// mod crossterm_type; // mod crossterm_type;
mod input; // mod input;
use input::keyboard::{async_input, input as stdin}; //use input::keyboard::{async_input, input as stdin};
use crossterm::raw::IntoRawMode;
use std::{thread, time}; use std::{thread, time};
fn main() { 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));
}
}

View File

@ -6,20 +6,20 @@
use super::super::shared::functions; use super::super::shared::functions;
use super::*; use super::*;
use std::io::Write; use std::io::Write;
use Context; use {Context, ScreenManager};
use std::fmt::Display; use std::fmt::Display;
use std::rc::Rc; use std::rc::Rc;
/// Struct that stores an specific platform implementation for cursor related actions. /// Struct that stores an specific platform implementation for cursor related actions.
pub struct TerminalCursor { pub struct TerminalCursor<'cursor> {
context: Rc<Context>, context: &'cursor ScreenManager,
terminal_cursor: Box<ITerminalCursor>, terminal_cursor: Box<ITerminalCursor>,
} }
impl TerminalCursor { impl<'cursor> TerminalCursor<'cursor> {
/// Create new cursor instance whereon cursor related actions can be performed. /// Create new cursor instance whereon cursor related actions can be performed.
pub fn new(context: Rc<Context>) -> TerminalCursor { pub fn new(context: &'cursor ScreenManager) -> TerminalCursor<'cursor> {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let cursor = functions::get_module::<Box<ITerminalCursor>>( let cursor = functions::get_module::<Box<ITerminalCursor>>(
WinApiCursor::new(context.screen_manager.clone()), WinApiCursor::new(context.screen_manager.clone()),

View File

@ -31,25 +31,25 @@ use std::rc::Rc;
///! so that cursor related actions can be preformed on both unix and windows systems. ///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminalCursor { pub trait ITerminalCursor {
/// Goto some location (x,y) in the context. /// 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 /// 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 /// 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. /// 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. /// 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. /// 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. /// 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 /// Return to saved cursor position
fn reset_position(&self); fn reset_position(&self, screen_manager: &ScreenManager);
/// Hide the terminal cursor. /// Hide the terminal cursor.
fn hide(&self); fn hide(&self, screen_manager: &ScreenManager);
/// Show the terminal cursor /// Show the terminal cursor
fn show(&self); fn show(&self, screen_manager: &ScreenManager);
/// enable or disable the blinking of the cursor. /// enable or disable the blinking of the cursor.
fn blink(&self, blink: bool); fn blink(&self, blink: bool, screen_manager: &ScreenManager);
} }

View File

@ -10,60 +10,58 @@ use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
/// This struct is an windows implementation for cursor related actions. /// This struct is an windows implementation for cursor related actions.
pub struct WinApiCursor { pub struct WinApiCursor;
screen_manager: Rc<Mutex<ScreenManager>>,
}
impl WinApiCursor { impl WinApiCursor {
pub fn new(screen_manager: Rc<Mutex<ScreenManager>>) -> Box<WinApiCursor> { pub fn new() -> Box<WinApiCursor> {
Box::from(WinApiCursor { screen_manager }) Box::from(WinApiCursor { })
} }
} }
impl ITerminalCursor for 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); 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) 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(); let (xpos, ypos) = self.pos();
self.goto(xpos, ypos - count); 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(); let (xpos, ypos) = self.pos();
self.goto(xpos + count, ypos); 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(); let (xpos, ypos) = self.pos();
self.goto(xpos, ypos + count); 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(); let (xpos, ypos) = self.pos();
self.goto(xpos - count, ypos); self.goto(xpos - count, ypos);
} }
fn save_position(&self) { fn save_position(&self, screen_manager: &ScreenManager) {
cursor::save_cursor_pos(&self.screen_manager); 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); cursor::reset_to_saved_position(&self.screen_manager);
} }
fn hide(&self) { fn hide(&self, screen_manager: &ScreenManager) {
cursor::cursor_visibility(false, &self.screen_manager); cursor::cursor_visibility(false, &self.screen_manager);
} }
fn show(&self) { fn show(&self, screen_manager: &ScreenManager) {
cursor::cursor_visibility(true, &self.screen_manager); cursor::cursor_visibility(true, &self.screen_manager);
} }
fn blink(&self, blink: bool) {} fn blink(&self, blink: bool, screen_manager: &ScreenManager) {}
} }

View File

@ -14,6 +14,7 @@ pub mod manager;
pub mod style; pub mod style;
pub mod terminal; pub mod terminal;
pub use shared::Terminal::Terminal;
pub use shared::crossterm::Crossterm; pub use shared::crossterm::Crossterm;
pub use shared::raw; pub use shared::raw;
pub use shared::screen; pub use shared::screen;

110
src/shared/Terminal.rs Normal file
View File

@ -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<Box<IRawScreenCommand>>,
alternate_screen: Option<Box<IAlternateScreenCommand>>
}
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();
}
}
}

View File

@ -8,3 +8,4 @@ pub mod traits;
pub mod raw; pub mod raw;
pub mod screen; pub mod screen;
pub mod Terminal;

View File

@ -17,99 +17,39 @@ use super::super::state::commands::unix_command::EnableRawModeCommand;
#[cfg(windows)] #[cfg(windows)]
use state::commands::win_commands::EnableRawModeCommand; use state::commands::win_commands::EnableRawModeCommand;
use state::commands::IStateCommand; use state::commands::IRawScreenCommand;
use {CommandManager, Context}; use {CommandManager, Context, ScreenManager };
use std::io::{self, Write}; use std::io::{self, Write};
use std::rc::Rc; use std::rc::Rc;
/// A wrapper for the raw terminal state. Which can be used to write to. /// A wrapper for the raw terminal state. Which can be used to write to.
pub struct RawTerminal { pub struct RawTerminal;
context: Rc<Context>,
command_id: u16,
}
impl RawTerminal { impl RawTerminal {
pub fn new(context: &Rc<Context>) -> RawTerminal { pub fn new() -> Box<IRawScreenCommand> {
let command_id = EnableRawModeCommand::new(&context.state_manager); Box::from(EnableRawModeCommand::new())
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)
} }
} }
//
///// 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>;
//}
//
//impl<W: Write> 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<Context>) -> io::Result<RawTerminal> {
// 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<Context>) -> io::Result<RawTerminal>;
}
impl<W: Write> 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<Context>) -> io::Result<RawTerminal> {
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<usize> {
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);
}
}

View File

@ -85,104 +85,43 @@
use shared::functions; use shared::functions;
use state::commands::*; use state::commands::*;
use {CommandManager, Context}; use {CommandManager, Context,ScreenManager};
use std::convert::From; use std::convert::From;
use std::io::{self, Write}; use std::io::{self, Write};
use std::rc::Rc; use std::rc::Rc;
pub struct AlternateScreen { pub struct AlternateScreen;
context: Rc<Context>,
command_id: u16,
}
impl AlternateScreen { impl AlternateScreen {
/// Get the alternate screen from the context. /// Get the alternate screen from the context.
/// By calling this method the current screen will be changed to the alternate screen. /// By calling this method the current screen will be changed to the alternate screen.
/// And you get back an handle for that screen. /// And you get back an handle for that screen.
pub fn from(context: Rc<Context>) -> Self { pub fn new() -> Box<IAlternateScreenCommand> {
let command_id = get_to_alternate_screen_command(context.clone()); let command = functions::get_module::<Box<IAlternateScreenCommand>>(
win_commands::ToAlternateScreenBufferCommand::new(),
shared_commands::ToAlternateScreenBufferCommand::new(),
).unwrap();
let screen = AlternateScreen { #[cfg(not(target_os = "windows"))]
context: context.clone(), let command = shared_commands::ToAlternateScreenBufferCommand::new();
command_id: command_id,
};
screen.to_alternate(); command
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<usize> {
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);
} }
} }
use super::super::shared::crossterm::Crossterm; use super::super::shared::crossterm::Crossterm;
impl From<Crossterm> for AlternateScreen { //impl From<Crossterm> for AlternateScreen {
fn from(crossterm: Crossterm) -> Self { // fn from(crossterm: Crossterm) -> Self {
let command_id = get_to_alternate_screen_command(crossterm.context()); // 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<Context>) -> u16 {
#[cfg(target_os = "windows")]
let command_id = functions::get_module::<u16>(
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;
}

View File

@ -31,3 +31,18 @@ pub trait IStateCommand {
fn execute(&mut self) -> bool; fn execute(&mut self) -> bool;
fn undo(&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<()>;
}

View File

@ -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. //! 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 Context;
use ScreenManager;
use std::rc::Rc; use std::rc::Rc;
use std::io::Result;
pub struct EmptyCommand; pub struct EmptyCommand;
impl IStateCommand for EmptyCommand { impl IStateCommand for EmptyCommand {
fn execute(&mut self) -> bool { fn execute(&mut self) -> bool {
return false; return false;
@ -17,39 +19,22 @@ impl IStateCommand for EmptyCommand {
} }
/// This command is used for switching to alternate screen and back to main screen. /// This command is used for switching to alternate screen and back to main screen.
pub struct ToAlternateScreenBufferCommand { pub struct ToAlternateScreenBufferCommand;
context: Rc<Context>,
}
impl ToAlternateScreenBufferCommand { impl ToAlternateScreenBufferCommand {
pub fn new(context: Rc<Context>) -> u16 { pub fn new() -> Box<ToAlternateScreenBufferCommand> {
let mut state = context.state_manager.lock().unwrap(); return Box::new(ToAlternateScreenBufferCommand {});
{
let key = state.get_changes_count();
let command = ToAlternateScreenBufferCommand {
context: context.clone(),
};
state.register_change(Box::from(command), key);
key
}
} }
} }
impl IStateCommand for ToAlternateScreenBufferCommand { impl IAlternateScreenCommand for ToAlternateScreenBufferCommand {
fn execute(&mut self) -> bool { fn to_alternate_screen(&self, screen_manager: &mut ScreenManager) -> Result<()> {
let mut screen = self.context.screen_manager.lock().unwrap(); screen_manager.write_str(csi!("?1049h"));
{ Ok(())
screen.write_str(csi!("?1049h"));
return true;
}
} }
fn undo(&mut self) -> bool { fn to_main_screen(&self, screen_manager: &mut ScreenManager) -> Result<()> {
let mut screen = self.context.screen_manager.lock().unwrap(); screen_manager.write_str(csi!("?1049l"));
{ Ok(())
screen.write_str(csi!("?1049l"));
return true;
}
} }
} }

View File

@ -7,6 +7,7 @@ use {CommandManager, Context, StateManager};
const FD_STDIN: ::std::os::unix::io::RawFd = 1; const FD_STDIN: ::std::os::unix::io::RawFd = 1;
use std::io::Result;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Mutex; 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. /// This command is used for enabling and disabling raw mode for the terminal.
pub struct EnableRawModeCommand { pub struct EnableRawModeCommand {
original_mode: Option<Box<Termios>>, original_mode: Result<Termios>,
command_id: u16,
} }
impl EnableRawModeCommand { impl EnableRawModeCommand {
pub fn new(state_manager: &Mutex<StateManager>) -> u16 { pub fn new() -> EnableRawModeCommand {
let mut state = state_manager.lock().unwrap(); return EnableRawModeCommand { original_mode: terminal::get_terminal_mode(), }
{
let key = state.get_changes_count();
let command = EnableRawModeCommand {
original_mode: None,
command_id: key,
};
state.register_change(Box::from(command), key);
key
}
} }
} }
impl IStateCommand for EnableRawModeCommand { impl EnableRawModeCommand {
fn execute(&mut self) -> bool { fn execute(&mut self) -> bool {
let original_mode = terminal::get_terminal_mode(); if let Ok(original_mode) = self.original_mode {
if let Ok(original_mode) = original_mode {
self.original_mode = Some(Box::from(original_mode));
let mut new_mode = original_mode; let mut new_mode = original_mode;
terminal::make_raw(&mut new_mode); terminal::make_raw(&mut new_mode);
terminal::set_terminal_mode(&new_mode); terminal::set_terminal_mode(&new_mode);

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::IStateCommand; use super::{ IStateCommand, IAlternateScreenCommand, IRawScreenCommand};
use {Context, StateManager}; use {Context, StateManager};
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel}; 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::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
use std::io::{Result, ErrorKind, Error };
/// This command is used for enabling and disabling ANSI code support for windows systems, /// 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. /// 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)] #[derive(Clone, Copy)]
pub struct EnableRawModeCommand { pub struct EnableRawModeCommand {
mask: DWORD, mask: DWORD,
key: u16,
} }
impl EnableRawModeCommand { impl EnableRawModeCommand {
pub fn new(state_manager: &Mutex<StateManager>) -> u16 { pub fn new() -> EnableRawModeCommand {
use self::wincon::{ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT}; use self::wincon::{ENABLE_ECHO_INPUT, ENABLE_LINE_INPUT, ENABLE_PROCESSED_INPUT};
let mut state = state_manager.lock().unwrap(); EnableRawModeCommand {
{ mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT,
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
} }
} }
} }
impl IStateCommand for EnableRawModeCommand { impl IRawScreenCommand for EnableRawModeCommand {
fn execute(&mut self) -> bool { fn enable(&mut self) -> Result<()> {
let input_handle = handle::get_input_handle().unwrap(); let input_handle = handle::get_input_handle()?;
let mut dw_mode: DWORD = 0; let mut dw_mode: DWORD = 0;
if !kernel::get_console_mode(&input_handle, &mut dw_mode) { 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; let new_mode = dw_mode & !self.mask;
if !kernel::set_console_mode(&input_handle, new_mode) { 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 { fn disable(&mut self) -> Result<()> {
let output_handle = handle::get_output_handle().unwrap(); let output_handle = handle::get_input_handle()?;
let mut dw_mode: DWORD = 0; let mut dw_mode: DWORD = 0;
if !kernel::get_console_mode(&output_handle, &mut dw_mode) { 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; let new_mode = dw_mode | self.mask;
if !kernel::set_console_mode(&output_handle, new_mode) { 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. /// 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 /// check https://docs.microsoft.com/en-us/windows/console/reading-and-writing-blocks-of-characters-and-attributes for more info
pub struct ToAlternateScreenBufferCommand { pub struct ToAlternateScreenBufferCommand;
context: Rc<Context>,
}
impl ToAlternateScreenBufferCommand { impl ToAlternateScreenBufferCommand {
pub fn new(context: Rc<Context>) -> u16 { pub fn new() -> Box<ToAlternateScreenBufferCommand>{
let mut state = context.state_manager.lock().unwrap(); return Box::from(ToAlternateScreenBufferCommand {});
{
let key = state.get_changes_count();
let command = ToAlternateScreenBufferCommand {
context: context.clone(),
};
state.register_change(Box::from(command), key);
key
}
} }
} }
impl IStateCommand for ToAlternateScreenBufferCommand { impl IAlternateScreenCommand for ToAlternateScreenBufferCommand {
fn execute(&mut self) -> bool { fn to_alternate_screen(&self, screen_manager: &mut ScreenManager) -> Result<()>{
use super::super::super::manager::WinApiScreenManager; 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. // create a new screen buffer to copy to.
let new_handle = csbi::create_console_screen_buffer(); let new_handle = csbi::create_console_screen_buffer();
// Make the new screen buffer the active 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 b: &mut WinApiScreenManager = match screen_manager
let mutex = &self.context.screen_manager; .as_any()
let mut screen = mutex.lock().unwrap(); .downcast_mut::<WinApiScreenManager>()
{
Some(b) => b,
None => return Err(Error::new(ErrorKind::Other,"Invalid cast exception")),
};
let b: &mut WinApiScreenManager = match screen b.set_alternate_handle(new_handle);
.as_any()
.downcast_mut::<WinApiScreenManager>()
{
Some(b) => b,
None => panic!(""),
};
b.set_alternate_handle(new_handle); Ok(())
}
true
} }
fn undo(&mut self) -> bool { fn to_main_screen(&self, screen_manager: &mut ScreenManager) -> Result<()>{
let handle = handle::get_output_handle().unwrap(); let handle = handle::get_output_handle()?;
csbi::set_active_screen_buffer(handle); csbi::set_active_screen_buffer(handle);
true Ok(())
} }
} }