refactored code comments fixed examples and invalid comments. Also added documentation

This commit is contained in:
= 2018-06-16 20:10:51 +02:00
parent 48a429a396
commit 2a40d10ae9
46 changed files with 1313 additions and 1141 deletions

File diff suppressed because it is too large Load Diff

View File

@ -14,14 +14,23 @@
extern crate crossterm;
mod terminal;
mod cursor;
mod color;
use terminal::alternate_screen;
use terminal::raw_mode;
use terminal::terminal as term;
use crossterm::cursor;
use self::crossterm::Context;
use self::crossterm::terminal::ClearType;
use crossterm::raw;
use crossterm::screen;
use crossterm::raw::IntoRawMode;
use std::io::Write;
use std::{time, thread};
fn main() {
// alternate_screen::switch_between_main_and_alternate_screen();
let context = Context::new();
raw_mode::print_wait_screen_on_alternate_window();
}

View File

@ -5,43 +5,54 @@
extern crate crossterm;
use self::crossterm::style::{ Color };
use self::crossterm::terminal;
use self::crossterm::Context;
/// print some red font | demonstration.
pub fn paint_foreground()
{
let context = Context::new();
let terminal = terminal::terminal(&context);
// Pass an string to the `paint()` method with you want to paint.
// This will give you an object back wits can be styled and displayed.
let mut styledobject = paint("Red font");
let mut styledobject = terminal.paint("Red font");
// Call the method `with()` on the object given by `paint()` and pass in any Color from the Color enum.
styledobject = styledobject.with(Color::Red);
// Print the object to the console and see the result.
println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined.
println!("{}", paint("Red font").with(Color::Red));
println!("{}", terminal.paint("Red font").with(Color::Red));
}
/// print some font on red background | demonstration.
pub fn paint_background()
{
let context = Context::new();
let terminal = terminal::terminal(&context);
// Pass an string to the `paint()` method with you want to paint.
// This will give you an object back wits can be styled and displayed.
let mut styledobject = paint("Red background color");
let mut styledobject = terminal.paint("Red background color");
// Call the method `on()` on the object given by `paint()` and pass in an Color from the Color enum.
styledobject = styledobject.on(Color::Red);
// Print the object to the console and check see the result
println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined.
println!("{}", paint("Red background color").on(Color::Red));
println!("{}", terminal.paint("Red background color").on(Color::Red));
}
/// print font with fore- background color | demonstration.
pub fn paint_foreground_and_background()
{
let context = Context::new();
let terminal = terminal::terminal(&context);
// Pass an string to the `paint()` method with you want to paint.
// This will give you an object back wits can be styled and displayed.
let mut styledobject = paint("Red font on blue background color");
let mut styledobject = terminal.paint("Red font on blue background color");
/* Foreground color:
Call the method `with()` on the object given by `paint()`
Pass in an Color from the Color enum.
@ -56,77 +67,89 @@ pub fn paint_foreground_and_background()
println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined.
println!("{}", paint("Red font on blue background color").with(Color::Red).on(Color::Blue));
println!("{}", terminal.paint("Red font on blue background color").with(Color::Red).on(Color::Blue));
}
/// Print all available foreground colors | demonstration.
pub fn print_all_foreground_colors()
{
println!("Black : \t {}", paint("").with(Color::Black));
println!("Red : \t\t {}", paint("").with(Color::Red));
println!("Dark Red: \t {}", paint("").with(Color::DarkRed));
println!("Green : \t {}", paint("").with(Color::Green));
println!("Dark Green : \t {}", paint("").with(Color::DarkGreen));
println!("Yellow : \t {}", paint("").with(Color::Yellow));
println!("Dark Yellow : \t {}", paint("").with(Color::DarkYellow));
println!("Blue : \t\t {}", paint("").with(Color::Blue));
println!("Dark Blue : \t {}", paint("").with(Color::DarkBlue));
println!("Magenta : \t {}", paint("").with(Color::Magenta));
println!("Dark Magenta : \t {}", paint("").with(Color::DarkMagenta));
println!("Cyan : \t\t {}", paint("").with(Color::Cyan));
println!("Dark Cyan : \t {}", paint("").with(Color::DarkCyan));
println!("Grey : \t\t {}", paint("").with(Color::Grey));
println!("White : \t {}", paint("").with(Color::White));
let context = Context::new();
let terminal = terminal::terminal(&context);
println!("Black : \t {}", terminal.paint("").with(Color::Black));
println!("Red : \t\t {}", terminal.paint("").with(Color::Red));
println!("Dark Red: \t {}", terminal.paint("").with(Color::DarkRed));
println!("Green : \t {}", terminal.paint("").with(Color::Green));
println!("Dark Green : \t {}", terminal.paint("").with(Color::DarkGreen));
println!("Yellow : \t {}", terminal.paint("").with(Color::Yellow));
println!("Dark Yellow : \t {}", terminal.paint("").with(Color::DarkYellow));
println!("Blue : \t\t {}", terminal.paint("").with(Color::Blue));
println!("Dark Blue : \t {}", terminal.paint("").with(Color::DarkBlue));
println!("Magenta : \t {}", terminal.paint("").with(Color::Magenta));
println!("Dark Magenta : \t {}", terminal.paint("").with(Color::DarkMagenta));
println!("Cyan : \t\t {}", terminal.paint("").with(Color::Cyan));
println!("Dark Cyan : \t {}", terminal.paint("").with(Color::DarkCyan));
println!("Grey : \t\t {}", terminal.paint("").with(Color::Grey));
println!("White : \t {}", terminal.paint("").with(Color::White));
}
/// Print all available foreground colors | demonstration.
pub fn print_all_background_colors()
{
println!("Black : \t {}", paint(" ").on(Color::Black));
println!("Red : \t\t {}", paint(" ").on(Color::Red));
println!("Dark Red: \t {}", paint(" ").on(Color::DarkRed));
println!("Green : \t {}", paint(" ").on(Color::Green));
println!("Dark Green : \t {}", paint(" ").on(Color::DarkGreen));
println!("Yellow : \t {}", paint(" ").on(Color::Yellow));
println!("Dark Yellow : \t {}", paint(" ").on(Color::DarkYellow));
println!("Blue : \t\t {}", paint(" ").on(Color::Blue));
println!("Dark Blue : \t {}", paint(" ").on(Color::DarkBlue));
println!("Magenta : \t {}", paint(" ").on(Color::Magenta));
println!("Dark Magenta : \t {}", paint(" ").on(Color::DarkMagenta));
println!("Cyan : \t\t {}", paint(" ").on(Color::Cyan));
println!("Dark Cyan : \t {}", paint(" ").on(Color::DarkCyan));
println!("Grey : \t\t {}", paint(" ").on(Color::Grey));
println!("White : \t {}", paint(" ").on(Color::White));
let context = Context::new();
let terminal = terminal::terminal(&context);
println!("Black : \t {}", terminal.paint(" ").on(Color::Black));
println!("Red : \t\t {}", terminal.paint(" ").on(Color::Red));
println!("Dark Red: \t {}", terminal.paint(" ").on(Color::DarkRed));
println!("Green : \t {}", terminal.paint(" ").on(Color::Green));
println!("Dark Green : \t {}", terminal.paint(" ").on(Color::DarkGreen));
println!("Yellow : \t {}", terminal.paint(" ").on(Color::Yellow));
println!("Dark Yellow : \t {}", terminal.paint(" ").on(Color::DarkYellow));
println!("Blue : \t\t {}", terminal.paint(" ").on(Color::Blue));
println!("Dark Blue : \t {}", terminal.paint(" ").on(Color::DarkBlue));
println!("Magenta : \t {}", terminal.paint(" ").on(Color::Magenta));
println!("Dark Magenta : \t {}", terminal.paint(" ").on(Color::DarkMagenta));
println!("Cyan : \t\t {}", terminal.paint(" ").on(Color::Cyan));
println!("Dark Cyan : \t {}", terminal.paint(" ").on(Color::DarkCyan));
println!("Grey : \t\t {}", terminal.paint(" ").on(Color::Grey));
println!("White : \t {}", terminal.paint(" ").on(Color::White));
#[cfg(unix)]
println!("RGB (10,10,10): \t {}", paint(" ").on(Color::Rgb {r: 10, g: 10, b: 10}));
println!("RGB (10,10,10): \t {}", terminal.paint(" ").on(Color::Rgb {r: 10, g: 10, b: 10}));
#[cfg(unix)]
println!("RGB (10,10,10): \t {}", paint(" ").on(Color::AnsiValue(50)));
println!("RGB (10,10,10): \t {}", terminal.paint(" ").on(Color::AnsiValue(50)));
}
/// Print font with all available attributes. Note that this can only be used at unix systems and that some are not supported widely | demonstration..
#[cfg(unix)]
pub fn print_font_with_attributes()
{
println!("{}", paint("Normal text"));
println!("{}", paint("Bold text").bold());
println!("{}", paint("Italic text").italic());
println!("{}", paint("Slow blinking text").slow_blink());
println!("{}", paint("Rapid blinking text").rapid_blink());
println!("{}", paint("Hidden text").hidden());
println!("{}", paint("Underlined text").underlined());
println!("{}", paint("Reversed color").reverse());
println!("{}", paint("Dim text color").dim());
println!("{}", paint("Crossed out font").crossed_out());
let context = Context::new();
let terminal = terminal::terminal(&context);
println!("{}", terminal.paint("Normal text"));
println!("{}", terminal.paint("Bold text").bold());
println!("{}", terminal.paint("Italic text").italic());
println!("{}", terminal.paint("Slow blinking text").slow_blink());
println!("{}", terminal.paint("Rapid blinking text").rapid_blink());
println!("{}", terminal.paint("Hidden text").hidden());
println!("{}", terminal.paint("Underlined text").underlined());
println!("{}", terminal.paint("Reversed color").reverse());
println!("{}", terminal.paint("Dim text color").dim());
println!("{}", terminal.paint("Crossed out font").crossed_out());
}
/// Print all supported rgb colors | demonstration.
#[cfg(unix)]
pub fn print_supported_colors()
{
let count = crossterm::style::color().get_available_color_count().unwrap();
let context = Context::new();
let terminal = terminal::terminal(&context);
let count = crossterm::style::color(context.screen_manager.clone()).get_available_color_count().unwrap();
for i in 0..count
{
println!("{}", paint(format!("Color: {}",i)).with(Color::AnsiValue(i as u8)));
println!("{}", terminal.paint(format!("Color: {}",i)).with(Color::AnsiValue(i as u8)));
}
}

View File

@ -3,23 +3,38 @@
//!
extern crate crossterm;
use self::crossterm::cursor::{cursor, TerminalCursor};
use self::crossterm::Context;
/// Set the cursor to position X: 10, Y: 5 in the terminal.
pub fn goto()
{
let context = Context::new();
// Get the cursor
let mut cursor = cursor();
let mut cursor = cursor(&context);
// Set the cursor to position X: 10, Y: 5 in the terminal
cursor.goto(10,5);
}
/// get the cursor position
pub fn pos()
{
let context = Context::new();
// Get the cursor
let mut cursor = cursor(&context);
// get the cursor position.
let (x,y) = cursor.pos();
}
/// Move the cursor 3 up | demonstration.
pub fn move_up()
{
let context = Context::new();
// Get the cursor
let mut cursor = cursor();
let mut cursor = cursor(&context);
// Move the cursor to position 3 times to the up in the terminal
cursor.move_up(3);
}
@ -27,8 +42,10 @@ pub fn move_up()
/// Move the cursor 3 to the right | demonstration.
pub fn move_right()
{
let context = Context::new();
// Get the cursor
let mut cursor = cursor();
let mut cursor = cursor(&context);
// Move the cursor to position 3 times to the right in the terminal
cursor.move_right(3);
}
@ -36,8 +53,10 @@ pub fn move_right()
/// Move the cursor 3 down | demonstration.
pub fn move_down()
{
let context = Context::new();
// Get the cursor
let mut cursor = cursor();
let mut cursor = cursor(&context);
// Move the cursor to position 3 times to the down in the terminal
cursor.move_down(3);
}
@ -45,8 +64,10 @@ pub fn move_down()
/// Move the cursor 3 to the left | demonstration.
pub fn move_left()
{
let context = Context::new();
// Get the cursor
let mut cursor = cursor();
let mut cursor = cursor(&context);
// Move the cursor to position 3 times to the left in the terminal
cursor.move_left(3);
}
@ -54,10 +75,12 @@ pub fn move_left()
/// Print character at X: 10 Y: 5 | demonstration.
pub fn print()
{
let context = Context::new();
// To print an some displayable content on an certain position.
// Get the cursor
let mut cursor = cursor();
let mut cursor = cursor(&context);
// Set the cursor to position X: 10, Y: 5 in the terminal
cursor.goto(10,5);
// Print the @ symbol at position X: 10, Y: 5 in the terminal
@ -79,7 +102,9 @@ pub fn print()
/// Save and reset cursor position | demonstration..
pub fn safe_and_reset_position()
{
let mut cursor = cursor();
let context = Context::new();
let mut cursor = cursor(&context);
// Goto X: 5 Y: 5
cursor.goto(5,5);

View File

@ -1,6 +1,6 @@
extern crate crossterm;
use crossterm::Terminal;
use crossterm::Context;
use crossterm::screen::AlternateScreen;
use crossterm::cursor::cursor;
use crossterm::terminal::{self, ClearType};
@ -8,7 +8,7 @@ use crossterm::terminal::{self, ClearType};
use std::io::{Write, stdout};
use std::{time, thread};
fn print_wait_screen(terminal: &Terminal)
fn print_wait_screen(terminal: &Context)
{
terminal::terminal(&terminal).clear(ClearType::All);
@ -39,16 +39,16 @@ fn print_wait_screen(terminal: &Terminal)
pub fn print_wait_screen_on_alternate_window()
{
let terminal = Terminal::new();
let context = Context::new();
// create scope. If this scope ends the screen will be switched back to mainscreen.
// because `AlternateScreen` switches back to main screen when switching back.
{
// create new alternate screen instance and switch to the alternate screen.
let mut screen = AlternateScreen::from(&terminal);
let mut screen = AlternateScreen::from(&context);
// Print the wait screen.
print_wait_screen(&terminal);
print_wait_screen(&context);
}
println!("Whe are back at the main screen");
@ -56,12 +56,12 @@ pub fn print_wait_screen_on_alternate_window()
pub fn switch_between_main_and_alternate_screen()
{
let terminal = Terminal::new();
let mut cursor = cursor(&terminal);
let context = Context::new();
let mut cursor = cursor(&context);
{
// create new alternate screen instance and switch to the alternate screen.
let mut screen = AlternateScreen::from(&terminal);
let mut screen = AlternateScreen::from(&context);
cursor.goto(0,0);
write!(screen, "we are at the alternate screen!");
screen.flush();

View File

@ -1,6 +1,6 @@
extern crate crossterm;
use crossterm::Terminal;
use crossterm::Context;
use crossterm::screen::AlternateScreen;
use crossterm::cursor::cursor;
use crossterm::terminal::{self, ClearType};
@ -11,23 +11,14 @@ use std::{time, thread};
use crossterm::raw::IntoRawMode;
// raw screen is not working correctly currently
fn print_wait_screen(terminal: &Terminal)
fn print_wait_screen(context: &Context)
{
terminal::terminal(&terminal).clear(ClearType::All);
terminal::terminal(&context).clear(ClearType::All);
let mut cursor = cursor(&terminal);
cursor.goto(0,0);
{
let mut screen_manager = terminal.screen_manager.lock().unwrap();
{
write!(screen_manager.stdout(),
"Welcome to the wait screen.\n\
Please wait a few seconds until we arrive back at the main screen.\n\
Progress: "
);
}
}
let mut cursor = cursor(&context);
cursor.goto(0,0).print("Welcome to the wait screen.");
cursor.goto(0,1).print("Please wait a few seconds until we arrive back at the main screen.");
cursor.goto(0,2).print("Progress: ");
// print some progress example.
for i in 1..5
@ -42,18 +33,21 @@ fn print_wait_screen(terminal: &Terminal)
pub fn print_wait_screen_on_alternate_window()
{
let terminal = Terminal::new();
let context = Context::new();
// create scope. If this scope ends the screen will be switched back to mainscreen.
// because `AlternateScreen` switches back to main screen when switching back.
// because `AlternateScreen` switches back to main screen when going out of scope.
{
let a = stdout().into_raw_mode(&terminal);
// create new alternate screen instance this call is also switching the screen to alternate screen.
// then convert the output of the program to raw mode.
// then print the wait screen on the alternate screen in raw mode.
let mut screen = AlternateScreen::from(&context);
let alternate_screen = screen.into_raw_mode(&context);
thread::sleep(time::Duration::from_secs(3));
// Print the wait screen.
print_wait_screen(&context);
// // Print the wait screen.
// print_wait_screen(&terminal);
screen.flush();
}
println!("Whe are back at the main screen");

View File

@ -4,7 +4,7 @@
extern crate crossterm;
use crossterm::Terminal;
use crossterm::Context;
use crossterm::terminal::{ ClearType, terminal };
use crossterm::cursor;
@ -18,10 +18,10 @@ fn print_test_data()
/// Clear all lines in terminal | demonstration
pub fn clear_all_lines()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
print_test_data();
@ -32,15 +32,15 @@ pub fn clear_all_lines()
/// Clear all lines from cursor position X:4, Y:4 down | demonstration
pub fn clear_from_cursor_down()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
print_test_data();
// Set terminal cursor position (see example for more info).
cursor::cursor(&term).goto(4,8);
cursor::cursor(&context).goto(4,8);
// Clear all cells from current cursor position down.
terminal.clear(ClearType::FromCursorDown);
@ -49,15 +49,15 @@ pub fn clear_from_cursor_down()
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
pub fn clear_from_cursor_up()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
print_test_data();
// Set terminal cursor position (see example for more info).
cursor::cursor(&term).goto(4,4);
cursor::cursor(&context).goto(4,4);
// Clear all cells from current cursor position down.
terminal.clear(ClearType::FromCursorUp);
@ -66,15 +66,15 @@ pub fn clear_from_cursor_up()
/// Clear all lines from cursor position X:4, Y:4 up | demonstration
pub fn clear_current_line()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
print_test_data();
// Set terminal cursor position (see example for more info).
cursor::cursor(&term).goto(4,4);
cursor::cursor(&context).goto(4,4);
// Clear current line cells.
terminal.clear(ClearType::CurrentLine);
@ -83,15 +83,15 @@ pub fn clear_current_line()
/// Clear all lines from cursor position X:4, Y:7 up | demonstration
pub fn clear_until_new_line()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
print_test_data();
// Set terminal cursor position (see example for more info).
cursor::cursor(&term).goto(4,20);
cursor::cursor(&context).goto(4,20);
// Clear all the cells until next line.
terminal.clear(ClearType::UntilNewLine);
@ -100,10 +100,10 @@ pub fn clear_until_new_line()
/// Print the the current terminal size | demonstration.
pub fn print_terminal_size()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
// Get terminal size
let terminal_size = terminal.terminal_size();
// Print results
@ -113,9 +113,9 @@ pub fn print_terminal_size()
/// Set the terminal size to width 10, height: 10 | demonstration.
pub fn set_terminal_size()
{
let term = Terminal::new();
let context = Context::new();
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
terminal.set_size(10,10);
}
@ -123,11 +123,11 @@ pub fn set_terminal_size()
/// Scroll down 10 lines | demonstration.
pub fn scroll_down()
{
let term = Terminal::new();
let context = Context::new();
print_test_data();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
// Scroll down 10 lines.
terminal.scroll_down(10);
}
@ -135,12 +135,12 @@ pub fn scroll_down()
/// Scroll down 10 lines | demonstration.
pub fn scroll_up()
{
let term = Terminal::new();
let context = Context::new();
print_test_data();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
// Scroll up 10 lines.
terminal.scroll_up(10);
}
@ -148,10 +148,10 @@ pub fn scroll_up()
/// Resize the terminal to X: 10, Y: 10 | demonstration.
pub fn resize_terminal()
{
let term = Terminal::new();
let context = Context::new();
// Get terminal
let mut terminal = terminal(&term);
let mut terminal = terminal(&context);
// Get terminal size
terminal.set_size(10,10);
}

View File

@ -1,75 +1,73 @@
//! This is an ANSI specific implementation for cursor related action.
//! 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 Terminal ;
use Context;
use shared::functions;
use super::ITerminalCursor;
/// This struct is an ansi implementation for cursor related actions.
pub struct AnsiCursor
{ }
pub struct AnsiCursor;
impl<'output> AnsiCursor {
impl AnsiCursor {
pub fn new() -> Box<AnsiCursor> {
Box::from(AnsiCursor {})
}
}
impl<'term> ITerminalCursor for AnsiCursor {
impl ITerminalCursor for AnsiCursor {
fn goto(&self, x: u16, y: u16, terminal: &Terminal)
fn goto(&self, x: u16, y: u16, context: &Context)
{
// ANSI codes are one-based. I want 0 based so we just need to increment and x,y.
let mut screen = terminal.screen_manager.lock().unwrap();
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{};{}H"), y + 1, x +1));
}
}
fn pos(&self, terminal: &Terminal) -> (u16, u16) {
functions::get_cursor_position(&terminal)
fn pos(&self, context: &Context) -> (u16, u16) {
functions::get_cursor_position(&context)
}
fn move_up(&self, count: u16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn move_up(&self, count: u16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{}A"), count));
}
}
fn move_right(&self, count: u16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn move_right(&self, count: u16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{}C"), count));
}
}
fn move_down(&self, count: u16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn move_down(&self, count: u16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{}B"), count));
}
}
fn move_left(&self, count: u16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn move_left(&self, count: u16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{}D"), count));
}
}
fn save_position(&mut self, terminal: &Terminal)
fn save_position(&mut self, context: &Context)
{
let mut screen = terminal.screen_manager.lock().unwrap();
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi_str(csi!("s"));
}
}
fn reset_position(&self, terminal: &Terminal)
fn reset_position(&self, context: &Context)
{
let mut screen = terminal.screen_manager.lock().unwrap();
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi_str(csi!("u"));
}

View File

@ -1,31 +1,31 @@
//! With this module you can perform actions that are cursor related.
//! Like changing and displaying the position of the cursor in terminal.
//! Like changing and display the position of the cursor in terminal.
//!
//! Note that positions of the cursor are 0 -based witch means that the coordinates starts counting from 0
//! Note that positions of the cursor are 0 -based witch means that the coordinates (cells) starts counting from 0
use super::*;
use Terminal;
use Context;
use std::fmt::Display;
use std::io::Write;
/// Struct that stores an specific platform implementation for cursor related actions.
pub struct TerminalCursor<'term> {
terminal: &'term Terminal,
pub struct TerminalCursor<'context> {
context: &'context Context,
terminal_cursor: Option<Box<ITerminalCursor>>,
}
impl <'term> TerminalCursor<'term>
impl <'context> TerminalCursor<'context>
{
/// Create new cursor instance whereon cursor related actions can be performed.
pub fn new(terminal: &'term Terminal) -> TerminalCursor<'term> {
pub fn new(context: &'context Context) -> TerminalCursor<'context> {
#[cfg(target_os = "windows")]
let cursor = functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new());
#[cfg(not(target_os = "windows"))]
let cursor = Some(AnsiCursor::new() as Box<ITerminalCursor>);
TerminalCursor { terminal_cursor: cursor , terminal: terminal}
TerminalCursor { terminal_cursor: cursor , context}
}
/// Goto some position (x,y) in the terminal.
@ -35,15 +35,23 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// cursor::cursor().goto(10,10);
// pub fn goto()
// {
// let context = Context::new();
//
// // Get the cursor
// let mut cursor = cursor(&context);
// // Set the cursor to position X: 10, Y: 5 in the terminal
// cursor.goto(10,5);
// }
///
/// ```
pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor<'term> {
pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor<'context> {
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.goto(x, y, &self.terminal);
terminal_cursor.goto(x, y, &self.context);
}
self
}
@ -55,16 +63,23 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// let pos = cursor::cursor().pos();
/// println!("{:?}", pos);
/// pub fn pos()
/// {
/// let context = Context::new();
///
/// // Get the cursor
/// let mut cursor = cursor(&context);
/// // get the cursor position.
/// let (x,y) = cursor.pos();
/// }
///
/// ```
pub fn pos(&mut self) -> (u16, u16) {
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.pos(&self.terminal)
terminal_cursor.pos(&self.context)
} else {
(0, 0)
}
@ -77,19 +92,23 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// // Move 1 time up
/// cursor::cursor().move_up(1);
/// pub fn move_up()
/// {
/// let context = Context::new();
///
/// // Move 2 times up
/// cursor::cursor().move_up(2);
/// // Get the cursor
/// let mut cursor = cursor(&context);
/// // Move the cursor to position 3 times to the up in the terminal
/// cursor.move_up(3);
/// }
///
/// ```
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'term> {
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'context> {
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_up(count, &self.terminal);
terminal_cursor.move_up(count, &self.context);
}
self
}
@ -99,22 +118,23 @@ impl <'term> TerminalCursor<'term>
/// #Example
///
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
///
/// // move 1 time right
/// cursor::cursor().move_right(1);
///
/// // move 2 times right
/// cursor::cursor().move_right(2);
///
// pub fn move_right()
// {
// let context = Context::new();
//
// // Get the cursor
// let mut cursor = cursor(&context);
// // Move the cursor to position 3 times to the right in the terminal
// cursor.move_right(3);
// }
/// ```
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'term> {
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'context> {
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_right(count, &self.terminal);
terminal_cursor.move_right(count, &self.context);
}
self
}
@ -126,19 +146,23 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// // move 1 time down
/// cursor::cursor().move_down(1);
/// pub fn move_down()
/// {
/// let context = Context::new();
///
/// // move 2 times down
/// cursor::cursor().move_down(2);
/// // Get the cursor
/// let mut cursor = cursor(&context);
/// // Move the cursor to position 3 times to the down in the terminal
/// cursor.move_down(3);
/// }
///
/// ```
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'term> {
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'context> {
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_down(count, &self.terminal);
terminal_cursor.move_down(count, &self.context);
}
self
}
@ -150,19 +174,23 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// // move 1 time left
/// cursor::cursor().move_left(1);
/// pub fn move_left()
/// {
/// let context = Context::new();
///
/// // move 2 time left
/// cursor::cursor().move_left(2);
/// // Get the cursor
/// let mut cursor = cursor(&context);
/// // Move the cursor to position 3 times to the left in the terminal
/// cursor.move_left(3);
/// }
///
/// ```
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'term> {
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'context> {
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_left(count, &self.terminal);
terminal_cursor.move_left(count, &self.context);
}
self
}
@ -184,23 +212,27 @@ impl <'term> TerminalCursor<'term>
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// use std;
/// use std::io::Write;
///
/// let context = Context::new();
///
/// // of course we can just do this.
/// cursor::cursor().goto(10,10);
/// cursor::cursor(&context).goto(10,10);
/// print!("@");
/// std::io::stdout().flush();
///
/// // but now we can chain the methods so it looks cleaner and it automatically flushes the buffer.
/// cursor::cursor()
/// cursor::cursor(&context)
/// .goto(10,10)
/// .print("@");
///
/// ```
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor<'term> {
let mut screen = self.terminal.screen_manager.lock().unwrap();
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor<'context> {
let mut screen = self.context.screen_manager.lock().unwrap();
{
write!(screen.stdout(), "{}", value);
// rust is line buffered so we need to flush the buffer in order to print it at the current cursor position.
@ -218,16 +250,17 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// cursor::cursor().safe_position();
/// let context = Context::new();
/// cursor::cursor(&context).safe_position();
///
/// ```
pub fn save_position(&mut self)
{
if let Some(ref mut terminal_cursor) = self.terminal_cursor {
terminal_cursor.save_position(&self.terminal);
terminal_cursor.save_position(&self.context);
}
}
@ -240,40 +273,43 @@ impl <'term> TerminalCursor<'term>
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::cursor::cursor;
/// use self::crossterm::Context;
///
/// cursor().reset_position();
/// let context = Context::new();
/// cursor(&context).reset_position();
///
/// ```
pub fn reset_position(&mut self)
{
if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.reset_position(&self.terminal);
terminal_cursor.reset_position(&self.context);
}
}
}
/// Get an TerminalCursor implementation whereon cursor related actions can be performed.
///
/// Check `/examples/cursor` in the libary for more spesific examples.
/// Check `/examples/version/cursor` in the libary for more spesific examples.
///
/// #Example
///
/// ```rust
///
/// extern crate crossterm;
///
/// use self::crossterm::Context;
/// use self::crossterm::cursor;
///
/// let context = Context::new();
///
/// // Get cursor and goto pos X: 5, Y: 10
/// let mut cursor = cursor::cursor();
/// let mut cursor = cursor::cursor(&context);
/// cursor.goto(5,10);
///
/// //Or you can do it in one line.
/// cursor::cursor().goto(5,10);
/// cursor::cursor(&context).goto(5,10);
///
/// ```
pub fn cursor<'term>(terminal: &'term Terminal) -> Box<TerminalCursor<'term>> {
Box::from(TerminalCursor::new(&terminal))
pub fn cursor<'context>(context: &'context Context) -> Box<TerminalCursor<'context>> {
Box::from(TerminalCursor::new(&context))
}

View File

@ -9,6 +9,7 @@
//!
pub mod cursor;
#[cfg(target_os = "windows")]
mod winapi_cursor;
mod ansi_cursor;
@ -17,7 +18,7 @@ mod ansi_cursor;
use self::winapi_cursor::WinApiCursor;
use self::ansi_cursor::AnsiCursor;
use Terminal;
use Context;
pub use self::cursor::{ cursor, TerminalCursor };
///! This trait defines the actions that can be preformed with the terminal cursor.
@ -29,20 +30,20 @@ pub use self::cursor::{ cursor, TerminalCursor };
///! This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminalCursor {
/// Goto some location (x,y) in the terminal.
fn goto(&self, x: u16, y: u16, terminal: &Terminal);
/// Get the location (x,y) of the current cusror in the terminal
fn pos(&self, terminal: &Terminal) -> (u16, u16);
/// Goto some location (x,y) in the context.
fn goto(&self, x: u16, y: u16, context: &Context);
/// Get the location (x,y) of the current cusror in the context
fn pos(&self, context: &Context) -> (u16, u16);
/// Move cursor n times up
fn move_up(&self, count: u16, terminal: &Terminal);
fn move_up(&self, count: u16, context: &Context);
/// Move the cursor `n` times to the right.
fn move_right(&self, count: u16, terminal: &Terminal);
fn move_right(&self, count: u16, context: &Context);
/// Move the cursor `n` times down.
fn move_down(&self, count: u16, terminal: &Terminal);
fn move_down(&self, count: u16, context: &Context);
/// Move the cursor `n` times left.
fn move_left(&self, count: u16, terminal: &Terminal);
/// Save cursor position for recall later. Note that this position is stored program based not per instance of the cursor struct.
fn save_position(&mut self, terminal: &Terminal);
fn move_left(&self, count: u16, context: &Context);
/// 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(&mut self, context: &Context);
/// Return to saved cursor position
fn reset_position(&self, terminal: &Terminal);
fn reset_position(&self, context: &Context);
}

View File

@ -1,58 +1,56 @@
//! 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 {Terminal, Construct};
use Context;
use super::ITerminalCursor;
use kernel::windows_kernel::{kernel, cursor};
/// This struct is an windows implementation for cursor related actions.
pub struct WinApiCursor;
impl Construct for WinApiCursor {
fn new() -> Box<WinApiCursor> {
impl WinApiCursor {
pub fn new() -> Box<WinApiCursor> {
Box::from(WinApiCursor { })
}
}
impl ITerminalCursor for WinApiCursor {
fn goto(&self, x: u16, y: u16, terminal: &Terminal) {
fn goto(&self, x: u16, y: u16, context: &Context) {
kernel::set_console_cursor_position(x as i16, y as i16);
}
fn pos(&self, terminal: &Terminal) -> (u16, u16) {
fn pos(&self, context: &Context) -> (u16, u16) {
cursor::pos()
}
fn move_up(&self, count: u16, terminal: &Terminal) {
fn move_up(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos();
self.goto(xpos, ypos - count);
}
fn move_right(&self, count: u16, terminal: &Terminal) {
fn move_right(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos();
self.goto(xpos + count, ypos);
}
fn move_down(&self, count: u16, terminal: &Terminal) {
fn move_down(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos();
self.goto(xpos, ypos + count);
}
fn move_left(&self, count: u16, terminal: &Terminal) {
fn move_left(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos();
self.goto(xpos - count, ypos);
}
fn save_position(&mut self, terminal: &Terminal)
fn save_position(&mut self, context: &Context)
{
cursor::save_cursor_pos();
}
fn reset_position(&self, terminal: &Terminal)
fn reset_position(&self, context: &Context)
{
cursor::reset_to_saved_position();
}

View File

@ -1,13 +1,14 @@
//! This module contains all `unix` specific terminal related logic.
use { libc, Context, Terminal };
use {libc, StateManager, Context, CommandManager};
use termios::Termios;
pub use self::libc::{termios};
use self::libc::{STDOUT_FILENO, TIOCGWINSZ, c_ushort, ioctl, c_int};
use state::commands::{ NoncanonicalModeCommand, IContextCommand} ;
use state::commands::{ NoncanonicalModeCommand, IStateCommand} ;
use std::io::Error;
use std::{ io, mem };
use std::rc::Rc;
/// A representation of the size of the current terminal.
#[repr(C)]
@ -40,16 +41,15 @@ pub fn terminal_size() -> (u16,u16) {
}
/// Get the current cursor position.
pub fn pos(terminal: &Terminal) -> (u16,u16)
pub fn pos(terminal: &Context) -> (u16, u16)
{
use std::io::{ Write,Read };
let mut command_id = NoncanonicalModeCommand::new(&terminal.state_manager);
let mut command = NoncanonicalModeCommand::new(&terminal.context);
command.0.execute(&terminal);
CommandManager::execute(terminal, command_id);
// This code is original written by term_cursor credits to them.
use std::io;
let mut std = io::stdout();
// Write command
@ -97,10 +97,8 @@ pub fn pos(terminal: &Terminal) -> (u16,u16)
// Expect `R`
let res = if c == 'R' { (cols as u16, rows as u16) } else { return (0, 0) };
let mut context = terminal.context.lock().unwrap();
{
context.undo_state(command.1, terminal);
}
CommandManager::undo(terminal, command_id);
res
}

View File

@ -1,6 +1,6 @@
//! This module handles the enabling `ANSI escape codes` for windows terminals.
use Context;
use StateManager;
use state::commands::ICommand;
static mut HAS_BEEN_TRYED_TO_ENABLE: bool = false;

View File

@ -23,6 +23,7 @@ pub fn save_cursor_pos()
}
}
/// get the current cursor position.
pub fn pos() -> (u16,u16)
{
let csbi = kernel::get_console_screen_buffer_info();

View File

@ -1,78 +0,0 @@
use winapi::um::winnt::HANDLE;
use std::mem::zeroed;
use winapi::um::processenv::{GetStdHandle};
use winapi::um::winbase::{STD_OUTPUT_HANDLE, STD_INPUT_HANDLE };
static mut ALTERNATEHANDLE: Option<HANDLE> = None;
static mut CONSOLE_OUTPUT_HANDLE: Option<HANDLE> = None;
static mut CONSOLE_INPUT_HANDLE: Option<HANDLE> = None;
pub fn register_new_alternate_handle(handle: Handle) -> HANDLE
{
unsafe
{
ALTERNATEHANDLE = handle;
}
ALTERNATEHANDLE.unwrap();
}
pub fn clear_alternate_screen()
{
unsafe
{
ALTERNATEHANDLE = None;
}
}
/// Get the std_output_handle of the console
pub fn get_output_handle() -> HANDLE {
unsafe {
if let Some(alternate_handle) = ALTERNATEHANDLE
{
alternate_handle
}
else if let Some(handle) = CONSOLE_OUTPUT_HANDLE {
handle
} else {
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
if !is_valid_handle(&handle)
{
panic!("Cannot get output handle")
}
CONSOLE_OUTPUT_HANDLE = Some(handle);
handle
}
}
}
/// Get the std_input_handle of the console
pub fn get_input_handle() -> HANDLE {
unsafe {
if let Some(handle) = CONSOLE_INPUT_HANDLE {
handle
} else {
let handle = GetStdHandle(STD_INPUT_HANDLE);
if !is_valid_handle(&handle)
{
panic!("Cannot get input handle")
}
CONSOLE_INPUT_HANDLE = Some(handle);
handle
}
}
}
/// Checks if the console handle is an invalid handle value.
pub fn is_valid_handle(handle: &HANDLE) -> bool {
if *handle == INVALID_HANDLE_VALUE {
false
} else {
true
}
}

View File

@ -58,7 +58,7 @@ pub fn get_input_handle() -> HANDLE {
}
/// Checks if the console handle is an invalid handle value.
pub fn is_valid_handle(handle: &HANDLE) -> bool {
fn is_valid_handle(handle: &HANDLE) -> bool {
if *handle == INVALID_HANDLE_VALUE {
false
} else {

View File

@ -1,4 +1,4 @@
//! This module contains the `windows` specific (unsafe) logic.
//! This module contains the `windows` specific logic.
pub mod kernel;
pub mod cursor;

View File

@ -14,12 +14,11 @@ pub mod terminal;
pub mod manager;
pub use shared::{screen, raw};
pub use state::context::Context;
use shared::traits::{Construct};
pub use state::{ Context };
pub use manager::manager::{ ScreenManager };
pub use shared::terminal::Terminal;
use state::command_manager::CommandManager;
use state::state_manager::StateManager;
use manager::ScreenManager;
#[cfg(windows)]
extern crate winapi;
@ -27,5 +26,3 @@ extern crate winapi;
extern crate libc;
#[cfg(unix)]
extern crate termios;
extern crate rand;

View File

@ -1,3 +1,7 @@
//! This is an ANSI specific implementation for the screen manager
//! This module is used for windows 10 terminals and unix terminals by default.
//! This module uses the stdout to write to the console.
use std::io::{self, Write};
use super::IScreenManager;
@ -24,24 +28,12 @@ impl<Output :Write> IScreenManager<Output> for AnsiScreenManager<Output>
{
write!(self.output, "{}", string);
self.flush();
// println!("test");
// match self.is_alternate_screen
// {
// true => ,
// false => write!(io::stdout(), "{}", string),
// };
}
fn write_ansi_str(&mut self, string: &str)
{
write!(self.output, "{}", string);
self.flush();
// println!("test");
// match self.is_alternate_screen
// {
// true => write!(self.output, "{}", string),
// false => write!(io::stdout(), "{}", string),
// };
}
}

View File

@ -1,8 +1,12 @@
use std::io::Write;
//! This module provides an interface for working with the sceen. 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. And this module provides this place.
use super::IScreenManager;
use super::ansi_manager::AnsiScreenManager;
use std::io::Write;
/// Struct that stores an specific platform implementation for screen related actions.
pub struct ScreenManager
{
screen_manager: Box<IScreenManager<Box<Write>>>
@ -10,6 +14,7 @@ pub struct ScreenManager
impl ScreenManager
{
/// Create new screen manager instance whereon screen related actions can be performed.
pub fn new() -> ScreenManager {
// #[cfg(target_os = "windows")]
// let cursor = functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new());
@ -22,6 +27,7 @@ impl ScreenManager
}
}
/// Get the stdout of the current screen
pub fn stdout(&mut self) -> &mut Box<Write>
{
self.screen_manager.stdout()
@ -32,11 +38,13 @@ impl ScreenManager
self.screen_manager.toggle_is_alternate_screen(is_alternate_screen);
}
/// Write an ANSI code as String.
pub fn write_ansi(&mut self, string: String)
{
self.screen_manager.write_ansi(string);
}
/// Write an ANSI code as &str
pub fn write_ansi_str(&mut self, string: &str)
{
self.screen_manager.write_ansi_str(string);

View File

@ -1,3 +1,6 @@
//! This module provides one place to work with the screen.
//! For example whe can write to the console true this module.
pub mod manager;
#[cfg(target_os = "windows")]
@ -12,8 +15,11 @@ pub use self::manager::{ ScreenManager };
pub trait IScreenManager<Output>
{
/// get the stdout of the screen. This can be used to write to the
fn stdout(&mut self) -> &mut Output;
fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool);
/// Write ansi code as String to the current stdout.
fn write_ansi(&mut self, string: String);
/// Write a &str to the current stdout.
fn write_ansi_str(&mut self, string: &str);
}

View File

@ -1,6 +1,6 @@
//! Some actions need to preformed platform independently since they can not be solved `ANSI escape codes`.
use Terminal;
use Context;
#[cfg(windows)]
use kernel::windows_kernel::terminal::terminal_size;
@ -20,7 +20,7 @@ pub fn get_terminal_size() -> (u16, u16)
}
/// Get the cursor position based on the current platform.
pub fn get_cursor_position(screen: &Terminal) -> (u16,u16)
pub fn get_cursor_position(screen: &Context) -> (u16, u16)
{
#[cfg(unix)]
return pos(&screen);

View File

@ -4,6 +4,5 @@
pub mod macros;
pub mod traits;
pub mod functions;
pub mod terminal;
pub mod screen;
pub mod raw;

View File

@ -24,49 +24,34 @@ use super::super::state::commands::unix_command::EnableRawModeCommand;
#[cfg(windows)]
use state::commands::win_commands::EnableRawModeCommand;
use { Terminal };
use state::commands::IContextCommand;
use {Context, CommandManager };
use state::commands::IStateCommand;
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<'a>
{
terminal : &'a Terminal,
terminal : &'a Context,
command_id: u16,
}
/// Trait withs contains a method for switching into raw mode.
pub trait IntoRawMode<'a>: Write + Sized
{
fn into_raw_mode(&self, terminal: &'a Terminal) -> io::Result<RawTerminal<'a>>;
fn into_raw_mode(&self, terminal: &'a Context) -> io::Result<RawTerminal<'a>>;
}
//impl<'a> IntoRawMode<'a> for RawTerminal<'a>
//{
// /// Switch to raw mode.
// ///
// /// 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, terminal: &'a Terminal) -> io::Result<RawTerminal>
// {
// let (mut command, command_id) = EnableRawModeCommand::new(&terminal.context);
// let success = command.execute(&terminal);
//
// if success
// {
// Ok(RawTerminal { terminal: terminal, command_id: command_id})
//
// }else { panic!("cannot move into raw mode") }
// }
//}
impl <'a, W: Write> IntoRawMode<'a> for W
{
fn into_raw_mode(&self, terminal: &'a Terminal) -> io::Result<RawTerminal<'a>> {
let (mut command, command_id) = EnableRawModeCommand::new(&terminal.context);
let success = command.execute(&terminal);
/// 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, terminal: &'a Context) -> io::Result<RawTerminal<'a>> {
let command_id = EnableRawModeCommand::new(&terminal.state_manager);
let success = CommandManager::execute(terminal, command_id);
if success
{
@ -96,9 +81,6 @@ impl <'a> Drop for RawTerminal<'a>
{
fn drop(&mut self)
{
let mut context = self.terminal.context.lock().unwrap();
{
context.undo_state(self.command_id, &self.terminal);
}
let success = CommandManager::undo(&self.terminal, self.command_id);
}
}

View File

@ -1,96 +1,57 @@
//! This module contains all the logic for switching between alternate screen and main screen.
use Terminal;
use Context;
use state::commands::*;
use std::io::{self, Write};
//pub struct ToMainScreen;
//
//impl fmt::Display for ToMainScreen
//{
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// get_to_alternate_screen_command().undo();
// Ok(())
// }
//}
//
///// Struct that switches to alternate screen buffer on display.
//pub struct ToAlternateScreen;
//
//impl fmt::Display for ToAlternateScreen
//{
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// get_to_alternate_screen_command().execute();
// Ok(())
// }
//}
/// Struct that can be used for writing to an alternate screen.
///
/// #Example
///
/// ```rust
/// extern crate crossterm;
/// use self::crossterm::terminal::screen;
/// use std::{time, thread};
/// ...
///
/// // Initialize and switch to the alternate screen from an std output handle.
/// // Now you can write to this screen.
/// let mut screen = screen::AlternateScreen::from(stdout());
/// // Write some text to the alternate screen.
/// write!(screen, "Welcome to the alternate screen. Wait 4 seconds to switch back").unwrap();
/// thread::sleep(time::Duration::from_secs(4));
/// // switch back to main screen.
/// write!(screen, "{}", screen::ToMainScreen);
/// write!(screen, "{}", "We are back again at the main screen");
///
/// ...
///
/// ```
pub struct AlternateScreen<'term> {
term: &'term Terminal
pub struct AlternateScreen<'context> {
context: &'context Context
}
impl<'term> AlternateScreen<'term> {
pub fn from(output: &'term Terminal) -> Self {
get_to_alternate_screen_command().execute(&output);
AlternateScreen { term: output }
impl<'context> AlternateScreen<'context> {
/// Get the alternate screen from the context.
/// By calling this method the current screen will be changed to the alternate screen.
/// And you get back an handle for that screen.
pub fn from(context: &'context Context) -> Self {
get_to_alternate_screen_command().execute(&context);
AlternateScreen { context: context }
}
/// Change the current screen to the mainscreen.
pub fn to_main(&self)
{
get_to_alternate_screen_command().undo(&self.term);
get_to_alternate_screen_command().undo(&self.context);
}
/// Change the current screen to alternate screen.
pub fn to_alternate(&self)
{
get_to_alternate_screen_command().execute(&self.term);
get_to_alternate_screen_command().execute(&self.context);
}
}
impl<'term> Write for AlternateScreen<'term> {
impl<'context> Write for AlternateScreen<'context> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut screen = self.term.screen_manager.lock().unwrap();
let mut screen = self.context.screen_manager.lock().unwrap();
{
screen.stdout().write(buf)
}
}
fn flush(&mut self) -> io::Result<()> {
let mut screen = self.term.screen_manager.lock().unwrap();
let mut screen = self.context.screen_manager.lock().unwrap();
{
screen.stdout().flush()
}
}
}
impl<'term> Drop for AlternateScreen<'term>
impl<'context> Drop for AlternateScreen<'context>
{
fn drop(&mut self)
{
get_to_alternate_screen_command().undo(&self.term);
get_to_alternate_screen_command().undo(&self.context);
}
}

View File

@ -1,82 +0,0 @@
use std::sync::Mutex;
use std::rc::Rc;
use { Context, ScreenManager};
//use super::super::terminal;
//use super::super::cursor;
use super::super::style;
use std::fmt;
pub struct Terminal
{
pub screen_manager: Rc<Mutex<ScreenManager>>,
pub context: Mutex<Context>
}
impl Terminal
{
pub fn new() -> Terminal
{
Terminal {
screen_manager: Rc::new(Mutex::new(ScreenManager::new())),
context: Mutex::new(Context::new())
}
}
/// Get an TerminalColor implementation whereon color related actions can be performed.
///
/// # Example
///
/// ```rust
/// extern crate crossterm;
///
/// use self::crossterm::style::{color, Color};
///
/// // Get colored terminal instance
/// let mut colored_terminal = color();
///
/// // preform some actions on the colored terminal
/// colored_terminal.set_fg(Color::Red);
/// colored_terminal.set_bg(Color::Blue);
/// colored_terminal.reset();
/// ```
pub fn color(&self) -> Box<style::TerminalColor> {
Box::from(style::TerminalColor::new(self.screen_manager.clone()))
}
/// Wraps an displayable object so it can be formatted with colors and attributes.
///
/// Check `/examples/color` in the libary for more spesific examples.
///
/// #Example
///
/// ```rust
/// extern crate crossterm;
///
/// use self::crossterm::style::{paint,Color};
///
/// fn main()
/// {
/// // Create an styledobject object from the text 'Unstyled font'
/// // Currently it has the default foregroundcolor and backgroundcolor.
/// println!("{}",paint("Unstyled font"));
///
/// // Create an displayable object from the text 'Colored font',
/// // Paint this with the `Red` foreground color and `Blue` backgroundcolor.
/// // Print the result.
/// let styledobject = paint("Colored font").with(Color::Red).on(Color::Blue);
/// println!("{}", styledobject);
///
/// // Or all in one line
/// println!("{}", paint("Colored font").with(Color::Red).on(Color::Blue));
/// }
/// ```
pub fn paint<D>(&self, val: D) -> style::StyledObject<D>
where
D: fmt::Display,
{
style::ObjectStyle::new().apply_to(val, self.screen_manager.clone())
}
}

View File

@ -1,11 +1,3 @@
/// This trait is used for creating an instance of an concrete implementation from an base trait.
/// This trait allows the output to be different in size.
pub trait Construct{
fn new() -> Box<Self>
where
Self: Sized;
}
/// This trait can be used to create an empty instance of an struct.
pub trait Empty {
fn empty() -> Self;

View File

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

View File

@ -7,9 +7,10 @@
//! 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 `Context` struct where we store the commands for more info.
//! See the `StateManager` struct where we store the commands for more info.
use std::sync::Mutex;
use std::rc::Rc;
#[cfg(unix)]
pub mod unix_command;
@ -24,22 +25,21 @@ pub use self::unix_command::*;
#[cfg(windows)]
pub use self::win_commands::*;
use { Context, Terminal };
use {StateManager, Context};
/// This command can be used for simple commands witch just have an `undo()` and an `execute()`
pub trait ICommand
{
fn new() -> Box<Self> where Self: Sized;
fn execute(&mut self, terminal: &Terminal) -> bool;
fn undo(&mut self, terminal: &Terminal) -> bool;
fn execute(&mut self, terminal: &Context) -> bool;
fn undo(&mut self, terminal: &Context) -> bool;
}
/// 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 IContextCommand
pub trait IStateCommand
{
fn new(context: &Mutex<Context>) -> (Box<Self>, u16) where Self: Sized;
fn execute(&mut self, terminal: &Terminal) -> bool;
fn undo(&mut self, terminal: &Terminal) -> bool;
fn execute(&mut self, terminal: &Context) -> bool;
fn undo(&mut self, terminal: &Context) -> bool;
}

View File

@ -1,6 +1,21 @@
//! This module contains the commands that can be used for both unix and windows systems.
use Terminal ;
use super::ICommand;
//! This module contains the commands that can be used for both unix and windows systems. Or else said terminals that support ansi codes.
use Context;
use super::{ICommand, IStateCommand};
pub struct EmptyCommand;
impl IStateCommand for EmptyCommand
{
fn execute(&mut self, terminal: &Context) -> bool
{
return false
}
fn undo(&mut self, terminal: &Context) -> bool
{
return false;
}
}
/// This command is used for switching to alternate screen and back to main screen.
#[derive(Clone, Copy)]
@ -12,7 +27,7 @@ impl ICommand for ToAlternateScreenBufferCommand
Box::from(ToAlternateScreenBufferCommand {})
}
fn execute(&mut self, terminal: &Terminal) -> bool
fn execute(&mut self, terminal: &Context) -> bool
{
let mut screen = terminal.screen_manager.lock().unwrap();
{
@ -22,7 +37,7 @@ impl ICommand for ToAlternateScreenBufferCommand
}
}
fn undo(&mut self, terminal: &Terminal) -> bool
fn undo(&mut self, terminal: &Context) -> bool
{
let mut screen = terminal.screen_manager.lock().unwrap();
{

View File

@ -1,13 +1,14 @@
//! This module contains the commands that can be used for unix systems.
use {Terminal, Context};
use super::IContextCommand;
use {Context, StateManager, CommandManager};
use super::IStateCommand;
use kernel::unix_kernel::terminal;
use termios::{Termios, tcsetattr, TCSAFLUSH, ICANON, ECHO, CREAD};
const FD_STDIN: ::std::os::unix::io::RawFd = 1;
use std::sync::Mutex;
use std::rc::Rc;
/// This command is used for switching to NoncanonicalMode.
#[derive(Copy, Clone)]
@ -16,20 +17,24 @@ pub struct NoncanonicalModeCommand
key: u16
}
impl IContextCommand for NoncanonicalModeCommand
impl NoncanonicalModeCommand
{
pub fn new(state: &Mutex<StateManager>) -> u16
{
fn new(context: &Mutex<Context>) -> (Box<NoncanonicalModeCommand>, u16) {
let key = 1;
let mut context = context.lock().unwrap();
let mut state_manager = state.lock().unwrap();
{
let command = NoncanonicalModeCommand { key: key };
context.register_change(Box::from(command), key);
(Box::from(command),key)
let command = Box::from(NoncanonicalModeCommand { key: key });
state_manager.register_change(command, key);
key
}
}
}
fn execute(&mut self, terminal: &Terminal) -> bool
impl IStateCommand for NoncanonicalModeCommand
{
fn execute(&mut self, terminal: &Context) -> bool
{
// Set noncanonical mode
if let Ok(orig) = Termios::from_fd(FD_STDIN)
@ -48,7 +53,7 @@ impl IContextCommand for NoncanonicalModeCommand
}
}
fn undo(&mut self, terminal: &Terminal) -> bool
fn undo(&mut self, terminal: &Context) -> bool
{
// Disable noncanonical mode
if let Ok(orig) = Termios::from_fd(FD_STDIN)
@ -70,34 +75,35 @@ impl IContextCommand for NoncanonicalModeCommand
}
/// This command is used for enabling and disabling raw mode for the terminal.
#[derive(Copy, Clone)]
pub struct EnableRawModeCommand
{
original_mode: Option<Termios>,
original_mode: Option<Box<Termios>>,
command_id: u16
}
impl IContextCommand for EnableRawModeCommand
impl EnableRawModeCommand
{
fn new(context: &Mutex<Context>) -> (Box<EnableRawModeCommand>, u16) {
pub fn new(state_manager: &Mutex<StateManager>) -> u16{
let key = 2;
let mut context = context.lock().unwrap();
let mut state = state_manager.lock().unwrap();
{
let command = EnableRawModeCommand { original_mode: None, command_id: key };
context.register_change(Box::from(command), key);
(Box::from(command), key)
state.register_change(Box::from(command), key);
key
}
}
}
fn execute(&mut self, terminal: &Terminal) -> bool
impl IStateCommand for EnableRawModeCommand
{
fn execute(&mut self, terminal: &Context) -> bool
{
let original_mode = terminal::get_terminal_mode();
if let Ok(original_mode) = original_mode
{
panic!("setting {:?}", original_mode);
self.original_mode = Some(original_mode);
self.original_mode = Some(Box::from(original_mode));
let mut new_mode = original_mode;
terminal::make_raw(&mut new_mode);
terminal::set_terminal_mode(&new_mode);
@ -108,12 +114,10 @@ impl IContextCommand for EnableRawModeCommand
}
}
fn undo(&mut self, terminal: &Terminal) -> bool
fn undo(&mut self, terminal: &Context) -> bool
{
panic!("undoing {:?}", self.original_mode);
if let Some(original_mode) = self.original_mode
if let Some(ref original_mode) = self.original_mode
{
let result = terminal::set_terminal_mode(&original_mode);
match result

View File

@ -1,7 +1,7 @@
//! This module contains the commands that can be used for windows systems.
use super::{ICommand, IContextCommand};
use super::super::Context;
use super::{ICommand, IStateCommand};
use super::super::StateManager;
use kernel::windows_kernel::{kernel, ansi_support};
use winapi::shared::minwindef::DWORD;
@ -9,6 +9,7 @@ use winapi::um::wincon;
use winapi::um::wincon::{ENABLE_VIRTUAL_TERMINAL_PROCESSING ,SMALL_RECT, COORD, CHAR_INFO};
use std::mem;
use std::rc::Rc;
use std::sync::Mutex;
/// This command is used for enabling and disabling ANSI code support for windows systems,
@ -88,15 +89,17 @@ pub struct EnableRawModeCommand
key: i16
}
impl IContextCommand for EnableRawModeCommand
impl IStateCommand for EnableRawModeCommand
{
fn new(context: &mut Context) -> (Box<EnableRawModeCommand>, i16) {
fn new(state: &mut StateManager) -> (Box<EnableRawModeCommand>, i16) {
use self::wincon::{ENABLE_LINE_INPUT,ENABLE_PROCESSED_INPUT, ENABLE_PROCESSED_OUTPUT, ENABLE_WRAP_AT_EOL_OUTPUT, ENABLE_ECHO_INPUT};
let key = super::generate_key();
let command = EnableRawModeCommand { mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT, key: key };
context.register_change(Box::from(command), key);
(Box::from(command),key)
let rc = Rc::new(command);
state.register_change(rc.clone(), key);
(rc.clone(),key)
}
fn execute(&mut self, terminal: &Terminal) -> bool
@ -154,7 +157,7 @@ impl ICommand for ToAlternateScreenBufferCommand
Box::from(ToAlternateScreenBufferCommand {})
}
fn execute(&mut self, context: &Context) -> bool
fn execute(&mut self, state: &StateManager) -> bool
{
let mut chi_buffer: [CHAR_INFO;160] = unsafe {mem::zeroed() };
@ -208,7 +211,7 @@ impl ICommand for ToAlternateScreenBufferCommand
true
}
fn undo(&mut self, context: &Context) -> bool
fn undo(&mut self, state: &StateManager) -> bool
{
let handle = kernel::get_output_handle();
kernel::set_active_screen_buffer(handle);

View File

@ -1,65 +1,92 @@
//! This module is used for registering, storing an restoring the terminal state changes.
//! This module contains the code for the context of the terminal.
use std::collections::HashMap;
use super::commands::IContextCommand;
use Terminal;
/// Struct that stores the changed states of the terminal.
use std::sync::Mutex;
use std::rc::Rc;
use super::super::style;
use { StateManager, ScreenManager };
use std::fmt;
/// This type contains the context of the current terminal. The context surrounds the changed states of the terminal and can be used for managing the output of the terminal.
pub struct Context
{
changed_states: HashMap<u16, Box<IContextCommand>>,
pub screen_manager: Rc<Mutex<ScreenManager>>,
pub state_manager: Mutex<StateManager>
}
impl Context
{
/// Create new Context where the terminals states can be handled.
/// 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 managin 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() -> Context
{
Context {
changed_states: HashMap::new(),
screen_manager: Rc::new(Mutex::new(ScreenManager::new())),
state_manager: Mutex::new(StateManager::new())
}
}
// /// Restore all changes that are made to the terminal.
// pub fn restore_changes(&mut self)
// {
// use std::iter::FromIterator;
//
// let mut buffer = Vec::new();
//
// for i in 0..self.changed_states.len()
// {
// buffer[i] = self.changed_states.iter().nth(i).unwrap();
// }
//
// for i in 0..buffer.len()
// {
// buffer[i].1.undo(self);
// }
// }
/// Register new changed state with the given key.
pub fn register_change(&mut self, change: Box<IContextCommand>, key: u16)
/// Wraps an displayable object so it can be formatted with colors and attributes.
///
/// Check `/examples/color` in the libary for more spesific examples.
///
/// #Example
///
/// ```rust
/// extern crate crossterm;
///
/// use self::crossterm::style::{paint,Color};
///
/// fn main()
/// {
/// // Create an styledobject object from the text 'Unstyled font'
/// // Currently it has the default foregroundcolor and backgroundcolor.
/// println!("{}",paint("Unstyled font"));
///
/// // Create an displayable object from the text 'Colored font',
/// // Paint this with the `Red` foreground color and `Blue` backgroundcolor.
/// // Print the result.
/// let styledobject = paint("Colored font").with(Color::Red).on(Color::Blue);
/// println!("{}", styledobject);
///
/// // Or all in one line
/// println!("{}", paint("Colored font").with(Color::Red).on(Color::Blue));
/// }
/// ```
pub fn paint<D>(&self, val: D) -> style::StyledObject<D>
where
D: fmt::Display,
{
if !self.changed_states.contains_key(&key)
style::ObjectStyle::new().apply_to(val, self.screen_manager.clone())
}
}
impl Drop for Context
{
self.changed_states.insert(key, change);
}
}
/// Undo an specific state by the given state key.
pub fn undo_state(&mut self, state_key: u16, terminal: &Terminal)
fn drop(&mut self)
{
if self.changed_states.contains_key(&state_key)
{
{
let mut command = self.changed_states.get_mut(&state_key).unwrap();
command.undo(&terminal);
}
&self.changed_states.remove(&state_key);
let mut changes = self.state_manager.lock().unwrap();
changes.restore_changes(&self);
}
}
}

View File

@ -3,7 +3,7 @@
//! 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.
mod context;
pub mod state_manager;
pub mod commands;
pub use self::context::{Context};
pub mod command_manager;
pub mod context;

View File

@ -0,0 +1,56 @@
//! This module is used for registering, storing an restoring the terminal state changes.
use Context;
use super::commands::IStateCommand;
use super::commands::shared_commands::EmptyCommand;
use std::rc::Rc;
use std::sync::Mutex;
use std::collections::HashMap;
/// 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, context: &Context)
{
for (id, item) in self.changed_states.iter_mut()
{
let mut item = item.lock().unwrap();
item.undo(&context);
}
}
/// 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)))
}
}

View File

@ -1,7 +1,7 @@
//! This is an ANSI specific implementation for styling related action.
//! This module is used for windows 10 terminals and unix terminals by default.
use { Construct, ScreenManager };
use ScreenManager;
use super::ITerminalColor;
use super::super::{Color, ColorType};
@ -12,8 +12,8 @@ use std::sync::Mutex;
#[derive(Debug)]
pub struct AnsiColor;
impl Construct for AnsiColor {
fn new() -> Box<AnsiColor> {
impl AnsiColor {
pub fn new() -> Box<AnsiColor> {
Box::from(AnsiColor {})
}
}

View File

@ -2,10 +2,9 @@
//! Like styling the font, foreground color and background.
use super::*;
use Construct;
use style::Color;
use std::{ io };
use std::io;
use std::rc::Rc;
use std::sync::Mutex;
@ -35,9 +34,12 @@ impl TerminalColor {
/// extern crate crossterm;
///
/// use self::crossterm::style::{ color, Color};
/// use crossterm::Context;
///
/// let context = Context::new();
///
/// // Get colored terminal instance
/// let mut colored_terminal = color();
/// let mut colored_terminal = color(&context);
///
/// // Set foreground color of the font
/// colored_terminal.set_fg(Color::Red);
@ -60,9 +62,12 @@ impl TerminalColor {
/// extern crate crossterm;
///
/// use self::crossterm::style::{ color, Color};
/// use crossterm::Context;
///
/// let context = Context::new();
///
/// // Get colored terminal instance
/// let mut colored_terminal = color();
/// let mut colored_terminal = color(&context);
///
/// // Set background color of the font
/// colored_terminal.set_bg(Color::Red);
@ -83,9 +88,12 @@ impl TerminalColor {
/// extern crate crossterm;
///
/// use self::crossterm::style::color;
/// use crossterm::Context;
///
/// let context = Context::new();
///
/// // Get colored terminal instance
/// let mut colored_terminal = color();
/// let mut colored_terminal = color(&context);
///
/// colored_terminal.reset();
///
@ -114,6 +122,10 @@ impl TerminalColor {
}
}
/// Get an Color implementation whereon color related actions can be performed.
///
/// Check `/examples/version/color` in the libary for more specific examples.
///
pub fn color(screen_manager: Rc<Mutex<ScreenManager>>) -> Box<TerminalColor> {
Box::from(TerminalColor::new(screen_manager.clone()))
}

View File

@ -7,13 +7,13 @@ mod ansi_color;
#[cfg(target_os = "windows")]
use self::winapi_color::WinApiColor;
use self::ansi_color::AnsiColor;
use { ScreenManager };
use super::{Color, ColorType};
use std::rc::Rc;
use std::sync::Mutex;
use { ScreenManager };
///! 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.

View File

@ -5,7 +5,6 @@ mod color;
mod styles;
pub use self::color::color::{color, TerminalColor };
pub use self::styles::objectstyle::ObjectStyle;
pub use self::styles::styledobject::StyledObject;

View File

@ -5,6 +5,7 @@ use style::{Color, StyledObject};
use ScreenManager;
use std::sync::Mutex;
use std::rc::Rc;
#[cfg(unix)]
use super::super::Attribute;

View File

@ -1,4 +1,4 @@
//! This module contains the logic to style an object that contains some context witch can be styled.
//! This module contains the logic to style an object that contains some state witch can be styled.
use std::fmt;
use std::io::Write;

View File

@ -1,7 +1,7 @@
//! This is an `ANSI escape code` specific implementation for terminal related action.
//! This module is used for windows 10 terminals and unix terminals by default.
use {Construct, Terminal};
use Context;
use shared::functions;
use super::{ClearType, ITerminal};
@ -10,16 +10,16 @@ use std::io::Write;
/// This struct is an ansi implementation for terminal related actions.
pub struct AnsiTerminal;
impl Construct for AnsiTerminal {
fn new() -> Box<AnsiTerminal> {
impl AnsiTerminal {
pub fn new() -> Box<AnsiTerminal> {
Box::from(AnsiTerminal {})
}
}
impl ITerminal for AnsiTerminal {
fn clear(&self, clear_type: ClearType, terminal: &Terminal) {
fn clear(&self, clear_type: ClearType, context: &Context) {
let mut screen_manager = terminal.screen_manager.lock().unwrap();
let mut screen_manager = context.screen_manager.lock().unwrap();
{
let stdout = screen_manager.stdout();
@ -43,26 +43,26 @@ impl ITerminal for AnsiTerminal {
}
}
fn terminal_size(&self, terminal: &Terminal) -> (u16, u16) {
fn terminal_size(&self, context: &Context) -> (u16, u16) {
functions::get_terminal_size()
}
fn scroll_up(&self, count: i16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn scroll_up(&self, count: i16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{}S"), count));
}
}
fn scroll_down(&self, count: i16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn scroll_down(&self, count: i16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("{}T"), count));
}
}
fn set_size(&self, width: i16, height: i16, terminal: &Terminal) {
let mut screen = terminal.screen_manager.lock().unwrap();
fn set_size(&self, width: i16, height: i16, context: &Context) {
let mut screen = context.screen_manager.lock().unwrap();
{
screen.write_ansi(format!(csi!("8;{};{}t"), width, height));
}

View File

@ -4,14 +4,7 @@
//! - alternate screen
//! - raw mode
//! - clearing resizing scrolling the terminal.
use Terminal;
use self::ansi_terminal::AnsiTerminal;
pub use self::terminal::{ terminal};
#[cfg(target_os = "windows")]
use self::winapi_terminal::WinApiTerminal;
//!
pub mod terminal;
@ -19,6 +12,13 @@ pub mod terminal;
mod winapi_terminal;
mod ansi_terminal;
#[cfg(target_os = "windows")]
use self::winapi_terminal::WinApiTerminal;
use self::ansi_terminal::AnsiTerminal;
use Context;
pub use self::terminal::{ terminal};
/// Enum that can be used for the kind of clearing that can be done in the terminal.
pub enum ClearType {
All,
@ -38,13 +38,13 @@ pub enum ClearType {
///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminal {
/// Clear the current cursor by specifying the clear type
fn clear(&self, clear_type: ClearType, terminal: &Terminal);
fn clear(&self, clear_type: ClearType, context: &Context);
/// Get the terminal size (x,y)
fn terminal_size(&self, terminal: &Terminal) -> (u16, u16);
fn terminal_size(&self, context: &Context) -> (u16, u16);
/// Scroll `n` lines up in the current terminal.
fn scroll_up(&self, count: i16, terminal: &Terminal);
fn scroll_up(&self, count: i16, context: &Context);
/// Scroll `n` lines down in the current terminal.
fn scroll_down(&self, count: i16, terminal: &Terminal);
fn scroll_down(&self, count: i16, context: &Context);
/// Resize terminal to the given width and height.
fn set_size(&self,width: i16, height: i16, terminal: &Terminal);
fn set_size(&self,width: i16, height: i16, context: &Context);
}

View File

@ -2,25 +2,27 @@
//! Like clearing and scrolling in the terminal or getting the size of the terminal.
use super::*;
use Construct;
use super::super::shared::terminal;
use Context;
use super::super::style;
use std::fmt;
/// Struct that stores an specific platform implementation for terminal related actions.
pub struct Terminal<'terminal> {
pub struct Terminal<'context> {
terminal: Option<Box<ITerminal>>,
term: &'terminal terminal::Terminal
context: &'context Context
}
impl<'terminal> Terminal<'terminal> {
impl<'context> Terminal<'context> {
/// Create new terminal instance whereon terminal related actions can be performed.
pub fn new(term: &'terminal terminal::Terminal) -> Terminal<'terminal> {
pub fn new(context: &'context Context) -> Terminal<'context> {
#[cfg(target_os = "windows")]
let terminal = functions::get_module::<Box<ITerminal>>(WinApiTerminal::new(), AnsiTerminal::new());
#[cfg(not(target_os = "windows"))]
let terminal = Some(AnsiTerminal::new() as Box<ITerminal>);
Terminal { terminal, term }
Terminal { terminal, context: context }
}
@ -32,8 +34,10 @@ impl<'terminal> Terminal<'terminal> {
///
/// extern crate crossterm;
/// use crossterm::terminal;
/// use crossterm::Context;
///
/// let mut term = terminal::terminal();
/// let context = Context::new();
/// let mut term = terminal::terminal(&context);
///
/// // clear all cells in terminal.
/// term.clear(terminal::ClearType::All);
@ -49,7 +53,7 @@ impl<'terminal> Terminal<'terminal> {
/// ```
pub fn clear(&mut self, clear_type: ClearType) {
if let Some(ref terminal) = self.terminal {
terminal.clear(clear_type, &self.term);
terminal.clear(clear_type, &self.context);
}
}
@ -61,8 +65,10 @@ impl<'terminal> Terminal<'terminal> {
///
/// extern crate crossterm;
/// use crossterm::terminal;
/// use crossterm::Context;
///
/// let mut term = terminal::terminal();
/// let context = Context::new();
/// let mut term = terminal::terminal(&context);
///
/// let size = term.terminal_size();
/// println!("{:?}", size);
@ -70,7 +76,7 @@ impl<'terminal> Terminal<'terminal> {
/// ```
pub fn terminal_size(&mut self) -> (u16, u16) {
if let Some(ref terminal) = self.terminal {
return terminal.terminal_size(&self.term)
return terminal.terminal_size(&self.context)
}
(0,0)
}
@ -83,8 +89,10 @@ impl<'terminal> Terminal<'terminal> {
///
/// extern crate crossterm;
/// use crossterm::terminal;
/// use crossterm::Context;
///
/// let mut term = terminal::terminal();
/// let context = Context::new();
/// let mut term = terminal::terminal(&context);
///
/// // scroll up by 5 lines
/// let size = term.scroll_up(5);
@ -92,7 +100,7 @@ impl<'terminal> Terminal<'terminal> {
/// ```
pub fn scroll_up(&mut self, count: i16) {
if let Some(ref terminal) = self.terminal {
terminal.scroll_up(count,&self.term);
terminal.scroll_up(count,&self.context);
}
}
@ -104,8 +112,10 @@ impl<'terminal> Terminal<'terminal> {
///
/// extern crate crossterm;
/// use crossterm::terminal;
/// use crossterm::Context;
///
/// let mut term = terminal::terminal();
/// let context = Context::new();
/// let mut term = terminal::terminal(&context);
///
/// // scroll down by 5 lines
/// let size = term.scroll_down(5);
@ -113,7 +123,7 @@ impl<'terminal> Terminal<'terminal> {
/// ```
pub fn scroll_down(&mut self, count: i16) {
if let Some(ref terminal) = self.terminal {
terminal.scroll_down(count, &self.term);
terminal.scroll_down(count, &self.context);
}
}
@ -125,8 +135,10 @@ impl<'terminal> Terminal<'terminal> {
///
/// extern crate crossterm;
/// use crossterm::terminal;
/// use crossterm::Context;
///
/// let mut term = terminal::terminal();
/// let context = Context::new();
/// let mut term = terminal::terminal(&context);
///
/// // Set of the size to X: 10 and Y: 10
/// let size = term.set_size(10,10);
@ -135,14 +147,48 @@ impl<'terminal> Terminal<'terminal> {
pub fn set_size(&mut self, width: i16, height: i16)
{
if let Some (ref terminal) = self.terminal {
terminal.set_size(width,height,&self.term);
terminal.set_size(width,height,&self.context);
}
}
/// Wraps an displayable object so it can be formatted with colors and attributes.
///
/// Check `/examples/color` in the libary for more spesific examples.
///
/// #Example
///
/// ```rust
/// extern crate crossterm;
///
/// use self::crossterm::style::{paint,Color};
///
/// fn main()
/// {
/// // Create an styledobject object from the text 'Unstyled font'
/// // Currently it has the default foregroundcolor and backgroundcolor.
/// println!("{}",paint("Unstyled font"));
///
/// // Create an displayable object from the text 'Colored font',
/// // Paint this with the `Red` foreground color and `Blue` backgroundcolor.
/// // Print the result.
/// let styledobject = paint("Colored font").with(Color::Red).on(Color::Blue);
/// println!("{}", styledobject);
///
/// // Or all in one line
/// println!("{}", paint("Colored font").with(Color::Red).on(Color::Blue));
/// }
/// ```
pub fn paint<D>(&self, val: D) -> style::StyledObject<D>
where
D: fmt::Display,
{
style::ObjectStyle::new().apply_to(val, self.context.screen_manager.clone())
}
}
/// Get an Terminal implementation whereon terminal related actions can be performed.
///
/// Check `/examples/terminal` in the libary for more spesific examples.
/// Check `/examples/version/terminal` in the libary for more spesific examples.
///
/// #Example
///
@ -150,16 +196,17 @@ impl<'terminal> Terminal<'terminal> {
///
/// extern crate crossterm;
/// use crossterm::terminal;
/// use crossterm::Context;
///
/// let mut term = terminal::terminal();
/// let context = Context::new();
///
/// let mut term = terminal::terminal(&context);
///
/// // scroll down by 5 lines
/// let size = term.scroll_down(5);
///
/// ```
///
///
pub fn terminal<'terminal>(terminal: &'terminal terminal::Terminal) -> Box<Terminal<'terminal>> {
Box::from(Terminal::new(&terminal))
pub fn terminal<'context>(context: &'context Context) -> Box<Terminal<'context>> {
Box::from(Terminal::new(&context))
}

View File

@ -1,5 +1,5 @@
//! This is an `WINAPI` specific implementation for terminal related action.
//! This module is used for windows 10 terminals and unix terminals by default.
//! This module is used for non supporting `ANSI` windows terminals.
use {Construct};
use cursor::cursor;