refactored all code and canged name spaces and moved code to other modules.

This commit is contained in:
TimonPost 2018-07-28 19:26:35 +02:00
parent 8f160713bb
commit 6970dfadd8
56 changed files with 389 additions and 997 deletions

View File

@ -12,7 +12,8 @@
//! - Run program with: `cargo run`
extern crate crossterm;
use crossterm::Terminal;
use crossterm::Crossterm;
use crossterm::style::Color;
// mod terminal;
// mod color;
@ -25,8 +26,11 @@ use crossterm::Terminal;
use std::{thread, time};
fn main() {
let term = Terminal::new();
let term = Crossterm::new();
let mut cursor = term.cursor();
cursor.goto(10, 10);
cursor.print("test");
term.terminal().set_size(20,20);
let mut color = term.color();
color.set_fg(Color::Red);
}

View File

@ -0,0 +1,41 @@
//! This module is used for managing the state changes of the terminal.
//!
//! If `crossterm` changes some core state of the terminal like: enabling ANSI or enabling raw mode it should be reverted when the current process ends.
//! It would be a little lame to let the terminal in raw mode after the the current process ends for the user of this library.
use super::super::manager::ScreenManager;
use std::io::Result;
pub mod shared_commands;
#[cfg(target_os = "unix")]
pub mod unix_command;
#[cfg(target_os = "windows")]
pub mod win_commands;
#[cfg(target_os = "windows")]
pub use self::win_commands::*;
#[cfg(target_os = "unix")]
pub use self::unix_commands::*;
pub use self::shared_commands::*;
/// This command is used for complex commands whits change the terminal state.
/// By passing an `Context` instance this command will register it self to notify the terminal state change.
pub trait IStateCommand {
fn execute(&mut self) -> bool;
fn undo(&mut self) -> bool;
}
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,22 +1,7 @@
//! 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, IAlternateScreenCommand};
use Context;
use ScreenManager;
use super::{IAlternateScreenCommand, ScreenManager};
use std::rc::Rc;
use std::io::Result;
pub struct EmptyCommand;
impl IStateCommand for EmptyCommand {
fn execute(&mut self) -> bool {
return false;
}
fn undo(&mut self) -> bool {
return false;
}
}
/// This command is used for switching to alternate screen and back to main screen.
pub struct ToAlternateScreenBufferCommand;

View File

@ -3,13 +3,10 @@
use super::{IStateCommand, IRawScreenCommand};
use kernel::unix_kernel::terminal;
use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH};
use {CommandManager, Context, StateManager};
const FD_STDIN: ::std::os::unix::io::RawFd = 1;
use std::io::{Result,Error, ErrorKind};
use std::rc::Rc;
use std::sync::Mutex;
/// This command is used for switching to NoncanonicalMode.
#[derive(Copy, Clone)]

View File

@ -1,7 +1,6 @@
//! This module contains the commands that can be used for windows systems.
use super::{ IStateCommand, IAlternateScreenCommand, IRawScreenCommand};
use {Context, StateManager};
use super::{ ScreenManager, IStateCommand, IAlternateScreenCommand, IRawScreenCommand};
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
use std::mem;
@ -9,8 +8,6 @@ use winapi::shared::minwindef::DWORD;
use winapi::um::wincon;
use winapi::um::wincon::{CHAR_INFO, COORD, ENABLE_VIRTUAL_TERMINAL_PROCESSING, SMALL_RECT};
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,
@ -123,8 +120,6 @@ impl IRawScreenCommand for EnableRawModeCommand {
}
}
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;

130
src/common/crossterm.rs Normal file
View File

