Created terminal type and changed alternate and raw screen
This commit is contained in:
parent
d38f406dc7
commit
403d0668a7
@ -12,93 +12,22 @@
|
|||||||
//! - 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() {
|
||||||
// let context = Context::new();
|
|
||||||
crossterm();
|
|
||||||
{
|
{
|
||||||
// let screen = ::crossterm::screen::AlternateScreen::from(context.clone());
|
let mut terminal = Terminal::new();
|
||||||
// screen.into_raw_mode(context.clone());
|
terminal.enable_alternate_screen();
|
||||||
|
thread::sleep(time::Duration::from_millis(5000));
|
||||||
// async_input::async_reading_on_alternate_screen();
|
|
||||||
// async_input::test();
|
|
||||||
// stdin::t();
|
|
||||||
// stdin::read_line();
|
|
||||||
// stdin::read_char();
|
|
||||||
// stdin::read_char();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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_until_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 + curs_y;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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()),
|
||||||
|
@ -31,28 +31,26 @@ 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);
|
||||||
|
fn absolute_pos(&self, screen_manager: &ScreenManager) -> (u16, u16);
|
||||||
fn absolute_pos(&self) -> (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);
|
||||||
}
|
}
|
||||||
|
@ -10,65 +10,63 @@ 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 absolute_pos(&self) -> (u16, u16)
|
fn absolute_pos(&self, screen_manager: &ScreenManager) -> (u16, u16)
|
||||||
{
|
{
|
||||||
cursor::absolute_cursor_pos(&self.screen_manager)
|
cursor::absolute_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) {}
|
||||||
}
|
}
|
||||||
|
@ -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
110
src/shared/Terminal.rs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,3 +8,4 @@ pub mod traits;
|
|||||||
|
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
pub mod screen;
|
pub mod screen;
|
||||||
|
pub mod Terminal;
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
@ -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<()>;
|
||||||
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
{
|
|
||||||
let key = state.get_changes_count();
|
|
||||||
let command = EnableRawModeCommand {
|
|
||||||
mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT,
|
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;
|
|
||||||
let mut screen = mutex.lock().unwrap();
|
|
||||||
|
|
||||||
let b: &mut WinApiScreenManager = match screen
|
|
||||||
.as_any()
|
.as_any()
|
||||||
.downcast_mut::<WinApiScreenManager>()
|
.downcast_mut::<WinApiScreenManager>()
|
||||||
{
|
{
|
||||||
Some(b) => b,
|
Some(b) => b,
|
||||||
None => panic!(""),
|
None => return Err(Error::new(ErrorKind::Other,"Invalid cast exception")),
|
||||||
};
|
};
|
||||||
|
|
||||||
b.set_alternate_handle(new_handle);
|
b.set_alternate_handle(new_handle);
|
||||||
}
|
|
||||||
true
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user