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; extern crate crossterm;
mod terminal; mod terminal;
mod cursor;
mod color;
use terminal::alternate_screen; use terminal::alternate_screen;
use terminal::raw_mode; 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() { fn main() {
// alternate_screen::switch_between_main_and_alternate_screen();
let context = Context::new();
raw_mode::print_wait_screen_on_alternate_window(); raw_mode::print_wait_screen_on_alternate_window();
} }

View File

@ -5,43 +5,54 @@
extern crate crossterm; extern crate crossterm;
use self::crossterm::style::{ Color }; use self::crossterm::style::{ Color };
use self::crossterm::terminal;
use self::crossterm::Context;
/// print some red font | demonstration. /// print some red font | demonstration.
pub fn paint_foreground() 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. // 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. // 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. // Call the method `with()` on the object given by `paint()` and pass in any Color from the Color enum.
styledobject = styledobject.with(Color::Red); styledobject = styledobject.with(Color::Red);
// Print the object to the console and see the result. // Print the object to the console and see the result.
println!("{}", styledobject); println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined. // 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. /// print some font on red background | demonstration.
pub fn paint_background() 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. // 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. // 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. // Call the method `on()` on the object given by `paint()` and pass in an Color from the Color enum.
styledobject = styledobject.on(Color::Red); styledobject = styledobject.on(Color::Red);
// Print the object to the console and check see the result // Print the object to the console and check see the result
println!("{}", styledobject); println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined. // 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. /// print font with fore- background color | demonstration.
pub fn paint_foreground_and_background() 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. // 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. // 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: /* Foreground color:
Call the method `with()` on the object given by `paint()` Call the method `with()` on the object given by `paint()`
Pass in an Color from the Color enum. Pass in an Color from the Color enum.
@ -56,77 +67,89 @@ pub fn paint_foreground_and_background()
println!("{}", styledobject); println!("{}", styledobject);
// Crossterm provides method chaining so that the above points can be inlined. // 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. /// Print all available foreground colors | demonstration.
pub fn print_all_foreground_colors() pub fn print_all_foreground_colors()
{ {
println!("Black : \t {}", paint("").with(Color::Black)); let context = Context::new();
println!("Red : \t\t {}", paint("").with(Color::Red)); let terminal = terminal::terminal(&context);
println!("Dark Red: \t {}", paint("").with(Color::DarkRed));
println!("Green : \t {}", paint("").with(Color::Green)); println!("Black : \t {}", terminal.paint("").with(Color::Black));
println!("Dark Green : \t {}", paint("").with(Color::DarkGreen)); println!("Red : \t\t {}", terminal.paint("").with(Color::Red));
println!("Yellow : \t {}", paint("").with(Color::Yellow)); println!("Dark Red: \t {}", terminal.paint("").with(Color::DarkRed));
println!("Dark Yellow : \t {}", paint("").with(Color::DarkYellow)); println!("Green : \t {}", terminal.paint("").with(Color::Green));
println!("Blue : \t\t {}", paint("").with(Color::Blue)); println!("Dark Green : \t {}", terminal.paint("").with(Color::DarkGreen));
println!("Dark Blue : \t {}", paint("").with(Color::DarkBlue)); println!("Yellow : \t {}", terminal.paint("").with(Color::Yellow));
println!("Magenta : \t {}", paint("").with(Color::Magenta)); println!("Dark Yellow : \t {}", terminal.paint("").with(Color::DarkYellow));
println!("Dark Magenta : \t {}", paint("").with(Color::DarkMagenta)); println!("Blue : \t\t {}", terminal.paint("").with(Color::Blue));
println!("Cyan : \t\t {}", paint("").with(Color::Cyan)); println!("Dark Blue : \t {}", terminal.paint("").with(Color::DarkBlue));
println!("Dark Cyan : \t {}", paint("").with(Color::DarkCyan)); println!("Magenta : \t {}", terminal.paint("").with(Color::Magenta));
println!("Grey : \t\t {}", paint("").with(Color::Grey)); println!("Dark Magenta : \t {}", terminal.paint("").with(Color::DarkMagenta));
println!("White : \t {}", paint("").with(Color::White)); 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. /// Print all available foreground colors | demonstration.
pub fn print_all_background_colors() pub fn print_all_background_colors()
{ {
println!("Black : \t {}", paint(" ").on(Color::Black)); let context = Context::new();
println!("Red : \t\t {}", paint(" ").on(Color::Red)); let terminal = terminal::terminal(&context);
println!("Dark Red: \t {}", paint(" ").on(Color::DarkRed));
println!("Green : \t {}", paint(" ").on(Color::Green)); println!("Black : \t {}", terminal.paint(" ").on(Color::Black));
println!("Dark Green : \t {}", paint(" ").on(Color::DarkGreen)); println!("Red : \t\t {}", terminal.paint(" ").on(Color::Red));
println!("Yellow : \t {}", paint(" ").on(Color::Yellow)); println!("Dark Red: \t {}", terminal.paint(" ").on(Color::DarkRed));
println!("Dark Yellow : \t {}", paint(" ").on(Color::DarkYellow)); println!("Green : \t {}", terminal.paint(" ").on(Color::Green));
println!("Blue : \t\t {}", paint(" ").on(Color::Blue)); println!("Dark Green : \t {}", terminal.paint(" ").on(Color::DarkGreen));
println!("Dark Blue : \t {}", paint(" ").on(Color::DarkBlue)); println!("Yellow : \t {}", terminal.paint(" ").on(Color::Yellow));
println!("Magenta : \t {}", paint(" ").on(Color::Magenta)); println!("Dark Yellow : \t {}", terminal.paint(" ").on(Color::DarkYellow));
println!("Dark Magenta : \t {}", paint(" ").on(Color::DarkMagenta)); println!("Blue : \t\t {}", terminal.paint(" ").on(Color::Blue));
println!("Cyan : \t\t {}", paint(" ").on(Color::Cyan)); println!("Dark Blue : \t {}", terminal.paint(" ").on(Color::DarkBlue));
println!("Dark Cyan : \t {}", paint(" ").on(Color::DarkCyan)); println!("Magenta : \t {}", terminal.paint(" ").on(Color::Magenta));
println!("Grey : \t\t {}", paint(" ").on(Color::Grey)); println!("Dark Magenta : \t {}", terminal.paint(" ").on(Color::DarkMagenta));
println!("White : \t {}", paint(" ").on(Color::White)); 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)] #[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)] #[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.. /// 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)] #[cfg(unix)]
pub fn print_font_with_attributes() pub fn print_font_with_attributes()
{ {
println!("{}", paint("Normal text")); let context = Context::new();
println!("{}", paint("Bold text").bold()); let terminal = terminal::terminal(&context);
println!("{}", paint("Italic text").italic());
println!("{}", paint("Slow blinking text").slow_blink()); println!("{}", terminal.paint("Normal text"));
println!("{}", paint("Rapid blinking text").rapid_blink()); println!("{}", terminal.paint("Bold text").bold());
println!("{}", paint("Hidden text").hidden()); println!("{}", terminal.paint("Italic text").italic());
println!("{}", paint("Underlined text").underlined()); println!("{}", terminal.paint("Slow blinking text").slow_blink());
println!("{}", paint("Reversed color").reverse()); println!("{}", terminal.paint("Rapid blinking text").rapid_blink());
println!("{}", paint("Dim text color").dim()); println!("{}", terminal.paint("Hidden text").hidden());
println!("{}", paint("Crossed out font").crossed_out()); 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. /// Print all supported rgb colors | demonstration.
#[cfg(unix)] #[cfg(unix)]
pub fn print_supported_colors() 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 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; extern crate crossterm;
use self::crossterm::cursor::{cursor, TerminalCursor}; use self::crossterm::cursor::{cursor, TerminalCursor};
use self::crossterm::Context;
/// Set the cursor to position X: 10, Y: 5 in the terminal. /// Set the cursor to position X: 10, Y: 5 in the terminal.
pub fn goto() pub fn goto()
{ {
let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(); let mut cursor = cursor(&context);
// Set the cursor to position X: 10, Y: 5 in the terminal // Set the cursor to position X: 10, Y: 5 in the terminal
cursor.goto(10,5); 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. /// Move the cursor 3 up | demonstration.
pub fn move_up() pub fn move_up()
{ {
let context = Context::new();
// Get the cursor // 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 // Move the cursor to position 3 times to the up in the terminal
cursor.move_up(3); cursor.move_up(3);
} }
@ -27,8 +42,10 @@ pub fn move_up()
/// Move the cursor 3 to the right | demonstration. /// Move the cursor 3 to the right | demonstration.
pub fn move_right() pub fn move_right()
{ {
let context = Context::new();
// Get the cursor // 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 // Move the cursor to position 3 times to the right in the terminal
cursor.move_right(3); cursor.move_right(3);
} }
@ -36,8 +53,10 @@ pub fn move_right()
/// Move the cursor 3 down | demonstration. /// Move the cursor 3 down | demonstration.
pub fn move_down() pub fn move_down()
{ {
let context = Context::new();
// Get the cursor // 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 // Move the cursor to position 3 times to the down in the terminal
cursor.move_down(3); cursor.move_down(3);
} }
@ -45,8 +64,10 @@ pub fn move_down()
/// Move the cursor 3 to the left | demonstration. /// Move the cursor 3 to the left | demonstration.
pub fn move_left() pub fn move_left()
{ {
let context = Context::new();
// Get the cursor // 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 // Move the cursor to position 3 times to the left in the terminal
cursor.move_left(3); cursor.move_left(3);
} }
@ -54,10 +75,12 @@ pub fn move_left()
/// Print character at X: 10 Y: 5 | demonstration. /// Print character at X: 10 Y: 5 | demonstration.
pub fn print() pub fn print()
{ {
let context = Context::new();
// To print an some displayable content on an certain position. // To print an some displayable content on an certain position.
// Get the cursor // Get the cursor
let mut cursor = cursor(); let mut cursor = cursor(&context);
// Set the cursor to position X: 10, Y: 5 in the terminal // Set the cursor to position X: 10, Y: 5 in the terminal
cursor.goto(10,5); cursor.goto(10,5);
// Print the @ symbol at position X: 10, Y: 5 in the terminal // 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.. /// Save and reset cursor position | demonstration..
pub fn safe_and_reset_position() pub fn safe_and_reset_position()
{ {
let mut cursor = cursor(); let context = Context::new();
let mut cursor = cursor(&context);
// Goto X: 5 Y: 5 // Goto X: 5 Y: 5
cursor.goto(5,5); cursor.goto(5,5);

View File

@ -1,6 +1,6 @@
extern crate crossterm; extern crate crossterm;
use crossterm::Terminal; use crossterm::Context;
use crossterm::screen::AlternateScreen; use crossterm::screen::AlternateScreen;
use crossterm::cursor::cursor; use crossterm::cursor::cursor;
use crossterm::terminal::{self, ClearType}; use crossterm::terminal::{self, ClearType};
@ -8,7 +8,7 @@ use crossterm::terminal::{self, ClearType};
use std::io::{Write, stdout}; use std::io::{Write, stdout};
use std::{time, thread}; use std::{time, thread};
fn print_wait_screen(terminal: &Terminal) fn print_wait_screen(terminal: &Context)
{ {
terminal::terminal(&terminal).clear(ClearType::All); terminal::terminal(&terminal).clear(ClearType::All);
@ -39,16 +39,16 @@ fn print_wait_screen(terminal: &Terminal)
pub fn print_wait_screen_on_alternate_window() 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. // 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 switching back.
{ {
// create new alternate screen instance and switch to the alternate screen. // 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 the wait screen.
print_wait_screen(&terminal); print_wait_screen(&context);
} }
println!("Whe are back at the main screen"); 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() pub fn switch_between_main_and_alternate_screen()
{ {
let terminal = Terminal::new(); let context = Context::new();
let mut cursor = cursor(&terminal); let mut cursor = cursor(&context);
{ {
// create new alternate screen instance and switch to the alternate screen. // 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); cursor.goto(0,0);
write!(screen, "we are at the alternate screen!"); write!(screen, "we are at the alternate screen!");
screen.flush(); screen.flush();

View File

@ -1,6 +1,6 @@
extern crate crossterm; extern crate crossterm;
use crossterm::Terminal; use crossterm::Context;
use crossterm::screen::AlternateScreen; use crossterm::screen::AlternateScreen;
use crossterm::cursor::cursor; use crossterm::cursor::cursor;
use crossterm::terminal::{self, ClearType}; use crossterm::terminal::{self, ClearType};
@ -11,23 +11,14 @@ use std::{time, thread};
use crossterm::raw::IntoRawMode; use crossterm::raw::IntoRawMode;
// raw screen is not working correctly currently // 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); let mut cursor = cursor(&context);
cursor.goto(0,0); 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: ");
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: "
);
}
}
// print some progress example. // print some progress example.
for i in 1..5 for i in 1..5
@ -42,18 +33,21 @@ fn print_wait_screen(terminal: &Terminal)
pub fn print_wait_screen_on_alternate_window() 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. // 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);
screen.flush();
// // Print the wait screen.
// print_wait_screen(&terminal);
} }
println!("Whe are back at the main screen"); println!("Whe are back at the main screen");

View File

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

View File

@ -1,75 +1,73 @@
//! This is an ANSI specific implementation for cursor related action. //! This is an ANSI specific implementation for cursor related action.
//! This module is used for windows 10 terminals and unix terminals by default. //! 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 shared::functions;
use super::ITerminalCursor; use super::ITerminalCursor;
/// This struct is an ansi implementation for cursor related actions. /// 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> { pub fn new() -> Box<AnsiCursor> {
Box::from(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 = context.screen_manager.lock().unwrap();
let mut screen = terminal.screen_manager.lock().unwrap();
{ {
screen.write_ansi(format!(csi!("{};{}H"), y + 1, x +1)); screen.write_ansi(format!(csi!("{};{}H"), y + 1, x +1));
} }
} }
fn pos(&self, terminal: &Terminal) -> (u16, u16) { fn pos(&self, context: &Context) -> (u16, u16) {
functions::get_cursor_position(&terminal) functions::get_cursor_position(&context)
} }
fn move_up(&self, count: u16, terminal: &Terminal) { fn move_up(&self, count: u16, context: &Context) {
let mut screen = terminal.screen_manager.lock().unwrap(); let mut screen = context.screen_manager.lock().unwrap();
{ {
screen.write_ansi(format!(csi!("{}A"), count)); screen.write_ansi(format!(csi!("{}A"), count));
} }
} }
fn move_right(&self, count: u16, terminal: &Terminal) { fn move_right(&self, count: u16, context: &Context) {
let mut screen = terminal.screen_manager.lock().unwrap(); let mut screen = context.screen_manager.lock().unwrap();
{ {
screen.write_ansi(format!(csi!("{}C"), count)); screen.write_ansi(format!(csi!("{}C"), count));
} }
} }
fn move_down(&self, count: u16, terminal: &Terminal) { fn move_down(&self, count: u16, context: &Context) {
let mut screen = terminal.screen_manager.lock().unwrap(); let mut screen = context.screen_manager.lock().unwrap();
{ {
screen.write_ansi(format!(csi!("{}B"), count)); screen.write_ansi(format!(csi!("{}B"), count));
} }
} }
fn move_left(&self, count: u16, terminal: &Terminal) { fn move_left(&self, count: u16, context: &Context) {
let mut screen = terminal.screen_manager.lock().unwrap(); let mut screen = context.screen_manager.lock().unwrap();
{ {
screen.write_ansi(format!(csi!("{}D"), count)); 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")); 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")); screen.write_ansi_str(csi!("u"));
} }

View File

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

View File

@ -9,6 +9,7 @@
//! //!
pub mod cursor; pub mod cursor;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
mod winapi_cursor; mod winapi_cursor;
mod ansi_cursor; mod ansi_cursor;
@ -17,7 +18,7 @@ mod ansi_cursor;
use self::winapi_cursor::WinApiCursor; use self::winapi_cursor::WinApiCursor;
use self::ansi_cursor::AnsiCursor; use self::ansi_cursor::AnsiCursor;
use Terminal; use Context;
pub use self::cursor::{ cursor, TerminalCursor }; pub use self::cursor::{ cursor, TerminalCursor };
///! This trait defines the actions that can be preformed with the terminal cursor. ///! 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), ///! 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. ///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminalCursor { pub trait ITerminalCursor {
/// Goto some location (x,y) in the terminal. /// Goto some location (x,y) in the context.
fn goto(&self, x: u16, y: u16, terminal: &Terminal); fn goto(&self, x: u16, y: u16, context: &Context);
/// Get the location (x,y) of the current cusror in the terminal /// Get the location (x,y) of the current cusror in the context
fn pos(&self, terminal: &Terminal) -> (u16, u16); fn pos(&self, context: &Context) -> (u16, u16);
/// Move cursor n times up /// 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. /// 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. /// 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. /// Move the cursor `n` times left.
fn move_left(&self, count: u16, terminal: &Terminal); fn move_left(&self, count: u16, context: &Context);
/// Save cursor position for recall later. Note that this position is stored program based not per instance of the cursor struct. /// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct.
fn save_position(&mut self, terminal: &Terminal); fn save_position(&mut self, context: &Context);
/// Return to saved cursor position /// 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 is an WINAPI specific implementation for cursor related action.
//! This module is used for windows terminals that do not support ANSI escape codes. //! 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 super::ITerminalCursor;
use kernel::windows_kernel::{kernel, cursor}; use kernel::windows_kernel::{kernel, cursor};
/// This struct is an windows implementation for cursor related actions. /// This struct is an windows implementation for cursor related actions.
pub struct WinApiCursor; pub struct WinApiCursor;
impl Construct for WinApiCursor { impl WinApiCursor {
fn new() -> Box<WinApiCursor> { pub fn new() -> Box<WinApiCursor> {
Box::from(WinApiCursor { }) Box::from(WinApiCursor { })
} }
} }
impl ITerminalCursor for 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); 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() cursor::pos()
} }
fn move_up(&self, count: u16, terminal: &Terminal) { fn move_up(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos(); let (xpos,ypos) = self.pos();
self.goto(xpos, ypos - count); self.goto(xpos, ypos - count);
} }
fn move_right(&self, count: u16, terminal: &Terminal) { fn move_right(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos(); let (xpos,ypos) = self.pos();
self.goto(xpos + count, ypos); self.goto(xpos + count, ypos);
} }
fn move_down(&self, count: u16, terminal: &Terminal) { fn move_down(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos(); let (xpos,ypos) = self.pos();
self.goto(xpos, ypos + count); self.goto(xpos, ypos + count);
} }
fn move_left(&self, count: u16, terminal: &Terminal) { fn move_left(&self, count: u16, context: &Context) {
let (xpos,ypos) = self.pos(); let (xpos,ypos) = self.pos();
self.goto(xpos - count, ypos); self.goto(xpos - count, ypos);
} }
fn save_position(&mut self, terminal: &Terminal) fn save_position(&mut self, context: &Context)
{ {
cursor::save_cursor_pos(); cursor::save_cursor_pos();
} }
fn reset_position(&self, terminal: &Terminal) fn reset_position(&self, context: &Context)
{ {
cursor::reset_to_saved_position(); cursor::reset_to_saved_position();
} }

View File

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

View File

@ -1,6 +1,6 @@
//! This module handles the enabling `ANSI escape codes` for windows terminals. //! This module handles the enabling `ANSI escape codes` for windows terminals.
use Context; use StateManager;
use state::commands::ICommand; use state::commands::ICommand;
static mut HAS_BEEN_TRYED_TO_ENABLE: bool = false; 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) pub fn pos() -> (u16,u16)
{ {
let csbi = kernel::get_console_screen_buffer_info(); 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. /// 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 { if *handle == INVALID_HANDLE_VALUE {
false false
} else { } 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 kernel;
pub mod cursor; pub mod cursor;

View File

@ -14,12 +14,11 @@ pub mod terminal;
pub mod manager; pub mod manager;
pub use shared::{screen, raw}; pub use shared::{screen, raw};
pub use state::context::Context;
use shared::traits::{Construct}; use state::command_manager::CommandManager;
pub use state::{ Context }; use state::state_manager::StateManager;
pub use manager::manager::{ ScreenManager }; use manager::ScreenManager;
pub use shared::terminal::Terminal;
#[cfg(windows)] #[cfg(windows)]
extern crate winapi; extern crate winapi;
@ -27,5 +26,3 @@ extern crate winapi;
extern crate libc; extern crate libc;
#[cfg(unix)] #[cfg(unix)]
extern crate termios; 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 std::io::{self, Write};
use super::IScreenManager; use super::IScreenManager;
@ -24,24 +28,12 @@ impl<Output :Write> IScreenManager<Output> for AnsiScreenManager<Output>
{ {
write!(self.output, "{}", string); write!(self.output, "{}", string);
self.flush(); self.flush();
// println!("test");
// match self.is_alternate_screen
// {
// true => ,
// false => write!(io::stdout(), "{}", string),
// };
} }
fn write_ansi_str(&mut self, string: &str) fn write_ansi_str(&mut self, string: &str)
{ {
write!(self.output, "{}", string); write!(self.output, "{}", string);
self.flush(); 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::IScreenManager;
use super::ansi_manager::AnsiScreenManager; use super::ansi_manager::AnsiScreenManager;
use std::io::Write;
/// Struct that stores an specific platform implementation for screen related actions.
pub struct ScreenManager pub struct ScreenManager
{ {
screen_manager: Box<IScreenManager<Box<Write>>> screen_manager: Box<IScreenManager<Box<Write>>>
@ -10,6 +14,7 @@ pub struct ScreenManager
impl ScreenManager impl ScreenManager
{ {
/// Create new screen manager instance whereon screen related actions can be performed.
pub fn new() -> ScreenManager { pub fn new() -> ScreenManager {
// #[cfg(target_os = "windows")] // #[cfg(target_os = "windows")]
// let cursor = functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new()); // 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> pub fn stdout(&mut self) -> &mut Box<Write>
{ {
self.screen_manager.stdout() self.screen_manager.stdout()
@ -32,11 +38,13 @@ impl ScreenManager
self.screen_manager.toggle_is_alternate_screen(is_alternate_screen); self.screen_manager.toggle_is_alternate_screen(is_alternate_screen);
} }
/// Write an ANSI code as String.
pub fn write_ansi(&mut self, string: String) pub fn write_ansi(&mut self, string: String)
{ {
self.screen_manager.write_ansi(string); self.screen_manager.write_ansi(string);
} }
/// Write an ANSI code as &str
pub fn write_ansi_str(&mut self, string: &str) pub fn write_ansi_str(&mut self, string: &str)
{ {
self.screen_manager.write_ansi_str(string); 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; pub mod manager;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -12,8 +15,11 @@ pub use self::manager::{ ScreenManager };
pub trait IScreenManager<Output> 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 stdout(&mut self) -> &mut Output;
fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool); 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); fn write_ansi(&mut self, string: String);
/// Write a &str to the current stdout.
fn write_ansi_str(&mut self, string: &str); 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`. //! Some actions need to preformed platform independently since they can not be solved `ANSI escape codes`.
use Terminal; use Context;
#[cfg(windows)] #[cfg(windows)]
use kernel::windows_kernel::terminal::terminal_size; 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. /// 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)] #[cfg(unix)]
return pos(&screen); return pos(&screen);

View File

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

View File

@ -24,49 +24,34 @@ use super::super::state::commands::unix_command::EnableRawModeCommand;
#[cfg(windows)] #[cfg(windows)]
use state::commands::win_commands::EnableRawModeCommand; use state::commands::win_commands::EnableRawModeCommand;
use { Terminal }; use {Context, CommandManager };
use state::commands::IContextCommand; use state::commands::IStateCommand;
use std::io::{ self, Write}; use std::io::{ self, Write};
use std::rc::Rc;
/// A wrapper for the raw terminal state. Which can be used to write to. /// A wrapper for the raw terminal state. Which can be used to write to.
pub struct RawTerminal<'a> pub struct RawTerminal<'a>
{ {
terminal : &'a Terminal, terminal : &'a Context,
command_id: u16, command_id: u16,
} }
/// Trait withs contains a method for switching into raw mode. /// Trait withs contains a method for switching into raw mode.
pub trait IntoRawMode<'a>: Write + Sized 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 impl <'a, W: Write> IntoRawMode<'a> for W
{ {
fn into_raw_mode(&self, terminal: &'a Terminal) -> io::Result<RawTerminal<'a>> { /// Raw mode means that input (stdin) won't be printed it will instead have to be written manually by
let (mut command, command_id) = EnableRawModeCommand::new(&terminal.context); /// the program. The input isn't canonicalised or line buffered (that is, you can
let success = command.execute(&terminal); /// 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 if success
{ {
@ -96,9 +81,6 @@ impl <'a> Drop for RawTerminal<'a>
{ {
fn drop(&mut self) fn drop(&mut self)
{ {
let mut context = self.terminal.context.lock().unwrap(); let success = CommandManager::undo(&self.terminal, self.command_id);
{
context.undo_state(self.command_id, &self.terminal);
}
} }
} }

View File

@ -1,96 +1,57 @@
//! This module contains all the logic for switching between alternate screen and main screen. //! This module contains all the logic for switching between alternate screen and main screen.
use Terminal; use Context;
use state::commands::*; use state::commands::*;
use std::io::{self, Write}; use std::io::{self, Write};
//pub struct ToMainScreen; pub struct AlternateScreen<'context> {
// context: &'context Context
//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
} }
impl<'term> AlternateScreen<'term> { impl<'context> AlternateScreen<'context> {
pub fn from(output: &'term Terminal) -> Self { /// Get the alternate screen from the context.
get_to_alternate_screen_command().execute(&output); /// By calling this method the current screen will be changed to the alternate screen.
AlternateScreen { term: output } /// 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) 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) 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> { 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) screen.stdout().write(buf)
} }
} }
fn flush(&mut self) -> io::Result<()> { 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() screen.stdout().flush()
} }
} }
} }
impl<'term> Drop for AlternateScreen<'term> impl<'context> Drop for AlternateScreen<'context>
{ {
fn drop(&mut self) 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. /// This trait can be used to create an empty instance of an struct.
pub trait Empty { pub trait Empty {
fn empty() -> Self; 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. //! 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. //! 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::sync::Mutex;
use std::rc::Rc;
#[cfg(unix)] #[cfg(unix)]
pub mod unix_command; pub mod unix_command;
@ -24,22 +25,21 @@ pub use self::unix_command::*;
#[cfg(windows)] #[cfg(windows)]
pub use self::win_commands::*; 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()` /// This command can be used for simple commands witch just have an `undo()` and an `execute()`
pub trait ICommand pub trait ICommand
{ {
fn new() -> Box<Self> where Self: Sized; fn new() -> Box<Self> where Self: Sized;
fn execute(&mut self, terminal: &Terminal) -> bool; fn execute(&mut self, terminal: &Context) -> bool;
fn undo(&mut self, terminal: &Terminal) -> bool; fn undo(&mut self, terminal: &Context) -> bool;
} }
/// This command is used for complex commands whits change the terminal state. /// 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. /// 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: &Context) -> bool;
fn execute(&mut self, terminal: &Terminal) -> bool; fn undo(&mut self, terminal: &Context) -> bool;
fn undo(&mut self, terminal: &Terminal) -> bool;
} }

View File

@ -1,6 +1,21 @@
//! This module contains the commands that can be used for both unix and windows systems. //! This module contains the commands that can be used for both unix and windows systems. Or else said terminals that support ansi codes.
use Terminal ; use Context;
use super::ICommand; 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. /// This command is used for switching to alternate screen and back to main screen.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -12,7 +27,7 @@ impl ICommand for ToAlternateScreenBufferCommand
Box::from(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(); 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(); 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. //! This module contains the commands that can be used for unix systems.
use {Terminal, Context}; use {Context, StateManager, CommandManager};
use super::IContextCommand; use super::IStateCommand;
use kernel::unix_kernel::terminal; use kernel::unix_kernel::terminal;
use termios::{Termios, tcsetattr, TCSAFLUSH, ICANON, ECHO, CREAD}; use termios::{Termios, tcsetattr, TCSAFLUSH, ICANON, ECHO, CREAD};
const FD_STDIN: ::std::os::unix::io::RawFd = 1; const FD_STDIN: ::std::os::unix::io::RawFd = 1;
use std::sync::Mutex; use std::sync::Mutex;
use std::rc::Rc;
/// This command is used for switching to NoncanonicalMode. /// This command is used for switching to NoncanonicalMode.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -16,20 +17,24 @@ pub struct NoncanonicalModeCommand
key: u16 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 key = 1;
let mut context = context.lock().unwrap(); let mut state_manager = state.lock().unwrap();
{ {
let command = NoncanonicalModeCommand { key: key }; let command = Box::from(NoncanonicalModeCommand { key: key });
context.register_change(Box::from(command), key); state_manager.register_change(command, key);
(Box::from(command),key) key
}
} }
} }
fn execute(&mut self, terminal: &Terminal) -> bool impl IStateCommand for NoncanonicalModeCommand
{
fn execute(&mut self, terminal: &Context) -> bool
{ {
// Set noncanonical mode // Set noncanonical mode
if let Ok(orig) = Termios::from_fd(FD_STDIN) 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 // Disable noncanonical mode
if let Ok(orig) = Termios::from_fd(FD_STDIN) 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. /// This command is used for enabling and disabling raw mode for the terminal.
#[derive(Copy, Clone)]
pub struct EnableRawModeCommand pub struct EnableRawModeCommand
{ {
original_mode: Option<Termios>, original_mode: Option<Box<Termios>>,
command_id: u16 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 key = 2;
let mut context = context.lock().unwrap(); let mut state = state_manager.lock().unwrap();
{ {
let command = EnableRawModeCommand { original_mode: None, command_id: key }; let command = EnableRawModeCommand { original_mode: None, command_id: key };
context.register_change(Box::from(command), key); state.register_change(Box::from(command), key);
(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(); let original_mode = terminal::get_terminal_mode();
if let Ok(original_mode) = original_mode if let Ok(original_mode) = original_mode
{ {
panic!("setting {:?}", original_mode); self.original_mode = Some(Box::from(original_mode));
self.original_mode = Some(original_mode);
let mut new_mode = original_mode; let mut new_mode = original_mode;
terminal::make_raw(&mut new_mode); terminal::make_raw(&mut new_mode);
terminal::set_terminal_mode(&new_mode); terminal::set_terminal_mode(&new_mode);
@ -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(ref original_mode) = self.original_mode
if let Some(original_mode) = self.original_mode
{ {
let result = terminal::set_terminal_mode(&original_mode); let result = terminal::set_terminal_mode(&original_mode);
match result match result

View File

@ -1,7 +1,7 @@
//! This module contains the commands that can be used for windows systems. //! This module contains the commands that can be used for windows systems.
use super::{ICommand, IContextCommand}; use super::{ICommand, IStateCommand};
use super::super::Context; use super::super::StateManager;
use kernel::windows_kernel::{kernel, ansi_support}; use kernel::windows_kernel::{kernel, ansi_support};
use winapi::shared::minwindef::DWORD; 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 winapi::um::wincon::{ENABLE_VIRTUAL_TERMINAL_PROCESSING ,SMALL_RECT, COORD, CHAR_INFO};
use std::mem; use std::mem;
use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
/// This command is used for enabling and disabling ANSI code support for windows systems, /// This command is used for enabling and disabling ANSI code support for windows systems,
@ -88,15 +89,17 @@ pub struct EnableRawModeCommand
key: i16 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}; 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 key = super::generate_key();
let command = EnableRawModeCommand { mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT, key: key }; let command = EnableRawModeCommand { mask: ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT, key: key };
context.register_change(Box::from(command), key); let rc = Rc::new(command);
(Box::from(command),key)
state.register_change(rc.clone(), key);
(rc.clone(),key)
} }
fn execute(&mut self, terminal: &Terminal) -> bool fn execute(&mut self, terminal: &Terminal) -> bool
@ -154,7 +157,7 @@ impl ICommand for ToAlternateScreenBufferCommand
Box::from(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() }; let mut chi_buffer: [CHAR_INFO;160] = unsafe {mem::zeroed() };
@ -208,7 +211,7 @@ impl ICommand for ToAlternateScreenBufferCommand
true true
} }
fn undo(&mut self, context: &Context) -> bool fn undo(&mut self, state: &StateManager) -> bool
{ {
let handle = kernel::get_output_handle(); let handle = kernel::get_output_handle();
kernel::set_active_screen_buffer(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 std::sync::Mutex;
use super::commands::IContextCommand; use std::rc::Rc;
use Terminal;
/// Struct that stores the changed states of the terminal. 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 pub struct Context
{ {
changed_states: HashMap<u16, Box<IContextCommand>>, pub screen_manager: Rc<Mutex<ScreenManager>>,
pub state_manager: Mutex<StateManager>
} }
impl Context 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 pub fn new() -> Context
{ {
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. /// Wraps an displayable object so it can be formatted with colors and attributes.
// pub fn restore_changes(&mut self) ///
// { /// Check `/examples/color` in the libary for more spesific examples.
// use std::iter::FromIterator; ///
// /// #Example
// let mut buffer = Vec::new(); ///
// /// ```rust
// for i in 0..self.changed_states.len() /// extern crate crossterm;
// { ///
// buffer[i] = self.changed_states.iter().nth(i).unwrap(); /// use self::crossterm::style::{paint,Color};
// } ///
// /// fn main()
// for i in 0..buffer.len() /// {
// { /// // Create an styledobject object from the text 'Unstyled font'
// buffer[i].1.undo(self); /// // Currently it has the default foregroundcolor and backgroundcolor.
// } /// println!("{}",paint("Unstyled font"));
// } ///
/// // Create an displayable object from the text 'Colored font',
/// Register new changed state with the given key. /// // Paint this with the `Red` foreground color and `Blue` backgroundcolor.
pub fn register_change(&mut self, change: Box<IContextCommand>, key: u16) /// // 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); fn drop(&mut self)
}
}
/// Undo an specific state by the given state key.
pub fn undo_state(&mut self, state_key: u16, terminal: &Terminal)
{ {
if self.changed_states.contains_key(&state_key) let mut changes = self.state_manager.lock().unwrap();
{ changes.restore_changes(&self);
{
let mut command = self.changed_states.get_mut(&state_key).unwrap();
command.undo(&terminal);
}
&self.changed_states.remove(&state_key);
} }
} }
}

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

View File

@ -2,10 +2,9 @@
//! Like styling the font, foreground color and background. //! Like styling the font, foreground color and background.
use super::*; use super::*;
use Construct;
use style::Color; use style::Color;
use std::{ io }; use std::io;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
@ -35,9 +34,12 @@ impl TerminalColor {
/// extern crate crossterm; /// extern crate crossterm;
/// ///
/// use self::crossterm::style::{ color, Color}; /// use self::crossterm::style::{ color, Color};
/// use crossterm::Context;
///
/// let context = Context::new();
/// ///
/// // Get colored terminal instance /// // Get colored terminal instance
/// let mut colored_terminal = color(); /// let mut colored_terminal = color(&context);
/// ///
/// // Set foreground color of the font /// // Set foreground color of the font
/// colored_terminal.set_fg(Color::Red); /// colored_terminal.set_fg(Color::Red);
@ -60,9 +62,12 @@ impl TerminalColor {
/// extern crate crossterm; /// extern crate crossterm;
/// ///
/// use self::crossterm::style::{ color, Color}; /// use self::crossterm::style::{ color, Color};
/// use crossterm::Context;
///
/// let context = Context::new();
/// ///
/// // Get colored terminal instance /// // Get colored terminal instance
/// let mut colored_terminal = color(); /// let mut colored_terminal = color(&context);
/// ///
/// // Set background color of the font /// // Set background color of the font
/// colored_terminal.set_bg(Color::Red); /// colored_terminal.set_bg(Color::Red);
@ -83,9 +88,12 @@ impl TerminalColor {
/// extern crate crossterm; /// extern crate crossterm;
/// ///
/// use self::crossterm::style::color; /// use self::crossterm::style::color;
/// use crossterm::Context;
///
/// let context = Context::new();
/// ///
/// // Get colored terminal instance /// // Get colored terminal instance
/// let mut colored_terminal = color(); /// let mut colored_terminal = color(&context);
/// ///
/// colored_terminal.reset(); /// 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> { pub fn color(screen_manager: Rc<Mutex<ScreenManager>>) -> Box<TerminalColor> {
Box::from(TerminalColor::new(screen_manager.clone())) Box::from(TerminalColor::new(screen_manager.clone()))
} }

View File

@ -7,13 +7,13 @@ mod ansi_color;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::winapi_color::WinApiColor; use self::winapi_color::WinApiColor;
use self::ansi_color::AnsiColor; use self::ansi_color::AnsiColor;
use { ScreenManager };
use super::{Color, ColorType}; use super::{Color, ColorType};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Mutex; use std::sync::Mutex;
use { ScreenManager };
///! This trait defines the actions that can be preformed with the terminal color. ///! 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 ///! This trait can be implemented so that an concrete implementation of the ITerminalColor can forfill
///! the wishes to work on an specific platform. ///! the wishes to work on an specific platform.

View File

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

View File

@ -5,6 +5,7 @@ use style::{Color, StyledObject};
use ScreenManager; use ScreenManager;
use std::sync::Mutex; use std::sync::Mutex;
use std::rc::Rc; use std::rc::Rc;
#[cfg(unix)] #[cfg(unix)]
use super::super::Attribute; 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::fmt;
use std::io::Write; use std::io::Write;

View File

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

View File

@ -4,14 +4,7 @@
//! - alternate screen //! - alternate screen
//! - raw mode //! - raw mode
//! - clearing resizing scrolling the terminal. //! - 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; pub mod terminal;
@ -19,6 +12,13 @@ pub mod terminal;
mod winapi_terminal; mod winapi_terminal;
mod ansi_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. /// Enum that can be used for the kind of clearing that can be done in the terminal.
pub enum ClearType { pub enum ClearType {
All, All,
@ -38,13 +38,13 @@ pub enum ClearType {
///! so that cursor related actions can be preformed on both unix and windows systems. ///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminal { pub trait ITerminal {
/// Clear the current cursor by specifying the clear type /// 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) /// 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. /// 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. /// 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. /// 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. //! Like clearing and scrolling in the terminal or getting the size of the terminal.
use super::*; use super::*;
use Construct; use Context;
use super::super::shared::terminal;
use super::super::style;
use std::fmt;
/// Struct that stores an specific platform implementation for terminal related actions. /// Struct that stores an specific platform implementation for terminal related actions.
pub struct Terminal<'terminal> { pub struct Terminal<'context> {
terminal: Option<Box<ITerminal>>, 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. /// 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")] #[cfg(target_os = "windows")]
let terminal = functions::get_module::<Box<ITerminal>>(WinApiTerminal::new(), AnsiTerminal::new()); let terminal = functions::get_module::<Box<ITerminal>>(WinApiTerminal::new(), AnsiTerminal::new());
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let terminal = Some(AnsiTerminal::new() as Box<ITerminal>); 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; /// extern crate crossterm;
/// use crossterm::terminal; /// 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. /// // clear all cells in terminal.
/// term.clear(terminal::ClearType::All); /// term.clear(terminal::ClearType::All);
@ -49,7 +53,7 @@ impl<'terminal> Terminal<'terminal> {
/// ``` /// ```
pub fn clear(&mut self, clear_type: ClearType) { pub fn clear(&mut self, clear_type: ClearType) {
if let Some(ref terminal) = self.terminal { 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; /// extern crate crossterm;
/// use crossterm::terminal; /// 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(); /// let size = term.terminal_size();
/// println!("{:?}", size); /// println!("{:?}", size);
@ -70,7 +76,7 @@ impl<'terminal> Terminal<'terminal> {
/// ``` /// ```
pub fn terminal_size(&mut self) -> (u16, u16) { pub fn terminal_size(&mut self) -> (u16, u16) {
if let Some(ref terminal) = self.terminal { if let Some(ref terminal) = self.terminal {
return terminal.terminal_size(&self.term) return terminal.terminal_size(&self.context)
} }
(0,0) (0,0)
} }
@ -83,8 +89,10 @@ impl<'terminal> Terminal<'terminal> {
/// ///
/// extern crate crossterm; /// extern crate crossterm;
/// use crossterm::terminal; /// 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 /// // scroll up by 5 lines
/// let size = term.scroll_up(5); /// let size = term.scroll_up(5);
@ -92,7 +100,7 @@ impl<'terminal> Terminal<'terminal> {
/// ``` /// ```
pub fn scroll_up(&mut self, count: i16) { pub fn scroll_up(&mut self, count: i16) {
if let Some(ref terminal) = self.terminal { 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; /// extern crate crossterm;
/// use crossterm::terminal; /// 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 /// // scroll down by 5 lines
/// let size = term.scroll_down(5); /// let size = term.scroll_down(5);
@ -113,7 +123,7 @@ impl<'terminal> Terminal<'terminal> {
/// ``` /// ```
pub fn scroll_down(&mut self, count: i16) { pub fn scroll_down(&mut self, count: i16) {
if let Some(ref terminal) = self.terminal { 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; /// extern crate crossterm;
/// use crossterm::terminal; /// 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 /// // Set of the size to X: 10 and Y: 10
/// let size = term.set_size(10,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) pub fn set_size(&mut self, width: i16, height: i16)
{ {
if let Some (ref terminal) = self.terminal { 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. /// 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 /// #Example
/// ///
@ -150,16 +196,17 @@ impl<'terminal> Terminal<'terminal> {
/// ///
/// extern crate crossterm; /// extern crate crossterm;
/// use crossterm::terminal; /// 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 /// // scroll down by 5 lines
/// let size = term.scroll_down(5); /// let size = term.scroll_down(5);
/// ///
/// ``` /// ```
/// ///
/// pub fn terminal<'context>(context: &'context Context) -> Box<Terminal<'context>> {
Box::from(Terminal::new(&context))
pub fn terminal<'terminal>(terminal: &'terminal terminal::Terminal) -> Box<Terminal<'terminal>> {
Box::from(Terminal::new(&terminal))
} }

View File

@ -1,5 +1,5 @@
//! This is an `WINAPI` specific implementation for terminal related action. //! 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 {Construct};
use cursor::cursor; use cursor::cursor;