@ -0,0 +1,130 @@
use super::commands::{IRawScreenCommand, IAlternateScreenCommand};
use super::screen::RawScreen;
use super::screen::AlternateScreen;
use super::super::manager;
use super::super::cursor;
use super::super::input;
use super::super::terminal;
use super::super::style;
use std::io::Result;
pub struct Crossterm {
raw_mode: bool,
alternate_mode: bool,
active_screen: manager::ScreenManager,
raw_terminal: Option<Box<IRawScreenCommand>>,
alternate_screen: Option<Box<IAlternateScreenCommand>>
}
impl Crossterm{
pub fn new() -> Crossterm
{
Crossterm
{
raw_mode: false,
alternate_mode: false,
active_screen: manager::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(RawScreen::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(RawScreen::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(())
}
pub fn cursor(&self) -> cursor::TerminalCursor {
cursor::TerminalCursor::new(&self.active_screen)
}
pub fn input(&self) -> input::TerminalInput {
return input::TerminalInput::new(&self.active_screen)
}
pub fn terminal(&self) -> terminal::Terminal {
return terminal::Terminal::new(&self.active_screen)
}
pub fn color(&self) -> style::TerminalColor {
return style::TerminalColor::new(&self.active_screen)
}
}
impl Drop for Crossterm
{
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

@ -1,15 +1,12 @@
//! Some actions need to preformed platform independently since they can not be solved `ANSI escape codes`.
use std::rc::Rc;
use std::sync::Mutex;
use Context;
use ScreenManager;
use super::ScreenManager;
#[cfg(windows)]
use kernel::windows_kernel::terminal::{exit, terminal_size, buffer_size};
#[cfg(windows)]
use kernel::windows_kernel::cursor::{pos, absolute_cursor_pos};
use kernel::windows_kernel::cursor::{pos};
#[cfg(unix)]
use kernel::unix_kernel::terminal::{exit, pos, terminal_size};

View File

@ -1,11 +1,14 @@
//! This module contains some code that can be used for all module in this library.
#[macro_use]
pub mod macros;
pub mod crossterm;
pub mod commands;
pub mod screen;
pub mod functions;
pub mod traits;
pub mod raw;
pub mod screen;
pub mod Terminal;
mod crossterm;
pub use self::crossterm::Crossterm;
use super::manager::ScreenManager;

View File

@ -83,13 +83,11 @@
//!
//! As you can see because we are using `Crossterm` we won't have to bother about the `Context`.
use shared::functions;
use state::commands::*;
use {CommandManager, Context,ScreenManager};
use super::{functions, ScreenManager};
use super::commands;
use std::convert::From;
use std::io::{self, Write};
use std::rc::Rc;
pub struct AlternateScreen;
@ -97,32 +95,17 @@ 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 new() -> Box<IAlternateScreenCommand> {
pub fn new() -> Box<commands::IAlternateScreenCommand> {
#[cfg(target_os = "windows")]
let command = functions::get_module::<Box<IAlternateScreenCommand>>(
win_commands::ToAlternateScreenBufferCommand::new(),
shared_commands::ToAlternateScreenBufferCommand::new(),
let command = functions::get_module::<Box<commands::IAlternateScreenCommand>>(
commands::win_commands::ToAlternateScreenBufferCommand::new(),
commands::shared_commands::ToAlternateScreenBufferCommand::new(),
).unwrap();
#[cfg(not(target_os = "windows"))]
let command = shared_commands::ToAlternateScreenBufferCommand::new();
let command = commands::shared_commands::ToAlternateScreenBufferCommand::new();
command
}
}
use super::super::shared::crossterm::Crossterm;
//impl From<Crossterm> 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;
// }
//}

7
src/common/screen/mod.rs Normal file
View File

@ -0,0 +1,7 @@
mod raw;
mod alternate;
use super::{ScreenManager, functions, commands};
pub use self::raw::RawScreen;
pub use self::alternate::AlternateScreen;

View File

@ -13,43 +13,25 @@
//! With these modes you can easier design the terminal screen.
#[cfg(not(windows))]
use super::super::state::commands::unix_command::EnableRawModeCommand;
use common::commands::EnableRawModeCommand;
#[cfg(windows)]
use state::commands::win_commands::EnableRawModeCommand;
use common::commands::EnableRawModeCommand;
use state::commands::IRawScreenCommand;
use {CommandManager, Context, ScreenManager };
use super::{functions, ScreenManager};
use super::commands;
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;
pub struct RawScreen;
impl RawTerminal {
pub fn new() -> Box<IRawScreenCommand> {
impl RawScreen {
pub fn new() -> Box<commands::IRawScreenCommand> {
Box::from(EnableRawModeCommand::new())
}
}
//
///// Trait withs contains a method for switching into raw mode.
//pub trait IntoRawMode: Write + Sized {
// fn into_raw_mode(&self, context: Rc<Context>) -> io::Result<RawTerminal>;
//}
//
//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."))
// }
//}
//}

View File

@ -1,3 +1,3 @@
//! This module contains all the specific `unix` code.
//! This module contains all the `unix` (unsafe) code.
pub mod terminal;

View File

@ -1,13 +1,12 @@
//! This module contains all `unix` specific terminal related logic.
pub use self::libc::termios;
use libc;
pub use libc::termios;
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ};
use state::commands::{IStateCommand, NoncanonicalModeCommand, EnableRawModeCommand};
use {libc, CommandManager, Context, StateManager};
use common::commands::{NoncanonicalModeCommand, EnableRawModeCommand};
use std::io::Error;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::{fs, io, mem};
use termios::{cfmakeraw, tcsetattr, Termios, TCSADRAIN};

View File

@ -1,17 +1,18 @@
//! This module handles the enabling `ANSI escape codes` for windows terminals.
use std::sync::{Once, ONCE_INIT};
use IStateCommand;
static mut HAS_BEEN_TRIED_TO_ENABLE: bool = false;
static mut IS_ANSI_ON_WINDOWS_ENABLED: Option<bool> = None;
static mut DOES_WINDOWS_SUPPORT_ANSI: Option<bool> = None;
static ENABLE_ANSI: Once = ONCE_INIT;
use common::commands::{EnableAnsiCommand, IStateCommand};
/// Try enable `ANSI escape codes` and return the result.
pub fn try_enable_ansi_support() -> bool {
ENABLE_ANSI.call_once(|| {
use state::commands::win_commands::EnableAnsiCommand;
let mut command = EnableAnsiCommand::new();
let success = command.execute();

View File

@ -8,12 +8,9 @@ use winapi::um::wincon::{
use winapi::um::winnt::HANDLE;
use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE};
use super::{handle, kernel, Empty};
use super::{handle, kernel, Empty, ScreenManager};
use std::io::{self, ErrorKind, Result};
use std::mem::size_of;
use std::rc::Rc;
use std::sync::Mutex;
use ScreenManager;
/// Create a new console screen buffer info struct.
pub fn get_csbi(screen_manager: &ScreenManager) -> Result<CONSOLE_SCREEN_BUFFER_INFO> {

View File

@ -9,8 +9,6 @@ use super::super::super::manager::{ScreenManager, WinApiScreenManager};
use super::{csbi, handle, kernel};
use std::io::{self, ErrorKind, Result};
use std::rc::Rc;
use std::sync::Mutex;
/// This stores the cursor pos, at program level. So it can be recalled later.
static mut SAVED_CURSOR_POS: (u16, u16) = (0, 0);

View File

@ -1,13 +1,12 @@
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processenv::GetStdHandle;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
use winapi::um::winnt::HANDLE;
use std::io::{self, ErrorKind, Result};
use std::rc::Rc;
use std::sync::Mutex;
use super::super::super::manager::{ScreenManager, WinApiScreenManager};
use std::io::{self, ErrorKind, Result};
/// Get the global stored handle whits provides access to the current screen.
pub fn get_current_handle(screen_manager: &ScreenManager) -> Result<HANDLE> {
let mut mutex = screen_manager;

View File

@ -1,5 +1,4 @@
//! This module is the core of all the `WINAPI` actions. All unsafe `WINAPI` function call are done here.
//! I am planing to refactor this a little since a lot of code could be handled safer.
use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use winapi::um::winnt::HANDLE;
@ -12,8 +11,6 @@ use super::{handle, Empty};
use super::super::super::manager::ScreenManager;
use std::io::{ErrorKind, Result};
use std::sync::Mutex;
use std::rc::Rc;
/// Get the largest console window size possible.
pub fn get_largest_console_window_size() -> COORD {
@ -70,9 +67,3 @@ pub fn is_true(value: i32) -> bool {
return true;
}
}
///// Get the original color of the terminal.
//pub fn get_original_console_color(screen_manager: &ScreenManager) -> u16 {
// let console_buffer_info = csbi::get_console_screen_buffer_info(screen_manager);
// console_buffer_info.wAttributes as u16
//}

View File

@ -1,4 +1,4 @@
//! This module contains the `windows` specific logic.
//! This module contains the `windows` (unsafe) logic.
pub mod ansi_support;
pub mod cursor;
@ -8,9 +8,9 @@ pub mod writing;
pub mod csbi;
pub mod handle;
use self::winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
use shared::traits::Empty;
use winapi;
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
use common::traits::Empty;
use super::super::manager::ScreenManager;
impl Empty for COORD {
fn empty() -> COORD {

View File

@ -1,11 +1,7 @@
use std::rc::Rc;
use std::sync::Mutex;
use ScreenManager;
use super::{csbi, handle};
use super::{csbi, handle, ScreenManager};
/// Get the terminal size
pub fn terminal_size(screen_manager: &ScreenManager) -> (u16, u16) {
pub fn terminal_size() -> (u16, u16) {
let handle = handle::get_output_handle().unwrap();

View File

@ -7,13 +7,10 @@ use winapi::um::wincon::{
};
use winapi::um::winnt::HANDLE;
use super::{csbi, handle, kernel};
use {Context, ScreenManager};
use super::{ScreenManager, csbi, handle, kernel};
use std::io::{self, ErrorKind, Result};
use std::rc::Rc;
use std::str;
use std::sync::Mutex;
/// Fill a certain block with characters.
pub fn fill_console_output_character(

View File

@ -4,29 +4,19 @@
//! You can just call the action you want to perform and under water it will check what to do based on the current platform.
#[macro_use]
mod shared;
pub mod common;
mod kernel;
mod state;
mod modules;
pub mod cursor;
pub mod input;
pub mod manager;
//pub mod style;
//pub mod terminal;
pub use common::screen;
pub use modules::style;
pub use modules::cursor;
pub use modules::manager;
pub use modules::terminal;
pub use modules::input;
pub use shared::Terminal::Terminal;
//pub use shared::crossterm::Crossterm;
pub use shared::crossterm::Crossterm;
pub use shared::raw;
pub use shared::screen;
pub use state::context::Context;
use manager::ScreenManager;
use state::command_manager::CommandManager;
use state::commands::IStateCommand;
use state::state_manager::StateManager;
pub use common::Crossterm;
#[cfg(unix)]
extern crate libc;

View File

@ -2,9 +2,7 @@
//! This module is used for windows 10 terminals and unix terminals by default.
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
use super::*;
use shared::functions;
use {Context,ScreenManager};
use super::{ScreenManager, functions, ITerminalCursor};
/// This struct is an ansi implementation for cursor related actions.
pub struct AnsiCursor;

View File

@ -3,13 +3,10 @@
//!
//! Note that positions of the cursor are 0 -based witch means that the coordinates (cells) starts counting from 0
use super::super::shared::functions;
use super::*;
use std::io::Write;
use {Context, ScreenManager};
use std::io::Write;
use std::fmt::Display;
use std::rc::Rc;
/// Struct that stores an specific platform implementation for cursor related actions.
pub struct TerminalCursor<'cursor> {
@ -360,6 +357,6 @@ impl<'cursor> TerminalCursor<'cursor> {
// cursor::cursor(&context).goto(5,10);
//
// ```
//pub fn cursor(context: &ScreenManager) -> Box<TerminalCursor> {
// Box::from(TerminalCursor::new(context.clone()))
//}
pub fn cursor(screen_manager: &ScreenManager) -> TerminalCursor {
TerminalCursor::new(screen_manager)
}

View File

@ -8,18 +8,18 @@
//! so that the cursor related actions can be preformed on both unix and windows systems.
//!
mod ansi_cursor;
pub mod cursor;
mod cursor;
#[cfg(target_os = "windows")]
mod winapi_cursor;
mod ansi_cursor;
use self::ansi_cursor::AnsiCursor;
#[cfg(target_os = "windows")]
use self::winapi_cursor::WinApiCursor;
use self::ansi_cursor::AnsiCursor;
pub use self::cursor::{TerminalCursor};
use ScreenManager;
use std::rc::Rc;
pub use self::cursor::{cursor, TerminalCursor};
use super::{ScreenManager, functions};
///! This trait defines the actions that can be preformed with the terminal cursor.
///! This trait can be implemented so that an concrete implementation of the ITerminalCursor can forfill

View File

@ -1,14 +1,11 @@
//! This is an WINAPI specific implementation for cursor related action.
//! This module is used for windows terminals that do not support ANSI escape codes.
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
use super::super::manager::{IScreenManager, ScreenManager, WinApiScreenManager};
use super::super::manager::{ScreenManager, WinApiScreenManager};
use super::ITerminalCursor;
use kernel::windows_kernel::{cursor, kernel};
use std::rc::Rc;
use std::sync::Mutex;
/// This struct is an windows implementation for cursor related actions.
pub struct WinApiCursor;

View File

@ -1,8 +1,6 @@
use std::io;
use super::*;
use std::rc::Rc;
use {Context, ScreenManager };
pub struct TerminalInput<'terminal> {
terminal_input: Box<ITerminalInput>,

View File

@ -1,21 +1,19 @@
use std::io;
mod input;
pub mod input;
#[cfg(target_os = "windows")]
use self::windows_input::WindowsInput;
#[cfg(not(target_os = "windows"))]
mod unix_input;
#[cfg(target_os = "windows")]
mod windows_input;
#[cfg(target_os = "windows")]
use self::windows_input::WindowsInput;
#[cfg(not(target_os = "windows"))]
use self::unix_input::UnixInput;
#[cfg(not(target_os = "windows"))]
mod unix_input;
pub use self::input::{input, TerminalInput};
use ScreenManager;
use super::ScreenManager;
use std::io::Read;
use std::io::{Read, self};
use std::sync::mpsc;
trait ITerminalInput {
@ -58,17 +56,3 @@ impl Read for AsyncReader {
Ok(total)
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Key {
Unknown,
ArrowLeft,
ArrowRight,
ArrowUp,
ArrowDown,
Enter,
Escape,
Char(char),
#[doc(hidden)]
__More,
}

View File

@ -1,13 +1,11 @@
use std::char;
use std::io;
use std::io::Read;
use std::io::Write;
use std::io::{self, Read, Write};
use std::sync::mpsc;
use std::thread;
use super::super::kernel::unix_kernel::terminal::{get_tty, read_char};
use super::{AsyncReader, ITerminalInput, Key};
use ScreenManager;
use kernel::unix_kernel::terminal::{get_tty, read_char};
use super::{ScreenManager, AsyncReader, ITerminalInput};
pub struct UnixInput;
impl UnixInput {

View File

@ -1,17 +1,13 @@
use std::char;
use std::io;
use std::io::Write;
use std::io::{self,Write};
use std::sync::mpsc;
use std::thread;
use super::{AsyncReader, ITerminalInput, Key};
use super::{AsyncReader, ITerminalInput, ScreenManager};
use winapi::um::winnt::INT;
use winapi::um::winuser;
use std::rc::Rc;
use ScreenManager;
pub struct WindowsInput;
impl WindowsInput {
@ -136,56 +132,6 @@ fn is_line_end(key: char) -> bool {
return false;
}
//0 59 = F1
//0 60 = F2
//0 61 = F3
//0 62 = F4
//0 63 = F5
//0 64 = F6
//0 65 = F7
//0 66 = F8
//0 67 = F9
//0 68 = F10
//224 71 = Home
//224 72 = ↑ (up arrow)
//224 73 = Page Up
//224 75 = ← (left arrow)
//224 77 = → (right arrow)
//224 79 = End
//224 80 = ↓ (down arrow)
//224 81 = Page Down
//224 82 = Insert
//224 83 = Delete
//224 133 = F11
//224 134 = F12
fn key_from_key_code(code: INT) -> Key {
println!("code: {}", code);
println!("up winapi: {}", winuser::VK_UP);
match code {
// 59 => Key::F1,
// 60 => Key::F2,
// 61 => Key::F3,
// 62 => Key::F4,
// 63 => Key::F5,
// 64 => Key::F6,
// 65 => Key::F7,
// 66 => Key::F8,
// 67 => Key::F9,
// 68 => Key::F10,
winuser::VK_LEFT => Key::ArrowLeft,
winuser::VK_RIGHT => Key::ArrowRight,
winuser::VK_UP => Key::ArrowUp,
winuser::VK_DOWN => Key::ArrowDown,
winuser::VK_RETURN => Key::Enter,
winuser::VK_ESCAPE => Key::Escape,
winuser::VK_BACK => Key::Char('\x08'),
winuser::VK_TAB => Key::Char('\x09'),
_ => Key::Unknown,
}
}
extern "C" {
fn _getwche() -> INT;
fn _getwch() -> INT;

View File

@ -2,10 +2,11 @@
//! This module is used for windows 10 terminals and unix terminals by default.
//! This module uses the stdout to write to the console.
use super::IScreenManager;
use std::any::Any;
use std::io::{self, Read, Write};
use std::sync::Mutex;
use super::IScreenManager;
use std::str::from_utf8;
pub struct AnsiScreenManager {

View File

@ -1,10 +1,9 @@
//! This module provides an interface for working with the screen. With that I mean that you can get or wirte to the handle of the current screen. stdout.
//! Because crossterm can work with alternate screen, we need a place that holds the handle to the current screen so we can write to that screen.
use super::super::shared::functions;
use super::*;
use std::any::Any;
use std::any::Any;
use std::fmt::Display;
use std::io::{self, Write};
@ -33,34 +32,38 @@ impl ScreenManager {
}
}
/// Set whether screen is raw screen.
pub fn set_is_raw_screen(&mut self, value: bool) {
self.screen_manager.set_is_raw_screen(value);
}
/// Toggle a boolean to whether alternate screen is on or of.
/// Set whether the current screen is alternate screen.
pub fn set_is_alternate_screen(&mut self, value: bool) {
self.screen_manager.set_is_alternate_screen(value);
}
/// Check if the current screen is in rawscreen modes
pub fn is_raw_screen(&self) -> bool {
self.screen_manager.is_raw_screen()
}
/// Toggle a boolean to whether alternate screen is on or of.
/// Check if the current screen is in alternate modes.
pub fn is_alternate_screen(&self) -> bool {
self.screen_manager.is_alternate_screen()
}
/// Write an ANSI code as String.
/// Write String to the current screen.
pub fn write_string(&self, string: String) -> io::Result<usize> {
self.screen_manager.write_str(string.as_str())
}
/// Flush the current screen.
pub fn flush(&self) -> io::Result<()>
{
self.screen_manager.flush()
}
/// Write an ANSI code as &str
/// Write &str to the current screen.
pub fn write_str(&self, string: &str) -> io::Result<usize> {
self.screen_manager.write_str(string)
}

View File

@ -18,17 +18,19 @@
//!
//! This is the reason why this module exits. It is to provide access to the current terminal screen whether it will be the alternate screen and main screen.
pub mod manager;
mod manager;
mod ansi_manager;
#[cfg(target_os = "windows")]
mod win_manager;
mod ansi_manager;
pub use self::ansi_manager::AnsiScreenManager;
#[cfg(target_os = "windows")]
pub use self::win_manager::WinApiScreenManager;
pub use self::ansi_manager::AnsiScreenManager;
pub use self::manager::ScreenManager;
use super::functions;
use std::any::Any;
use std::io;

View File

@ -5,7 +5,6 @@ use winapi::um::winnt::HANDLE;
use std::any::Any;
use std::io::{self, Write};
use std::rc::Rc;
pub struct WinApiScreenManager {
is_alternate_screen: bool,

10
src/modules/mod.rs Normal file
View File

@ -0,0 +1,10 @@
pub mod cursor;
pub mod terminal;
pub mod input;
pub mod manager;
pub mod style;
pub use super::manager::ScreenManager;
use super::common::functions;
use super::common::commands;
use super::common::traits;

View File

@ -1,50 +1,29 @@
//! This is an ANSI specific implementation for styling related action.
//! This module is used for windows 10 terminals and unix terminals by default.
use super::super::{Color, ColorType};
use super::ITerminalColor;
use ScreenManager;
use std::rc::Rc;
use std::sync::Mutex;
use super::{ITerminalColor, Color, ScreenManager, ColorType};
/// This struct is an ansi implementation for color related actions.
pub struct AnsiColor {
screen_manager: Rc<Mutex<ScreenManager>>,
}
pub struct AnsiColor;
impl AnsiColor {
pub fn new(screen_manager: Rc<Mutex<ScreenManager>>) -> Box<AnsiColor> {
Box::from(AnsiColor { screen_manager })
pub fn new() -> AnsiColor {
AnsiColor { }
}
}
impl ITerminalColor for AnsiColor {
fn set_fg(&self, fg_color: Color) {
let mx_guard = &self.screen_manager;
let mut screen = mx_guard.lock().unwrap();
screen.write_string(format!(
csi!("{}m"),
self.color_value(fg_color, ColorType::Foreground)
));
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager) {
screen_manager.write_string(format!(csi!("{}m"), self.color_value(fg_color, ColorType::Foreground)));
}
fn set_bg(&self, bg_color: Color) {
let mx_guard = &self.screen_manager;
let mut screen = mx_guard.lock().unwrap();
screen.write_string(format!(
csi!("{}m"),
self.color_value(bg_color, ColorType::Background)
));
fn set_bg(&self, bg_color: Color, screen_manager: &ScreenManager) {
screen_manager.write_string(format!(csi!("{}m"), self.color_value(bg_color, ColorType::Background))
);
}
fn reset(&self) {
let mut screen = self.screen_manager.lock().unwrap();
{
screen.write_str(csi!("0m"));
}
fn reset(&self, screen_manager: &ScreenManager) {
screen_manager.write_str(csi!("0m"));
}
fn color_value(&self, color: Color, color_type: ColorType) -> String {

View File

@ -1,35 +1,31 @@
//! With this module you can perform actions that are color related.
//! Like styling the font, foreground color and background.
use super::super::super::shared::functions;
use super::*;
use std::io;
use std::rc::Rc;
use std::sync::Mutex;
use style::Color;
use {Context, ScreenManager};
/// Struct that stores an specific platform implementation for color related actions.
pub struct TerminalColor {
pub struct TerminalColor<'terminal> {
color: Box<ITerminalColor>,
screen_manager: Rc<Mutex<ScreenManager>>,
screen_manager: &'terminal ScreenManager
}
impl TerminalColor {
impl<'terminal> TerminalColor<'terminal> {
/// Create new instance whereon color related actions can be performed.
pub fn new(context: Rc<Context>) -> TerminalColor {
pub fn new(screen_manager: &'terminal ScreenManager) -> TerminalColor<'terminal> {
#[cfg(target_os = "windows")]
let color = functions::get_module::<Box<ITerminalColor>>(
WinApiColor::new(context.screen_manager.clone()),
AnsiColor::new(context.screen_manager.clone()),
Box::from(WinApiColor::new()),
Box::from(AnsiColor::new()),
).unwrap();
#[cfg(not(target_os = "windows"))]
let color = AnsiColor::new(context.screen_manager.clone()) as Box<ITerminalColor>;
let color = AnsiColor::new() as Box<ITerminalColor>;
TerminalColor {
color: color,
screen_manager: context.screen_manager.clone(),
color,
screen_manager
}
}
@ -55,7 +51,7 @@ impl TerminalColor {
///
/// ```
pub fn set_fg(&self, color: Color) {
self.color.set_fg(color);
self.color.set_fg(color, &self.screen_manager);
}
/// Set the background color to the given color.
@ -81,7 +77,7 @@ impl TerminalColor {
///
/// ```
pub fn set_bg(&self, color: Color) {
self.color.set_bg(color);
self.color.set_bg(color, &self.screen_manager);
}
/// Reset the terminal colors and attributes to default.
@ -102,7 +98,7 @@ impl TerminalColor {
///
/// ```
pub fn reset(&self) {
self.color.reset();
self.color.reset(&self.screen_manager);
}
/// Get available color count.
@ -126,6 +122,6 @@ impl TerminalColor {
///
/// Check `/examples/version/color` in the library for more specific examples.
///
pub fn color(context: &Rc<Context>) -> Box<TerminalColor> {
Box::from(TerminalColor::new(context.clone()))
pub fn color(screen_manager: &ScreenManager) -> TerminalColor {
TerminalColor::new(screen_manager)
}

View File

@ -1,16 +1,42 @@
//! This module is used for styling the terminal text.
//! Under styling we can think of coloring the font and applying attributes to it.
pub mod color;
pub mod objectstyle;
pub mod styledobject;
mod color;
mod styles;
#[cfg(target_os = "windows")]
mod winapi_color;
mod ansi_color;
pub use self::color::color::{color, TerminalColor};
pub use self::styles::objectstyle::ObjectStyle;
pub use self::styles::styledobject::StyledObject;
#[cfg(target_os = "windows")]
use self::winapi_color::WinApiColor;
use self::ansi_color::AnsiColor;
use std::convert::From;
use std::str::FromStr;
pub use self::color::TerminalColor;
pub use self::styledobject::StyledObject;
pub use self::objectstyle::ObjectStyle;
use super::{ScreenManager, functions};
///! This trait defines the actions that can be preformed with the terminal color.
///! This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
///! the wishes to work on an specific platform.
///!
///! ## For example:
///!
///! This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
///! so that color related actions can be preformed on both unix and windows systems.
pub trait ITerminalColor {
/// Set the foreground color to the given color.
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager);
/// Set the background color to the given color.
fn set_bg(&self, fg_color: Color, screen_manager: &ScreenManager);
/// Reset the terminal color to default.
fn reset(&self, screen_manager: &ScreenManager);
/// Gets an value that represents an color from the given `Color` and `ColorType`.
fn color_value(&self, color: Color, color_type: ColorType) -> String;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
pub enum Attribute {
Bold = 1,

View File

@ -1,10 +1,8 @@
//! This module contains the `object style` that can be applied to an `styled object`.
use style::{Color, StyledObject};
use Context;
use super::{ScreenManager, Color, StyledObject};
use std::fmt::Display;
use std::rc::Rc;
#[cfg(unix)]
use super::super::Attribute;
@ -32,10 +30,10 @@ impl Default for ObjectStyle {
impl ObjectStyle {
/// Apply an `StyledObject` to the passed displayable object.
pub fn apply_to<D: Display>(&self, val: D, context: Rc<Context>) -> StyledObject<D> {
pub fn apply_to<'style, D: Display>(&self, val: D, screen_manager: &'style ScreenManager) -> StyledObject<'style,D> {
StyledObject {
object_style: self.clone(),
context: context,
screen_manager: screen_manager,
content: val,
}
}

View File

@ -1,10 +1,8 @@
//! This module contains the logic to style an object that contains some state witch can be styled.
use Context;
use super::{ScreenManager, ObjectStyle, Color};
use std::fmt::{self, Display};
use std::io::Write;
use std::rc::Rc;
#[cfg(unix)]
use super::super::Attribute;
@ -12,16 +10,14 @@ use super::super::Attribute;
#[cfg(windows)]
use super::super::super::manager::WinApiScreenManager;
use style::{Color, ObjectStyle};
/// Struct that contains both the style and the content wits can be styled.
pub struct StyledObject<D: Display> {
pub struct StyledObject<'terminal, D: Display> {
pub object_style: ObjectStyle,
pub content: D,
pub context: Rc<Context>,
pub screen_manager: &'terminal ScreenManager,
}
impl<D: Display> StyledObject<D> {
impl<'terminal,D: Display> StyledObject<'terminal,D> {
/// Set the foreground of the styled object to the passed `Color`
///
/// #Example
@ -42,7 +38,7 @@ impl<D: Display> StyledObject<D> {
/// println!("{}", paint("I am colored green").with(Color::Green));
///
/// ```
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
pub fn with(mut self, foreground_color: Color) -> StyledObject<'terminal,D> {
self.object_style = self.object_style.fg(foreground_color);
self
}
@ -67,7 +63,7 @@ impl<D: Display> StyledObject<D> {
/// println!("{}", paint("I am colored green").on(Color::Green))
///
/// ```
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
pub fn on(mut self, background_color: Color) -> StyledObject<'terminal,D> {
self.object_style = self.object_style.bg(background_color);
self
}
@ -85,7 +81,7 @@ impl<D: Display> StyledObject<D> {
///
/// ```
#[cfg(unix)]
pub fn attr(mut self, attr: Attribute) -> StyledObject<D> {
pub fn attr(mut self, attr: Attribute) -> StyledObject<'terminal,D> {
&self.object_style.add_attr(attr);
self
}
@ -146,9 +142,9 @@ impl<D: Display> StyledObject<D> {
}
}
impl<D: Display> Display for StyledObject<D> {
impl<'terminal, D: Display> Display for StyledObject<'terminal,D> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut colored_terminal = super::super::color(&self.context);
let mut colored_terminal = super::super::super::style::color::color(&self.screen_manager);
let mut reset = true;
if let Some(bg) = self.object_style.bg_color {
@ -163,29 +159,15 @@ impl<D: Display> Display for StyledObject<D> {
#[cfg(unix)]
for attr in self.object_style.attrs.iter() {
let mutex = &self.context.screen_manager;
{
let mut screen = mutex.lock().unwrap();
screen.write_string(format!(csi!("{}m"), *attr as i16));
}
self.screen_manager.write_string(format!(csi!("{}m"), *attr as i16));
reset = true;
}
let mutex = &self.context.screen_manager;
{
let mut screen_manager = mutex.lock().unwrap();
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", self.content).unwrap();
screen_manager.write_string(string);
}
let mutex = &self.context.screen_manager;
{
let mut screen = mutex.lock().unwrap();
screen.flush();
}
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", self.content).unwrap();
self.screen_manager.write_string(string);
self.screen_manager.flush();
if reset {
colored_terminal.reset();

View File

@ -1,31 +1,22 @@
use super::super::super::manager::WinApiScreenManager;
use super::super::{Color, ColorType};
use super::ITerminalColor;
use super::{Color, ColorType, ITerminalColor, ScreenManager};
use kernel::windows_kernel::{csbi, kernel};
use winapi::um::wincon;
use ScreenManager;
use std::rc::Rc;
use std::sync::Mutex;
/// This struct is an windows implementation for color related actions.
pub struct WinApiColor {
screen_manager: Rc<Mutex<ScreenManager>>,
}
pub struct WinApiColor;
impl WinApiColor {
pub fn new(screen_manager: Rc<Mutex<ScreenManager>>) -> Box<WinApiColor> {
Box::from(WinApiColor {
screen_manager: screen_manager,
})
pub fn new() -> WinApiColor {
WinApiColor {}
}
}
impl ITerminalColor for WinApiColor {
fn set_fg(&self, fg_color: Color) {
fn set_fg(&self, fg_color: Color, screen_manager: &ScreenManager) {
let color_value = &self.color_value(fg_color, ColorType::Foreground);
let csbi = csbi::get_csbi(&self.screen_manager).unwrap();
let csbi = csbi::get_csbi(screen_manager).unwrap();
// Notice that the color values are stored in wAttribute.
// So we need to use bitwise operators to check if the values exists or to get current console colors.
@ -40,13 +31,13 @@ impl ITerminalColor for WinApiColor {
color = color | wincon::BACKGROUND_INTENSITY as u16;
}
kernel::set_console_text_attribute(color, &self.screen_manager);
kernel::set_console_text_attribute(color, screen_manager);
}
fn set_bg(&self, bg_color: Color) {
fn set_bg(&self, bg_color: Color, screen_manager: &ScreenManager) {
let color_value = &self.color_value(bg_color, ColorType::Background);
let (csbi, handle) = csbi::get_csbi_and_handle(&self.screen_manager).unwrap();
let (csbi, handle) = csbi::get_csbi_and_handle(screen_manager).unwrap();
// Notice that the color values are stored in wAttribute.
// So wee need to use bitwise operators to check if the values exists or to get current console colors.
@ -61,12 +52,12 @@ impl ITerminalColor for WinApiColor {
color = color | wincon::FOREGROUND_INTENSITY as u16;
}
kernel::set_console_text_attribute(color, &self.screen_manager);
kernel::set_console_text_attribute(color, screen_manager);
}
fn reset(&self) {
self.set_bg(Color::Black);
self.set_fg(Color::White);
fn reset(&self, screen_manager: &ScreenManager) {
self.set_bg(Color::Black, screen_manager);
self.set_fg(Color::White, screen_manager);
}
/// This will get the winapi color value from the Color and ColorType struct

View File

@ -2,9 +2,7 @@
//! This module is used for windows 10 terminals and unix terminals by default.
use super::super::cursor::cursor;
use super::{ClearType, ITerminal, Rc};
use shared::functions;
use ScreenManager;
use super::{ClearType, ITerminal, ScreenManager, functions};
/// This struct is an ansi implementation for terminal related actions.
pub struct AnsiTerminal;

View File

@ -8,18 +8,16 @@
pub mod terminal;
mod ansi_terminal;
#[cfg(target_os = "windows")]
mod winapi_terminal;
mod ansi_terminal;
use self::ansi_terminal::AnsiTerminal;
#[cfg(target_os = "windows")]
use self::winapi_terminal::WinApiTerminal;
use std::rc::Rc;
use ScreenManager;
use self::ansi_terminal::AnsiTerminal;
pub use self::terminal::terminal;
use Context;
pub use self::terminal::Terminal;
use super::{ ScreenManager, functions };
/// Enum that can be used for the kind of clearing that can be done in the terminal.
pub enum ClearType {

View File

@ -1,16 +1,11 @@
//! With this module you can perform actions that are terminal related.
//! Like clearing and scrolling in the terminal or getting the size of the terminal.
use super::super::shared::functions;
use super::super::style;
use super::*;
use Context;
use std::fmt;
use std::io::Write;
use std::rc::Rc;
/// Struct that stores an specific platform implementation for terminal related actions.
pub struct Terminal<'terminal> {
terminal: Box<ITerminal>,
@ -220,6 +215,7 @@ impl<'terminal> Terminal<'terminal> {
///
/// ```
pub fn write<D: fmt::Display>(&self, value: D) {
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", value).unwrap();
self.screen_manager.write_string(string);

View File

@ -1,15 +1,10 @@
//! This is an `WINAPI` specific implementation for terminal related action.
//! This module is used for non supporting `ANSI` windows terminals.
use super::super::shared::functions;
use super::super::ScreenManager;
use super::{ClearType, ITerminal, Rc};
use cursor::cursor;
use super::{ClearType, ITerminal, ScreenManager, functions};
use super::super::super::cursor::cursor;
use kernel::windows_kernel::{csbi, kernel, terminal, writing};
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
use ScreenManager;
use std::sync::Mutex;
/// This struct is an windows implementation for terminal related actions.
pub struct WinApiTerminal;
@ -35,7 +30,7 @@ impl ITerminal for WinApiTerminal {
}
fn terminal_size(&self, screen_manager: &ScreenManager) -> (u16, u16) {
terminal::terminal_size(screen_manager)
terminal::terminal_size()
}
fn scroll_up(&self, count: i16, screen_manager: &ScreenManager) {

View File

@ -1,123 +0,0 @@
use {StateManager, ScreenManager};
use super::super::state::commands::*;
use super::raw::RawTerminal;
use super::screen::AlternateScreen;
use super::super::cursor;
use super::super::input;
//use super::super::terminal;
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(())
}
pub fn cursor(&self) -> cursor::TerminalCursor {
cursor::TerminalCursor::new(&self.active_screen)
}
pub fn input(&self) -> input::TerminalInput {
return input::TerminalInput::new(&self.active_screen)
}
}
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

@ -1,183 +0,0 @@
//////! This module provides easy access to the functionalities of crossterm.
//////! since `crossterm version 0.3.0` an `Context` type is introduced (check that documentation for more info why this type is introduced).
//////!
//////! You have to provide this `Context` to the modules: `cursor::cursor(), color::color(), terminal::terminal()`.
//////!
//////! use crossterm::Context;
//////! use crossterm::cursor;
//////! use crossterm::color;
//////! use crossterm::terminal;
//////!
//////! let context = Context::new();
//////! let cursor = cursor::cursor(&context)
//////! let terminal = terminal::terminal(&context);
//////! let color = terminal::color(&context);
//////!
//////! Because it can seem a little odd to constantly create an Context and provide it to these modules.
//////! You can better use `Crossterm` for accessing these modules.
//////! `Crossterm` handles the Context internally so jo do not have to bother about it, for example:
//////!
//////! let crossterm = Crossterm::new();
//////! let color = crossterm.color();
//////! let cursor = crossterm.cursor();
//////! let terminal = crossterm.terminal();
////
////use super::super::cursor;
////use super::super::input::input;
////use super::super::style;
////use super::super::terminal::terminal;
////
////use Context;
////
////use std::convert::From;
////use std::fmt::Display;
////use std::mem;
////use std::rc::Rc;
////use std::sync::Arc;
////
/////// Because it can seem a little odd to constantly create an `Context` and provide it to modules like: `cursor, color and terminal`.
/////// You can better use `Crossterm` for accessing these modules.
/////// `Crossterm` handles the Context internally so jo do not have to bother about it, for example:
///////
/////// Check `/examples/Crossterm 0.3.0/program_examples/first_depth_search` in the library for more specific examples.
///////
/////// let crossterm = Crossterm::new();
/////// let color = crossterm.color();
/////// let cursor = crossterm.cursor();
/////// let terminal = crossterm.terminal();
pub struct Crossterm {
//// context: Rc<Context>,
}
//
///// Create `Crossterm` instance from `Context`
//impl From<Rc<Context>> for Crossterm {
// fn from(context: Rc<Context>) -> Self {
// return Crossterm { context: context };
// }
//}
//
//impl Crossterm {
// pub fn new() -> Crossterm {
// return Crossterm {
// context: Context::new(),
// };
// }
//
// /// Get an Terminal implementation whereon terminal related actions can be performed.
// ///
// /// #Example
// ///
// /// ```rust
// ///
// /// extern crate crossterm;
// /// use crossterm::Crossterm;
// /// use crossterm::terminal;
// ///
// /// let crossterm = Crossterm::new();
// /// let mut terminal = crossterm.terminal();
// ///
// /// ```
// pub fn terminal(&self) -> terminal::Terminal {
// return terminal::Terminal::new(self.context.clone());
// }
//
// /// Get an TerminalCursor implementation whereon cursor related actions can be performed.
// ///
// /// #Example
// ///
// /// ```rust
// ///
// /// extern crate crossterm;
// /// use crossterm::Crossterm;
// /// use crossterm::terminal;
// ///
// /// let crossterm = Crossterm::new();
// /// let mut cursor = crossterm.cursor();
// ///
// /// // move cursor to x: 5 and y:10
// /// cursor.goto(5,10);
// ///
// /// ```
// pub fn cursor(&self) -> cursor::TerminalCursor {
// return cursor::TerminalCursor::new(self.context.clone());
// }
//
// /// Get an Color implementation whereon color related actions can be performed.
// ///
// /// Check `/examples/version/color` in the library for more specific examples.
// ///
// /// #Example
// ///
// /// ```rust
// ///
// /// extern crate crossterm;
// /// use crossterm::Crossterm;
// /// use crossterm::terminal;
// ///
// /// let crossterm = Crossterm::new();
// /// let mut terminal_color = crossterm.color();
// ///
// /// ```
// pub fn color(&self) -> style::TerminalColor {
// return style::TerminalColor::new(self.context.clone());
// }
//
// pub fn input(&self) -> input::TerminalInput {
// return input::TerminalInput::new(self.context.clone());
// }
//
// /// Wraps an displayable object so it can be formatted with colors and attributes.
// ///
// /// Check `/examples/color` in the library for more specific examples.
// ///
// /// #Example
// ///
// /// ```rust
// /// extern crate crossterm;
// ///
// /// use self::crossterm::style::{paint,Color};
// /// use self::crossterm::Crossterm;
// ///
// /// fn main()
// /// {
// /// let crossterm = Crossterm::new();
// /// // Create an styledobject object from the text 'Unstyled font'
// /// // Currently it has the default foreground color and background color.
// /// println!("{}",crossterm.paint("Unstyled font"));
// ///
// /// // Create an displayable object from the text 'Colored font',
// /// // Paint this with the `Red` foreground color and `Blue` background color.
// /// // Print the result.
// /// let styledobject = crossterm.paint("Colored font").with(Color::Red).on(Color::Blue);
// /// println!("{}", styledobject);
// ///
// /// // Or all in one line
// /// println!("{}", crossterm.paint("Colored font").with(Color::Red).on(Color::Blue));
// /// }
// /// ```
// pub fn paint<'a, D: Display>(&'a self, value: D) -> style::StyledObject<D> {
// self.terminal().paint(value)
// }
//
// /// Write any displayable value to the current screen weather it will be the main screen or alternate screen.
// ///
// /// #Example
// ///
// /// ```rust
// ///
// /// extern crate crossterm;
// /// use crossterm::Crossterm;
// ///
// /// let mut crossterm = Crossterm::new();
// /// crossterm.write("Some text \n Some text on new line.");
// ///
// /// ```
// pub fn write<D: Display>(&self, value: D) {
// self.terminal().write(value)
// }
//
// /// Get an copy of the context that `Crossterm` uses internally.
// pub fn context(&self) -> Rc<Context> {
// self.context.clone()
// }
//}

View File

@ -1,39 +0,0 @@
//! A wrapper for executing and undoing commands.
use super::commands::IStateCommand;
use std::rc::Rc;
use std::sync::Mutex;
use Context;
/// Simple wrapper for executing an command.
pub struct CommandManager;
impl CommandManager {
/// execute an certain command by id.
pub fn execute(context: Rc<Context>, command_id: u16) -> bool {
let mut mutex: Rc<Mutex<Box<IStateCommand>>>;
let mut state = context.state_manager.lock().unwrap();
{
mutex = state.get(command_id);
}
let mut command = mutex.lock().unwrap();
let has_succeeded = command.execute();
return has_succeeded;
}
/// undo an certain command by id.
pub fn undo(context: Rc<Context>, command_id: u16) -> bool {
let mut mutex: Rc<Mutex<Box<IStateCommand>>>;
let mut state = context.state_manager.lock().unwrap();
{
mutex = state.get(command_id);
}
let mut command = mutex.lock().unwrap();
let has_succeeded = command.undo();
return has_succeeded;
}
}

View File

@ -1,48 +0,0 @@
//! In this module I make use of the command pattern to wrap state changes.
//!
//! The `command pattern` is an OOP concept but what it does is very handy.
//! Shortly said what this pattern can do is having an command (struct) like `EnableRawModeCommand` this command has two methods one to `execute` that command and one to `undo`.
//! Every time you preform some action you can push it into an list and at the end when you want to revert all the commands you have executed than you can loop true that loop true that list and `undo` the actions.
//!
//! So where do whe use the `Commands` for? This is so that we can push all or terminal state changes into list.
//! When we do not need those changes we can revert all the changes by looping true the list and undo all the action.
//!
//! See the `StateManager` struct where we store the commands for more info.
use std::rc::Rc;
use std::sync::Mutex;
#[cfg(unix)]
pub mod unix_command;
#[cfg(windows)]
pub mod win_commands;
pub mod shared_commands;
#[cfg(unix)]
pub use self::unix_command::*;
#[cfg(windows)]
pub use self::win_commands::*;
/// This command is used for complex commands whits change the terminal state.
/// By passing an `Context` instance this command will register it self to notify the terminal state change.
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<()>;
}

View File

@ -1,99 +0,0 @@
//! What is the `Context` all about? This `Context` has several reasons why it is introduced into `crossterm version 0.3.0`.
//! These points are related to the features like `Alternatescreen` and managing the terminal state.
//!
//! - At first `Terminal state`:
//!
//! Because this is a terminal manipulating library there will be made changes to terminal when running an process.
//! If you stop the process you want the terminal back in its original state.
//! Therefore, I need to track the changes made to the terminal.
//!
//! - At second `Handle to the console`
//!
//! In Rust we can call `stdout()` to get an handle to the current default console handle.
//! For example when in unix systems you want to print something to the main screen you can use the following code:
//!
//! ```
//! write!(std::io::stdout(), "{}", "some text").
//! ```
//!
//! But things change when we are in alternate screen modes.
//! We can not simply use `stdout()` to get a handle to the alternate screen, since this call returns the current default console handle (handle to the mainscreen).
//!
//! Instead we need to store an handle to the screen output.
//! This handle could be used to put into alternate screen modes and back into main screen modes.
//! Through this stored handle Crossterm can execute its command on the current screen whether it be alternate screen or main screen.
//!
//! For unix systems we store the handle gotten from `stdout()` for windows systems that are not supporting ANSI escape codes we store WinApi `HANDLE` struct witch will provide access to the current screen.
//!
//! So to recap this `Context` struct is a wrapper for a type that manges terminal state changes.
//! When this `Context` goes out of scope all changes made will be undone.
//! Also is this `Context` is a wrapper for access to the current console screen.
//!
//!
//! Because Crossterm needs access to the above to types quite often I have chosen to add those two in one struct called `Context` so that this type could be shared throughout library.
//! Check this link for more info: [cleanup of the changes](https://stackoverflow.com/questions/48732387/how-can-i-run-clean-up-code-in-a-rust-library).
//!
//! Because like described above the user has to pass an context type to the modules of Crossterm like this:
//!
//! ```
//! let context = Context::new();
//!
//! let cursor = cursor(&context);
//! let terminal = terminal(&context);
//! let color = color(&context);
//! ```
//!
//! Check the documentation of `AlternateScreen` for more info about how to properly manage the `Context` of the terminal when using the alternate screen.
//! If you don't use alternate screen functionalities please checkout the `Crossterm` documentation whits will make things easier for you. Since you don't have to manage the `Context` by your self.
use {ScreenManager, StateManager};
use std::marker::Sync;
use std::rc::Rc;
use std::sync::Mutex;
/// This type is the context of the current terminal. The context is a wrapper for states changes of the terminal and can be used for managing the output of the terminal.
pub struct Context {
pub screen_manager: Rc<Mutex<ScreenManager>>,
pub state_manager: Mutex<StateManager>,
}
impl Context {
/// Create new Context instance so that you can provide it to other modules like terminal, cursor and color
///
/// This context type is just an wrapper that crossterm uses for managing the state the terminal.
///
/// You must provide this context otherwise crossterm would not be able to restore to the original state of the terminal.
/// Also futures like rawscreen and ansi codes can not be used.
///
/// #Example
///
/// ```rust
///
/// use crossterm::Context;
///
/// use crossterm::cursor;
/// use crossterm::color;
/// use crossterm::terminal;
///
/// let cursor = cursor::cursor(&context)
/// let terminal = terminal::terminal(&context);
/// let color = terminal::color(&context);
///
/// ```
pub fn new() -> Rc<Context> {
Rc::new(Context {
screen_manager: Rc::new(Mutex::new(ScreenManager::new())),
state_manager: Mutex::new(StateManager::new()),
})
}
}
use std::io::Write;
/// Revert the changes made to the terminal (this is not running currently don't know why, probably because Context is stored in an Rc<> and it will not be dropped because of that.).
impl Drop for Context {
fn drop(&mut self) {
let mut changes = self.state_manager.lock().unwrap();
changes.restore_changes();
}
}

View File

@ -1,9 +0,0 @@
//! This module is used for managing the state changes of the terminal.
//!
//! If `crossterm` changes some core state of the terminal like: enabling ANSI or enabling raw mode it should be reverted when the current process ends.
//! It would be a little lame to let the terminal in raw mode after the the current process ends for the user of this library.
pub mod command_manager;
pub mod commands;
pub mod context;
pub mod state_manager;

View File

@ -1,53 +0,0 @@
//! This module is used for registering, storing an restoring the terminal state changes.
//!
//! Because this is a terminal manipulating library there will be made changes to terminal when running an process.
//! If you stop the process you want the terminal back in its original state.
//! Therefore, I need to track the changes made to the terminal.
use super::commands::shared_commands::EmptyCommand;
use super::commands::IStateCommand;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Mutex;
/// Struct that stores the changed states of the terminal.
pub struct StateManager {
changed_states: HashMap<u16, Rc<Mutex<Box<IStateCommand>>>>,
}
impl StateManager {
/// Create new Context where the terminals states can be handled.
pub fn new() -> StateManager {
StateManager {
changed_states: HashMap::new(),
}
}
/// Restore all changes that are made to the terminal.
pub fn restore_changes(&mut self) {
for (id, item) in self.changed_states.iter_mut() {
let mut item = item.lock().unwrap();
item.undo();
}
}
/// Register new changed state with the given key.
pub fn register_change(&mut self, change: Box<IStateCommand>, key: u16) {
self.changed_states.insert(key, Rc::new(Mutex::new(change)));
}
/// Get an state command from storage by id.
pub fn get(&mut self, state_key: u16) -> Rc<Mutex<Box<IStateCommand>>> {
if self.changed_states.contains_key(&state_key) {
return self.changed_states[&state_key].clone();
}
return Rc::new(Mutex::new(Box::new(EmptyCommand)));
}
/// get the count of changes made. This could be used for the identifier when registering a state.
pub fn get_changes_count(&self) -> u16 {
return self.changed_states.len() as u16;
}
}

View File

@ -1,34 +0,0 @@
pub mod color;
mod ansi_color;
#[cfg(target_os = "windows")]
mod winapi_color;
use self::ansi_color::AnsiColor;
#[cfg(target_os = "windows")]
use self::winapi_color::WinApiColor;
use super::{Color, ColorType};
use ScreenManager;
use std::rc::Rc;
use std::sync::Mutex;
///! This trait defines the actions that can be preformed with the terminal color.
///! This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
///! the wishes to work on an specific platform.
///!
///! ## For example:
///!
///! This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
///! so that color related actions can be preformed on both unix and windows systems.
pub trait ITerminalColor {
/// Set the foreground color to the given color.
fn set_fg(&self, fg_color: Color);
/// Set the background color to the given color.
fn set_bg(&self, fg_color: Color);
/// Reset the terminal color to default.
fn reset(&self);
/// Gets an value that represents an color from the given `Color` and `ColorType`.
fn color_value(&self, color: Color, color_type: ColorType) -> String;
}

View File

@ -1,4 +0,0 @@
//! This module contains the modules that are responsible for storing the styling displayable objects or simply set text.
pub mod objectstyle;
pub mod styledobject;