added unix cursor hide show, fixed windows and added alternate screen

functionality. Also refactored and cleaned up code.:
This commit is contained in:
TimonPost 2018-06-22 21:04:30 +02:00
parent bb2067ed7b
commit 62fbb6b6a9
36 changed files with 1014 additions and 843 deletions

File diff suppressed because it is too large Load Diff

View File

@ -32,5 +32,8 @@ use std::{time, thread};
fn main() { fn main() {
// alternate_screen::switch_between_main_and_alternate_screen(); // alternate_screen::switch_between_main_and_alternate_screen();
let context = Context::new(); let context = Context::new();
raw_mode::print_wait_screen_on_alternate_window(); let mut scre = screen::AlternateScreen::from(context.clone());
write!(scre, "asdf");
scre.flush();
thread::sleep(time::Duration::from_secs(3));
} }

View File

@ -12,7 +12,7 @@ use self::crossterm::Context;
pub fn paint_foreground() pub fn paint_foreground()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
// 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.
@ -30,7 +30,7 @@ pub fn paint_foreground()
pub fn paint_background() pub fn paint_background()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
// 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.
@ -48,7 +48,7 @@ pub fn paint_background()
pub fn paint_foreground_and_background() pub fn paint_foreground_and_background()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
// 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.
@ -74,7 +74,7 @@ pub fn paint_foreground_and_background()
pub fn print_all_foreground_colors() pub fn print_all_foreground_colors()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
println!("Black : \t {}", terminal.paint("").with(Color::Black)); println!("Black : \t {}", terminal.paint("").with(Color::Black));
println!("Red : \t\t {}", terminal.paint("").with(Color::Red)); println!("Red : \t\t {}", terminal.paint("").with(Color::Red));
@ -97,7 +97,7 @@ pub fn print_all_foreground_colors()
pub fn print_all_background_colors() pub fn print_all_background_colors()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
println!("Black : \t {}", terminal.paint(" ").on(Color::Black)); println!("Black : \t {}", terminal.paint(" ").on(Color::Black));
println!("Red : \t\t {}", terminal.paint(" ").on(Color::Red)); println!("Red : \t\t {}", terminal.paint(" ").on(Color::Red));
@ -125,7 +125,7 @@ pub fn print_all_background_colors()
pub fn print_font_with_attributes() pub fn print_font_with_attributes()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
println!("{}", terminal.paint("Normal text")); println!("{}", terminal.paint("Normal text"));
println!("{}", terminal.paint("Bold text").bold()); println!("{}", terminal.paint("Bold text").bold());
@ -144,7 +144,7 @@ pub fn print_font_with_attributes()
pub fn print_supported_colors() pub fn print_supported_colors()
{ {
let context = Context::new(); let context = Context::new();
let terminal = terminal::terminal(&context); let terminal = terminal::terminal(context.clone());
let count = crossterm::style::color(context.screen_manager.clone()).get_available_color_count().unwrap(); let count = crossterm::style::color(context.screen_manager.clone()).get_available_color_count().unwrap();

View File

@ -12,7 +12,7 @@ pub fn goto()
let context = Context::new(); let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// 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);
} }
@ -23,7 +23,7 @@ pub fn pos()
let context = Context::new(); let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// get the cursor position. // get the cursor position.
let (x,y) = cursor.pos(); let (x,y) = cursor.pos();
} }
@ -34,7 +34,7 @@ pub fn move_up()
let context = Context::new(); let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// 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);
} }
@ -45,7 +45,7 @@ pub fn move_right()
let context = Context::new(); let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// 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);
} }
@ -56,7 +56,7 @@ pub fn move_down()
let context = Context::new(); let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// 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);
} }
@ -67,7 +67,7 @@ pub fn move_left()
let context = Context::new(); let context = Context::new();
// Get the cursor // Get the cursor
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// 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);
} }
@ -80,7 +80,7 @@ pub fn print()
// 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(&context); let mut cursor = cursor(context.clone());
// 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
@ -104,7 +104,7 @@ pub fn safe_and_reset_position()
{ {
let context = Context::new(); let context = Context::new();
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
// Goto X: 5 Y: 5 // Goto X: 5 Y: 5
cursor.goto(5,5); cursor.goto(5,5);

View File

@ -7,18 +7,18 @@ use crossterm::terminal::{self, ClearType};
use std::io::{Write, stdout}; use std::io::{Write, stdout};
use std::{time, thread}; use std::{time, thread};
use std::rc::Rc;
fn print_wait_screen(terminal: &Context) fn print_wait_screen(context: Rc<Context>)
{ {
terminal::terminal(&terminal).clear(ClearType::All); terminal::terminal(context.clone()).clear(ClearType::All);
let mut cursor = cursor(&terminal); let mut cursor = cursor(context.clone());
cursor.goto(0,0); cursor.goto(0,0);
{ {
let mut screen_manager = terminal.screen_manager.lock().unwrap(); let mut screen_manager = context.screen_manager.lock().unwrap();
{ {
write!(screen_manager.stdout(), write!(screen_manager,
"Welcome to the wait screen.\n\ "Welcome to the wait screen.\n\
Please wait a few seconds until we arrive back at the main screen.\n\ Please wait a few seconds until we arrive back at the main screen.\n\
Progress: " Progress: "
@ -45,10 +45,10 @@ pub fn print_wait_screen_on_alternate_window()
// 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(&context); let mut screen = AlternateScreen::from(context.clone());
// Print the wait screen. // Print the wait screen.
print_wait_screen(&context); print_wait_screen(context.clone());
} }
println!("Whe are back at the main screen"); println!("Whe are back at the main screen");
@ -57,11 +57,11 @@ 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 context = Context::new(); let context = Context::new();
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
{ {
// 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(&context); let mut screen = AlternateScreen::from(context.clone());
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

@ -7,15 +7,16 @@ use crossterm::terminal::{self, ClearType};
use std::io::{Write, stdout}; use std::io::{Write, stdout};
use std::{time, thread}; use std::{time, thread};
use std::rc::Rc;
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(context: &Context) fn print_wait_screen(context: Rc<Context>)
{ {
terminal::terminal(&context).clear(ClearType::All); terminal::terminal(context.clone()).clear(ClearType::All);
let mut cursor = cursor(&context); let mut cursor = cursor(context.clone());
cursor.goto(0,0).print("Welcome to the wait screen."); 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,1).print("Please wait a few seconds until we arrive back at the main screen.");
cursor.goto(0,2).print("Progress: "); cursor.goto(0,2).print("Progress: ");
@ -41,11 +42,11 @@ pub fn print_wait_screen_on_alternate_window()
// create new alternate screen instance this call is also switching the screen to alternate screen. // 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 convert the output of the program to raw mode.
// then print the wait screen on the alternate screen in raw mode. // then print the wait screen on the alternate screen in raw mode.
let mut screen = AlternateScreen::from(&context); let mut screen = AlternateScreen::from(context.clone());
let alternate_screen = screen.into_raw_mode(&context); let alternate_screen = screen.into_raw_mode(context.clone());
// Print the wait screen. // Print the wait screen.
print_wait_screen(&context); print_wait_screen(context.clone());
screen.flush(); screen.flush();
} }

View File

@ -21,7 +21,7 @@ pub fn clear_all_lines()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context);
print_test_data(); print_test_data();
@ -35,12 +35,12 @@ pub fn clear_from_cursor_down()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
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(&context).goto(4,8); cursor::cursor(context.clone()).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);
@ -52,12 +52,12 @@ pub fn clear_from_cursor_up()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
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(&context).goto(4,4); cursor::cursor(context.clone()).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);
@ -69,12 +69,12 @@ pub fn clear_current_line()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
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(&context).goto(4,4); cursor::cursor(context.clone()).goto(4,4);
// Clear current line cells. // Clear current line cells.
terminal.clear(ClearType::CurrentLine); terminal.clear(ClearType::CurrentLine);
@ -86,12 +86,12 @@ pub fn clear_until_new_line()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
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(&context).goto(4,20); cursor::cursor(context.clone()).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);
@ -103,7 +103,7 @@ pub fn print_terminal_size()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
// Get terminal size // Get terminal size
let terminal_size = terminal.terminal_size(); let terminal_size = terminal.terminal_size();
// Print results // Print results
@ -115,7 +115,7 @@ pub fn set_terminal_size()
{ {
let context = Context::new(); let context = Context::new();
let mut terminal = terminal(&context); let mut terminal = terminal(context);
terminal.set_size(10,10); terminal.set_size(10,10);
} }
@ -127,7 +127,7 @@ pub fn scroll_down()
print_test_data(); print_test_data();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
// Scroll down 10 lines. // Scroll down 10 lines.
terminal.scroll_down(10); terminal.scroll_down(10);
} }
@ -140,7 +140,7 @@ pub fn scroll_up()
print_test_data(); print_test_data();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
// Scroll up 10 lines. // Scroll up 10 lines.
terminal.scroll_up(10); terminal.scroll_up(10);
} }
@ -151,7 +151,7 @@ pub fn resize_terminal()
let context = Context::new(); let context = Context::new();
// Get terminal // Get terminal
let mut terminal = terminal(&context); let mut terminal = terminal(context.clone());
// Get terminal size // Get terminal size
terminal.set_size(10,10); terminal.set_size(10,10);
} }

View File

@ -4,72 +4,91 @@
use Context; use Context;
use shared::functions; use shared::functions;
use super::ITerminalCursor; use super::*;
/// 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
{
context: Rc<Context>
}
impl AnsiCursor { impl AnsiCursor {
pub fn new() -> Box<AnsiCursor> { pub fn new(context: Rc<Context>) -> Box<AnsiCursor> {
Box::from(AnsiCursor {}) Box::from(AnsiCursor { context })
} }
} }
impl ITerminalCursor for AnsiCursor { impl ITerminalCursor for AnsiCursor {
fn goto(&self, x: u16, y: u16, context: &Context) fn goto(&self, x: u16, y: u16)
{ {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.context.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, context: &Context) -> (u16, u16) { fn pos(&self) -> (u16, u16) {
functions::get_cursor_position(&context) functions::get_cursor_position(self.context.clone())
} }
fn move_up(&self, count: u16, context: &Context) { fn move_up(&self, count: u16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.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, context: &Context) { fn move_right(&self, count: u16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.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, context: &Context) { fn move_down(&self, count: u16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.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, context: &Context) { fn move_left(&self, count: u16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.write_ansi(format!(csi!("{}D"), count)); screen.write_ansi(format!(csi!("{}D"), count));
} }
} }
fn save_position(&mut self, context: &Context) fn save_position(&mut self)
{ {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.write_ansi_str(csi!("s")); screen.write_ansi_str(csi!("s"));
} }
} }
fn reset_position(&self, context: &Context) fn reset_position(&self)
{ {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.write_ansi_str(csi!("u")); screen.write_ansi_str(csi!("u"));
} }
} }
fn hide(&self)
{
let mut screen = self.context.screen_manager.lock().unwrap();
{
screen.write_ansi_str(csi!("?25l"));
}
}
fn show(&self)
{
let mut screen = self.context.screen_manager.lock().unwrap();
{
screen.write_ansi_str(csi!("?25h"));
}
}
} }

View File

@ -8,23 +8,23 @@ use Context;
use super::super::shared::functions; use super::super::shared::functions;
use std::fmt::Display; use std::fmt::Display;
use std::io::Write; use std::rc::Rc;
/// Struct that stores an specific platform implementation for cursor related actions. /// Struct that stores an specific platform implementation for cursor related actions.
pub struct TerminalCursor<'context> { pub struct TerminalCursor {
context: &'context Context, context: Rc<Context>,
terminal_cursor: Option<Box<ITerminalCursor>>, terminal_cursor: Option<Box<ITerminalCursor>>,
} }
impl <'context> TerminalCursor<'context> impl TerminalCursor
{ {
/// Create new cursor instance whereon cursor related actions can be performed. /// Create new cursor instance whereon cursor related actions can be performed.
pub fn new(context: &'context Context) -> TerminalCursor<'context> { pub fn new(context: Rc<Context>) -> TerminalCursor {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let cursor = functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new(), context); let cursor = functions::get_module::<Box<ITerminalCursor>>(WinApiCursor::new(), AnsiCursor::new(context.clone()));
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let cursor = Some(AnsiCursor::new() as Box<ITerminalCursor>); let cursor = Some(AnsiCursor::new(context.clone()) as Box<ITerminalCursor>);
TerminalCursor { terminal_cursor: cursor , context} TerminalCursor { terminal_cursor: cursor , context}
} }
@ -39,20 +39,20 @@ impl <'context> TerminalCursor<'context>
/// use self::crossterm::Context; /// use self::crossterm::Context;
/// use self::crossterm::cursor; /// use self::crossterm::cursor;
/// ///
// pub fn goto() /// pub fn goto()
// { /// {
// let context = Context::new(); /// let context = Context::new();
// ///
// // Get the cursor /// // Get the cursor
// let mut cursor = cursor(&context); /// 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);
// } /// }
/// ///
/// ``` /// ```
pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor<'context> { pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor {
if let Some(ref terminal_cursor) = self.terminal_cursor { if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.goto(x, y, &self.context); terminal_cursor.goto(x, y);
} }
self self
} }
@ -80,7 +80,7 @@ impl <'context> TerminalCursor<'context>
/// ``` /// ```
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.context) terminal_cursor.pos()
} else { } else {
(0, 0) (0, 0)
} }
@ -107,9 +107,9 @@ impl <'context> TerminalCursor<'context>
/// } /// }
/// ///
/// ``` /// ```
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'context> { pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor {
if let Some(ref terminal_cursor) = self.terminal_cursor { if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_up(count, &self.context); terminal_cursor.move_up(count);
} }
self self
} }
@ -123,19 +123,19 @@ impl <'context> TerminalCursor<'context>
/// use self::crossterm::Context; /// use self::crossterm::Context;
/// use self::crossterm::cursor; /// use self::crossterm::cursor;
/// ///
// pub fn move_right() /// pub fn move_right()
// { /// {
// let context = Context::new(); /// let context = Context::new();
// ///
// // Get the cursor /// // Get the cursor
// let mut cursor = cursor(&context); /// 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);
// } /// }
/// ``` /// ```
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'context> { pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor {
if let Some(ref terminal_cursor) = self.terminal_cursor { if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_right(count, &self.context); terminal_cursor.move_right(count);
} }
self self
} }
@ -161,9 +161,9 @@ impl <'context> TerminalCursor<'context>
/// } /// }
/// ///
/// ``` /// ```
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'context> { pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor {
if let Some(ref terminal_cursor) = self.terminal_cursor { if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_down(count, &self.context); terminal_cursor.move_down(count);
} }
self self
} }
@ -189,9 +189,9 @@ impl <'context> TerminalCursor<'context>
/// } /// }
/// ///
/// ``` /// ```
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'context> { pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor {
if let Some(ref terminal_cursor) = self.terminal_cursor { if let Some(ref terminal_cursor) = self.terminal_cursor {
terminal_cursor.move_left(count, &self.context); terminal_cursor.move_left(count);
} }
self self
} }
@ -232,12 +232,18 @@ impl <'context> TerminalCursor<'context>
/// .print("@"); /// .print("@");
/// ///
/// ``` /// ```
pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor<'context> { pub fn print<D: Display>(&mut self, value: D) -> &mut TerminalCursor {
let mut screen = self.context.screen_manager.lock().unwrap();
{ {
write!(screen.stdout(), "{}", value); let mut mutex = &self.context.screen_manager;
// rust is line buffered so we need to flush the buffer in order to print it at the current cursor position. {
screen.stdout().flush(); let mut screen_manager = mutex.lock().unwrap();
use std::fmt::Write;
let mut string = String::new();
write!(string, "{}", value).unwrap();
screen_manager.write_ansi(string);
}
} }
self self
} }
@ -261,7 +267,7 @@ impl <'context> TerminalCursor<'context>
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.context); terminal_cursor.save_position();
} }
} }
@ -284,7 +290,7 @@ impl <'context> TerminalCursor<'context>
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.context); terminal_cursor.reset_position();
} }
} }
} }
@ -311,6 +317,6 @@ impl <'context> TerminalCursor<'context>
/// cursor::cursor(&context).goto(5,10); /// cursor::cursor(&context).goto(5,10);
/// ///
/// ``` /// ```
pub fn cursor<'context>(context: &'context Context) -> Box<TerminalCursor<'context>> { pub fn cursor(context: Rc<Context>) -> Box<TerminalCursor> {
Box::from(TerminalCursor::new(&context)) Box::from(TerminalCursor::new(context.clone()))
} }

View File

@ -18,9 +18,10 @@ mod ansi_cursor;
use self::winapi_cursor::WinApiCursor; use self::winapi_cursor::WinApiCursor;
use self::ansi_cursor::AnsiCursor; use self::ansi_cursor::AnsiCursor;
use Context;
pub use self::cursor::{ cursor, TerminalCursor }; pub use self::cursor::{ cursor, TerminalCursor };
use std::rc::Rc;
///! 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.
///! This trait can be implemented so that an concrete implementation of the ITerminalCursor can forfill ///! This trait can be implemented so that an concrete implementation of the ITerminalCursor can forfill
///! the wishes to work on an specific platform. ///! the wishes to work on an specific platform.
@ -31,19 +32,23 @@ pub use self::cursor::{ cursor, TerminalCursor };
///! so that cursor related actions can be preformed on both unix and windows systems. ///! so that cursor related actions can be preformed on both unix and windows systems.
pub trait ITerminalCursor { pub trait ITerminalCursor {
/// Goto some location (x,y) in the context. /// Goto some location (x,y) in the context.
fn goto(&self, x: u16, y: u16, context: &Context); fn goto(&self, x: u16, y: u16);
/// Get the location (x,y) of the current cusror in the context /// Get the location (x,y) of the current cusror in the context
fn pos(&self, context: &Context) -> (u16, u16); fn pos(&self) -> (u16, u16);
/// Move cursor n times up /// Move cursor n times up
fn move_up(&self, count: u16, context: &Context); fn move_up(&self, count: u16);
/// Move the cursor `n` times to the right. /// Move the cursor `n` times to the right.
fn move_right(&self, count: u16, context: &Context); fn move_right(&self, count: u16);
/// Move the cursor `n` times down. /// Move the cursor `n` times down.
fn move_down(&self, count: u16, context: &Context); fn move_down(&self, count: u16);
/// Move the cursor `n` times left. /// Move the cursor `n` times left.
fn move_left(&self, count: u16, context: &Context); fn move_left(&self, count: u16);
/// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct. /// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct.
fn save_position(&mut self, context: &Context); fn save_position(&mut self);
/// Return to saved cursor position /// Return to saved cursor position
fn reset_position(&self, context: &Context); fn reset_position(&self);
/// Hide the terminal cursor.
fn hide(&self);
/// Show the terminal cursor
fn show(&self);
} }

View File

@ -1,8 +1,6 @@
//! 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. //! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
use Context;
use super::ITerminalCursor; use super::ITerminalCursor;
use kernel::windows_kernel::{kernel, cursor}; use kernel::windows_kernel::{kernel, cursor};
@ -17,41 +15,51 @@ impl WinApiCursor {
impl ITerminalCursor for WinApiCursor { impl ITerminalCursor for WinApiCursor {
fn goto(&self, x: u16, y: u16, context: &Context) { fn goto(&self, x: u16, y: u16) {
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, context: &Context) -> (u16, u16) { fn pos(&self) -> (u16, u16) {
cursor::pos() cursor::pos()
} }
fn move_up(&self, count: u16, context: &Context) { fn move_up(&self, count: u16) {
let (xpos,ypos) = self.pos(context); let (xpos,ypos) = self.pos();
self.goto(xpos, ypos - count, context); self.goto(xpos, ypos - count);
} }
fn move_right(&self, count: u16, context: &Context) { fn move_right(&self, count: u16) {
let (xpos,ypos) = self.pos(context); let (xpos,ypos) = self.pos();
self.goto(xpos + count, ypos, context); self.goto(xpos + count, ypos);
} }
fn move_down(&self, count: u16, context: &Context) { fn move_down(&self, count: u16) {
let (xpos,ypos) = self.pos(context); let (xpos,ypos) = self.pos();
self.goto(xpos, ypos + count,context); self.goto(xpos, ypos + count);
} }
fn move_left(&self, count: u16, context: &Context) { fn move_left(&self, count: u16) {
let (xpos,ypos) = self.pos(context); let (xpos,ypos) = self.pos();
self.goto(xpos - count, ypos,context); self.goto(xpos - count, ypos);
} }
fn save_position(&mut self, context: &Context) fn save_position(&mut self)
{ {
cursor::save_cursor_pos(); cursor::save_cursor_pos();
} }
fn reset_position(&self, context: &Context) fn reset_position(&self)
{ {
cursor::reset_to_saved_position(); cursor::reset_to_saved_position();
} }
fn hide(&self)
{
kernel::cursor_visibility(false);
}
fn show(&self)
{
kernel::cursor_visibility(true);
}
} }

View File

@ -1,24 +1,27 @@
//! This module handles the enabling `ANSI escape codes` for windows terminals. //! This module handles the enabling `ANSI escape codes` for windows terminals.
use {Context, StateManager}; use IStateCommand;
use state::commands::ICommand; use std::sync::{Once, ONCE_INIT};
static mut HAS_BEEN_TRYED_TO_ENABLE: bool = false; static mut HAS_BEEN_TRYED_TO_ENABLE: bool = false;
static mut IS_ANSI_ON_WINDOWS_ENABLED: Option<bool> = None; static mut IS_ANSI_ON_WINDOWS_ENABLED: Option<bool> = None;
static mut DOES_WINDOWS_SUPPORT_ANSI: Option<bool> = None; static mut DOES_WINDOWS_SUPPORT_ANSI: Option<bool> = None;
static START: Once = ONCE_INIT;
/// Try enable `ANSI escape codes` and return the result. /// Try enable `ANSI escape codes` and return the result.
pub fn try_enable_ansi_support(context: &Context) -> bool pub fn try_enable_ansi_support() -> bool
{ {
START.call_once(|| {
use state::commands::win_commands::EnableAnsiCommand; use state::commands::win_commands::EnableAnsiCommand;
let mut command = EnableAnsiCommand::new(); let mut command = EnableAnsiCommand::new();
let success = command.execute(&context); let success = command.execute();
set_is_windows_ansi_supportable(success); set_is_windows_ansi_supportable(success);
set_ansi_enabled(success); set_ansi_enabled(success);
has_been_tried_to_enable(true); has_been_tried_to_enable(true);
success });
windows_supportable()
} }
/// Get whether ansi has been enabled. /// Get whether ansi has been enabled.

View File

@ -1,18 +1,17 @@
//! This module is the core of all the `WINAPI` actions. All unsafe `WINAPI` function call are done here. //! This module is the core of all the `WINAPI` actions. All unsafe `WINAPI` function call are done here.
use winapi::um::winnt::HANDLE; use winapi::um::winnt::HANDLE;
use winapi::um::winbase::{STD_OUTPUT_HANDLE, STD_INPUT_HANDLE }; use winapi::um::winbase::{STD_OUTPUT_HANDLE, STD_INPUT_HANDLE };
use winapi::um::handleapi::INVALID_HANDLE_VALUE; use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::processenv::{GetStdHandle}; use winapi::um::processenv::{GetStdHandle};
use winapi::um::consoleapi::{SetConsoleMode,GetConsoleMode, }; use winapi::um::consoleapi::{SetConsoleMode,GetConsoleMode, };
use winapi::shared::minwindef::{TRUE}; use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::um::wincon; use winapi::um::wincon;
use winapi::um::wincon:: use winapi::um::wincon::
{ {
SetConsoleWindowInfo, SetConsoleCursorPosition, SetConsoleTextAttribute, SetConsoleScreenBufferSize, CreateConsoleScreenBuffer,SetConsoleActiveScreenBuffer, SetConsoleWindowInfo, SetConsoleCursorPosition, SetConsoleTextAttribute, SetConsoleScreenBufferSize, CreateConsoleScreenBuffer,SetConsoleActiveScreenBuffer, SetConsoleCursorInfo,
GetLargestConsoleWindowSize, GetConsoleScreenBufferInfo, GetLargestConsoleWindowSize, GetConsoleScreenBufferInfo,
FillConsoleOutputCharacterA, FillConsoleOutputAttribute, FillConsoleOutputCharacterA, FillConsoleOutputAttribute,WriteConsoleOutputCharacterA,WriteConsoleOutputAttribute,
CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT, COORD, CHAR_INFO, PSMALL_RECT CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT, COORD, CHAR_INFO, PSMALL_RECT, CONSOLE_CURSOR_INFO
}; };
use super::{Empty}; use super::{Empty};
@ -132,6 +131,22 @@ pub fn set_console_cursor_position(x: i16, y: i16)
} }
} }
pub fn cursor_visibility(visable: bool)
{
let handle = get_output_handle();
let cursor_info = CONSOLE_CURSOR_INFO
{
dwSize: 100,
bVisible: if visable { FALSE } else {TRUE}
};
unsafe
{
SetConsoleCursorInfo(handle, &cursor_info);
}
}
pub fn set_console_text_attribute(value: u16) pub fn set_console_text_attribute(value: u16)
{ {
let output_handle = get_output_handle(); let output_handle = get_output_handle();
@ -282,6 +297,32 @@ pub fn write_console_output(write_buffer: &HANDLE, copy_buffer: &mut [CHAR_INFO;
} }
} }
pub fn write_char_buffer(handle: HANDLE, buf: &[u8])
{
use std::ffi::CString;
use std::str;
// get buffer info
let csbi = get_console_screen_buffer_info();
// get string from u8[] and parse it to an c_str
let mut data = str::from_utf8(buf).unwrap();
let c_str = CString::new(data);
let ptr: *const u16 = c_str.unwrap().as_ptr() as *const u16;
// get current position
let current_pos = COORD {X: csbi.dwCursorPosition.X, Y: csbi.dwCursorPosition.Y};
let mut cells_written: u32 = 0;
// write to console
unsafe
{
WriteConsoleOutputAttribute(handle, ptr, data.len() as u32, current_pos, &mut cells_written);
}
}
/// Parse integer to an bool /// Parse integer to an bool
fn is_true(value: i32) -> bool fn is_true(value: i32) -> bool
{ {

View File

@ -16,6 +16,7 @@ pub mod manager;
pub use shared::{screen, raw}; pub use shared::{screen, raw};
pub use state::context::Context; pub use state::context::Context;
use state::commands::IStateCommand;
use state::command_manager::CommandManager; use state::command_manager::CommandManager;
use state::state_manager::StateManager; use state::state_manager::StateManager;
use manager::ScreenManager; use manager::ScreenManager;

View File

@ -3,6 +3,7 @@
//! This module uses the stdout to write to the console. //! This module uses the stdout to write to the console.
use std::io::{self, Write}; use std::io::{self, Write};
use std::any::Any;
use super::IScreenManager; use super::IScreenManager;
@ -14,12 +15,11 @@ pub struct AnsiScreenManager
impl IScreenManager for AnsiScreenManager impl IScreenManager for AnsiScreenManager
{ {
type Output = Box<Write>;
fn stdout(&mut self) -> &mut Self::Output // fn stdout(&mut self) -> &mut Self::Output
{ // {
return &mut self.output // return &mut self.output
} // }
fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool) fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool)
{ {
@ -37,6 +37,19 @@ impl IScreenManager for AnsiScreenManager
write!(self.output, "{}", string); write!(self.output, "{}", string);
self.flush(); self.flush();
} }
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.output.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.output.flush()
}
fn as_any(&mut self) -> &mut Any
{
self
}
} }
impl AnsiScreenManager { impl AnsiScreenManager {
@ -47,14 +60,3 @@ impl AnsiScreenManager {
} }
} }
} }
impl Write for AnsiScreenManager
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.output.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.stdout().flush()
}
}

View File

@ -1,39 +1,38 @@
//! 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. //! 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. //! 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::{AnsiScreenManager, WinApiScreenManager, IScreenManager };
use super::super::shared::functions;
use std::any::Any;
use super::IScreenManager; use std::fmt::Display;
use super::ansi_manager::AnsiScreenManager; use std::io::{ self, Write };
use std::io::Write; #[cfg(target_os = "windows")]
use winapi::um::winnt::HANDLE;
/// Struct that stores an specific platform implementation for screen related actions. /// Struct that stores an specific platform implementation for screen related actions.
pub struct ScreenManager pub struct ScreenManager
{ {
screen_manager: Box<IScreenManager<Output=Box<Write>>> screen_manager: Box<IScreenManager>
} }
impl ScreenManager impl ScreenManager
{ {
/// Create new screen manager instance whereon screen related actions can be performed. /// 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 screen_manager = functions::get_module::<Box<IScreenManager>>(Box::from(WinApiScreenManager::new()), Box::from(AnsiScreenManager::new())).unwrap();
// //
// #[cfg(not(target_os = "windows"))] // #[cfg(not(target_os = "windows"))]
// let screen_manager = Box::new(AnsiScreenManager::new());
ScreenManager ScreenManager
{ {
screen_manager: Box::new(AnsiScreenManager::new()), screen_manager: Box::from(WinApiScreenManager::new()),
} }
} }
/// Get the stdout of the current screen pub fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool)
pub fn stdout(&mut self) -> &mut Box<Write>
{
self.screen_manager.stdout()
}
pub fn toggle_is_alternate_screen(&mut self,is_alternate_screen: bool)
{ {
self.screen_manager.toggle_is_alternate_screen(is_alternate_screen); self.screen_manager.toggle_is_alternate_screen(is_alternate_screen);
} }
@ -49,4 +48,17 @@ impl ScreenManager
{ {
self.screen_manager.write_ansi_str(string); self.screen_manager.write_ansi_str(string);
} }
pub fn as_any(&mut self) -> &mut Any { self.screen_manager.as_any() }
}
impl Write for ScreenManager
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.screen_manager.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.screen_manager.flush()
}
} }

View File

@ -8,20 +8,26 @@ mod win_manager;
mod ansi_manager; mod ansi_manager;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::win_manager::WinApiScreenManager; pub use self::win_manager::WinApiScreenManager;
use self::ansi_manager::AnsiScreenManager; pub use self::ansi_manager::AnsiScreenManager;
pub use self::manager::{ ScreenManager }; pub use self::manager::{ ScreenManager };
use std::io;
use std::any::Any;
pub trait IScreenManager pub trait IScreenManager
{ {
type Output;
/// get the stdout of the screen. This can be used to write to the /// get the stdout of the screen. This can be used to write to the
fn stdout(&mut self) -> &mut Self::Output; // fn stdout(&mut self) -> &mut Self::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. /// 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. /// Write a &str to the current stdout.
fn write_ansi_str(&mut self, string: &str); fn write_ansi_str(&mut self, string: &str);
fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
fn flush(&mut self) -> io::Result<()>;
fn as_any(&mut self) -> &mut Any;
} }

View File

@ -2,21 +2,18 @@ use super::IScreenManager;
use kernel::windows_kernel::kernel; use kernel::windows_kernel::kernel;
use winapi::um::winnt::HANDLE; use winapi::um::winnt::HANDLE;
use std::io::{self,Write};
use std::any::Any;
pub struct WinApiScreenManager pub struct WinApiScreenManager
{ {
pub is_alternate_screen: bool, pub is_alternate_screen: bool,
output: Box<HANDLE>, output: HANDLE,
alternate_handle: HANDLE
} }
impl IScreenManager for WinApiScreenManager where impl IScreenManager for WinApiScreenManager
{ {
type Output = HANDLE;
fn stdout(&mut self) -> &mut Self::Output
{
return &mut self.output
}
fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool) fn toggle_is_alternate_screen(&mut self, is_alternate_screen: bool)
{ {
self.is_alternate_screen = is_alternate_screen; self.is_alternate_screen = is_alternate_screen;
@ -33,24 +30,39 @@ impl IScreenManager for WinApiScreenManager where
// write!(self.output, "{}", string); // write!(self.output, "{}", string);
// self.flush(); // self.flush();
} }
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.is_alternate_screen
{
kernel::write_char_buffer(self.alternate_handle, buf);
}
else {
kernel::write_char_buffer(self.output, buf);
}
Ok(0)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn as_any(&mut self) -> &mut Any
{
self
}
} }
impl WinApiScreenManager { impl WinApiScreenManager {
pub fn new() -> Self { pub fn new() -> Self {
WinApiScreenManager { WinApiScreenManager {
output: (Box::from(kernel::get_output_handle())), output: kernel::get_output_handle(),
is_alternate_screen: false is_alternate_screen: false,
alternate_handle: kernel::get_output_handle(),
} }
} }
pub fn set_alternate_handle(&mut self, alternate_handle: HANDLE)
{
self.alternate_handle = alternate_handle;
}
} }
//impl<Output:Write> Write for AnsiScreenManager<Output>
//{
// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// self.output.write(buf)
// }
//
// fn flush(&mut self) -> io::Result<()> {
// self.stdout().flush()
// }
//}

View File

@ -1,6 +1,7 @@
//! 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 Context; use Context;
use std::rc::Rc;
#[cfg(windows)] #[cfg(windows)]
use kernel::windows_kernel::terminal::terminal_size; use kernel::windows_kernel::terminal::terminal_size;
@ -20,7 +21,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: &Context) -> (u16, u16) pub fn get_cursor_position(screen: Rc<Context>) -> (u16, u16)
{ {
#[cfg(unix)] #[cfg(unix)]
return pos(&screen); return pos(&screen);
@ -31,7 +32,7 @@ pub fn get_cursor_position(screen: &Context) -> (u16, u16)
#[cfg(windows)] #[cfg(windows)]
/// Get an module specific implementation based on the current platform. /// Get an module specific implementation based on the current platform.
pub fn get_module<T>(winapi_impl: T, unix_impl: T, context: &Context) -> Option<T> pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T>
{ {
let mut term: Option<T> = None; let mut term: Option<T> = None;
let mut does_support = true; let mut does_support = true;
@ -41,7 +42,7 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T, context: &Context) -> Option<
use kernel::windows_kernel::ansi_support::try_enable_ansi_support; use kernel::windows_kernel::ansi_support::try_enable_ansi_support;
// Try to enable ansi on windows if not than use WINAPI. // Try to enable ansi on windows if not than use WINAPI.
does_support = try_enable_ansi_support(&context); does_support = try_enable_ansi_support();
if !does_support if !does_support
{ {

View File

@ -31,56 +31,56 @@ use std::io::{ self, Write};
use std::rc::Rc; use std::rc::Rc;
/// A wrapper for the raw terminal state. Which can be used to write to. /// A wrapper for the raw terminal state. Which can be used to write to.
pub struct RawTerminal<'a> pub struct RawTerminal
{ {
terminal : &'a Context, context : Rc<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: Write + Sized
{ {
fn into_raw_mode(&self, terminal: &'a Context) -> io::Result<RawTerminal<'a>>; fn into_raw_mode(&self, context:Rc<Context>) -> io::Result<RawTerminal>;
} }
impl <'a, W: Write> IntoRawMode<'a> for W impl <W: Write> IntoRawMode for W
{ {
/// Raw mode means that input (stdin) won't be printed it will instead have to be written manually by /// 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 /// the program. The input isn't canonicalised or line buffered (that is, you can
/// read from input(stdin) one byte of a time). /// read from input(stdin) one byte of a time).
fn into_raw_mode(&self, terminal: &'a Context) -> io::Result<RawTerminal<'a>> { fn into_raw_mode(&self, context: Rc<Context>) -> io::Result<RawTerminal> {
let command_id = EnableRawModeCommand::new(&terminal.state_manager); let command_id = EnableRawModeCommand::new(&context.state_manager);
let success = CommandManager::execute(terminal, command_id); let success = CommandManager::execute(context.clone(), command_id);
if success if success
{ {
Ok(RawTerminal { terminal: &terminal, command_id: command_id}) Ok(RawTerminal { context: context.clone(), command_id: command_id})
}else { panic!("cannot move into raw mode") } }else { panic!("cannot move into raw mode") }
} }
} }
impl<'a> Write for RawTerminal<'a> { impl Write for RawTerminal {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut screen = self.terminal.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.stdout().write(buf) screen.write(buf)
} }
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
let mut screen = self.terminal.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.stdout().flush() screen.flush()
} }
} }
} }
/// If an instance of `RawTerminal` will be dropped all terminal changes that are made will be undone. /// If an instance of `RawTerminal` will be dropped all terminal changes that are made will be undone.
impl <'a> Drop for RawTerminal<'a> impl Drop for RawTerminal
{ {
fn drop(&mut self) fn drop(&mut self)
{ {
let success = CommandManager::undo(&self.terminal, self.command_id); let success = CommandManager::undo(self.context.clone(), self.command_id);
} }
} }

View File

@ -2,67 +2,97 @@
use Context; use Context;
use state::commands::*; use state::commands::*;
use super::functions;
use std::io::{self, Write};
pub struct AlternateScreen<'context> { use std::io::{self, Write};
context: &'context Context use std::rc::Rc;
pub struct AlternateScreen {
context: Rc<Context>,
command_id: u16
} }
impl<'context> AlternateScreen<'context> { impl AlternateScreen {
/// Get the alternate screen from the context. /// Get the alternate screen from the context.
/// By calling this method the current screen will be changed to the alternate screen. /// By calling this method the current screen will be changed to the alternate screen.
/// And you get back an handle for that screen. /// And you get back an handle for that screen.
pub fn from(context: &'context Context) -> Self { pub fn from(context: Rc<Context>) -> Self {
get_to_alternate_screen_command(context).execute(&context); let command_id = get_to_alternate_screen_command(context.clone());
AlternateScreen { context: context }
let screen = AlternateScreen { context: context, command_id: command_id };
screen.to_alternate();
return screen;
} }
/// Change the current screen to the mainscreen. /// Change the current screen to the mainscreen.
pub fn to_main(&self) pub fn to_main(&self)
{ {
get_to_alternate_screen_command(&self.context).undo(&self.context); let mut mutex = &self.context.state_manager;
{
let mut state_manager = mutex.lock().unwrap();
let mut mx = &state_manager.get(self.command_id);
{
let mut command = mx.lock().unwrap();
command.undo();
}
}
} }
/// Change the current screen to alternate screen. /// Change the current screen to alternate screen.
pub fn to_alternate(&self) pub fn to_alternate(&self)
{ {
get_to_alternate_screen_command(&self.context).execute(&self.context); let mut mutex = &self.context.state_manager;
{
let mut state_manager = mutex.lock().unwrap();
let mut mx = &state_manager.get(self.command_id);
{
let mut command = mx.lock().unwrap();
command.execute();
}
}
} }
} }
impl<'context> Write for AlternateScreen<'context> { impl Write for AlternateScreen {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut screen = self.context.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.stdout().write(buf) screen.write(buf)
} }
} }
fn flush(&mut self) -> io::Result<()> { fn flush(&mut self) -> io::Result<()> {
let mut screen = self.context.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.stdout().flush() screen.flush()
} }
} }
} }
impl<'context> Drop for AlternateScreen<'context> impl Drop for AlternateScreen
{ {
fn drop(&mut self) fn drop(&mut self)
{ {
get_to_alternate_screen_command(&self.context).undo(&self.context); let mut mutex = &self.context.state_manager;
{
let mut state_manager = mutex.lock().unwrap();
let mut mx = &state_manager.get(self.command_id);
{
let mut command = mx.lock().unwrap();
command.undo();
}
}
} }
} }
// Get the alternate screen command to enable and disable alternate screen based on the current platform // Get the alternate screen command to enable and disable alternate screen based on the current platform
fn get_to_alternate_screen_command(context: &Context) -> Box<ICommand> fn get_to_alternate_screen_command(context: Rc<Context>) -> u16
{ {
#[cfg(target_os = "windows")] // #[cfg(target_os = "windows")]
let command = functions::get_module::<Box<ICommand>>(win_commands::ToAlternateScreenBufferCommand::new(), shared_commands::ToAlternateScreenBufferCommand::new(), context).unwrap(); // let command = functions::get_module::<Box<ICommand>>(win_commands::ToAlternateScreenBufferCommand::new(), shared_commands::ToAlternateScreenBufferCommand::new(), context).unwrap();
#[cfg(not(target_os = "windows"))] // #[cfg(not(target_os = "windows"))]
let command = shared_commands::ToAlternateScreenBufferCommand::new(); win_commands::ToAlternateScreenBufferCommand::new(context)
command
} }

View File

@ -9,32 +9,32 @@ pub struct CommandManager;
impl CommandManager impl CommandManager
{ {
/// execute an certain command by id. /// execute an certain command by id.
pub fn execute(terminal: &Context, command_id: u16) -> bool pub fn execute(context: Rc<Context>, command_id: u16) -> bool
{ {
let mut mutex: Rc<Mutex<Box<IStateCommand>>>; let mut mutex: Rc<Mutex<Box<IStateCommand>>>;
let mut state = terminal.state_manager.lock().unwrap(); let mut state = context.state_manager.lock().unwrap();
{ {
mutex = state.get(command_id); mutex = state.get(command_id);
} }
let mut command = mutex.lock().unwrap(); let mut command = mutex.lock().unwrap();
let has_succeeded = command.execute(&terminal); let has_succeeded = command.execute();
return has_succeeded; return has_succeeded;
} }
/// undo an certain command by id. /// undo an certain command by id.
pub fn undo(terminal: &Context, command_id: u16) -> bool pub fn undo(context: Rc<Context>, command_id: u16) -> bool
{ {
let mut mutex: Rc<Mutex<Box<IStateCommand>>>; let mut mutex: Rc<Mutex<Box<IStateCommand>>>;
let mut state = terminal.state_manager.lock().unwrap(); let mut state = context.state_manager.lock().unwrap();
{ {
mutex = state.get(command_id); mutex = state.get(command_id);
} }
let mut command = mutex.lock().unwrap(); let mut command = mutex.lock().unwrap();
let has_succeeded = command.undo(&terminal); let has_succeeded = command.undo();
return has_succeeded; return has_succeeded;
} }
} }

View File

@ -25,21 +25,11 @@ pub use self::unix_command::*;
#[cfg(windows)] #[cfg(windows)]
pub use self::win_commands::*; pub use self::win_commands::*;
use {StateManager, Context};
/// This command can be used for simple commands witch just have an `undo()` and an `execute()`
pub trait ICommand
{
fn new() -> Box<Self> where Self: Sized;
fn execute(&mut self, terminal: &Context) -> 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 IStateCommand pub trait IStateCommand
{ {
fn execute(&mut self, terminal: &Context) -> bool; fn execute(&mut self) -> bool;
fn undo(&mut self, terminal: &Context) -> bool; fn undo(&mut self) -> bool;
} }

View File

@ -1,35 +1,40 @@
//! This module contains the commands that can be used for both unix and windows systems. Or else said terminals that support ansi codes. //! This module contains the commands that can be used for both unix and windows systems. Or else said terminals that support ansi codes.
use Context; use Context;
use super::{ICommand, IStateCommand}; use super::{IStateCommand};
pub struct EmptyCommand; pub struct EmptyCommand;
impl IStateCommand for EmptyCommand impl IStateCommand for EmptyCommand
{ {
fn execute(&mut self, terminal: &Context) -> bool fn execute(&mut self) -> bool
{ {
return false return false
} }
fn undo(&mut self, terminal: &Context) -> bool fn undo(&mut self) -> bool
{ {
return false; 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)] pub struct ToAlternateScreenBufferCommand<'a>
pub struct ToAlternateScreenBufferCommand;
impl ICommand for ToAlternateScreenBufferCommand
{ {
fn new() -> Box<ToAlternateScreenBufferCommand> { context: &'a Context
Box::from(ToAlternateScreenBufferCommand {}) }
}
fn execute(&mut self, terminal: &Context) -> bool impl<'a> ToAlternateScreenBufferCommand<'a>
{
pub fn new(context: & 'a Context) -> Box < ToAlternateScreenBufferCommand > {
Box::from(ToAlternateScreenBufferCommand {context: context})
}
}
impl<'context> IStateCommand for ToAlternateScreenBufferCommand<'context>
{
fn execute(&mut self) -> bool
{ {
let mut screen = terminal.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.write_ansi_str(csi!("?1049h")); screen.write_ansi_str(csi!("?1049h"));
screen.toggle_is_alternate_screen(true); screen.toggle_is_alternate_screen(true);
@ -37,9 +42,9 @@ impl ICommand for ToAlternateScreenBufferCommand
} }
} }
fn undo(&mut self, terminal: &Context) -> bool fn undo(&mut self) -> bool
{ {
let mut screen = terminal.screen_manager.lock().unwrap(); let mut screen = self.context.screen_manager.lock().unwrap();
{ {
screen.write_ansi_str(csi!("?1049l")); screen.write_ansi_str(csi!("?1049l"));
screen.toggle_is_alternate_screen(false); screen.toggle_is_alternate_screen(false);

View File

@ -34,7 +34,7 @@ impl NoncanonicalModeCommand
impl IStateCommand for NoncanonicalModeCommand impl IStateCommand for NoncanonicalModeCommand
{ {
fn execute(&mut self, terminal: &Context) -> bool fn execute(&mut self) -> 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)
@ -53,7 +53,7 @@ impl IStateCommand for NoncanonicalModeCommand
} }
} }
fn undo(&mut self, terminal: &Context) -> bool fn undo(&mut self) -> 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)
@ -97,7 +97,7 @@ impl EnableRawModeCommand
impl IStateCommand for EnableRawModeCommand impl IStateCommand for EnableRawModeCommand
{ {
fn execute(&mut self, terminal: &Context) -> bool fn execute(&mut self) -> bool
{ {
let original_mode = terminal::get_terminal_mode(); let original_mode = terminal::get_terminal_mode();
@ -114,7 +114,7 @@ impl IStateCommand for EnableRawModeCommand
} }
} }
fn undo(&mut self, terminal: &Context) -> bool fn undo(&mut self) -> bool
{ {
if let Some(ref original_mode) = self.original_mode if let Some(ref original_mode) = self.original_mode
{ {

View File

@ -1,6 +1,6 @@
//! This module contains the commands that can be used for windows systems. //! This module contains the commands that can be used for windows systems.
use super::{ICommand, IStateCommand}; use super::IStateCommand;
use { StateManager, Context }; use { StateManager, Context };
use kernel::windows_kernel::{kernel, ansi_support}; use kernel::windows_kernel::{kernel, ansi_support};
@ -20,14 +20,18 @@ pub struct EnableAnsiCommand
mask: DWORD, mask: DWORD,
} }
impl ICommand for EnableAnsiCommand impl EnableAnsiCommand
{ {
fn new() -> Box<EnableAnsiCommand> { pub fn new() -> Box<EnableAnsiCommand> {
let command = EnableAnsiCommand { mask: ENABLE_VIRTUAL_TERMINAL_PROCESSING }; let command = EnableAnsiCommand { mask: ENABLE_VIRTUAL_TERMINAL_PROCESSING };
Box::from(command) Box::from(command)
} }
}
fn execute(&mut self, context: &Context) -> bool
impl IStateCommand for EnableAnsiCommand
{
fn execute(&mut self,) -> bool
{ {
// we need to check whether we tried to enable ansi before. If we have we can just return if that had succeeded. // we need to check whether we tried to enable ansi before. If we have we can just return if that had succeeded.
if ansi_support::has_been_tried_to_enable_ansi() && ansi_support::ansi_enabled() if ansi_support::has_been_tried_to_enable_ansi() && ansi_support::ansi_enabled()
@ -39,14 +43,12 @@ impl ICommand for EnableAnsiCommand
let mut dw_mode: DWORD = 0; let mut dw_mode: DWORD = 0;
if !kernel::get_console_mode(&output_handle, &mut dw_mode) if !kernel::get_console_mode(&output_handle, &mut dw_mode)
{ {
panic!("Cannot get console mode");
return false; return false;
} }
dw_mode |= self.mask; dw_mode |= self.mask;
if !kernel::set_console_mode(&output_handle, dw_mode) if !kernel::set_console_mode(&output_handle, dw_mode)
{ {
panic!("Cannot get console mode");
return false; return false;
} }
@ -54,7 +56,7 @@ impl ICommand for EnableAnsiCommand
} }
} }
fn undo(&mut self, context: &Context) -> bool fn undo(&mut self) -> bool
{ {
if ansi_support::ansi_enabled() if ansi_support::ansi_enabled()
{ {
@ -90,8 +92,7 @@ pub struct EnableRawModeCommand
impl EnableRawModeCommand impl EnableRawModeCommand
{ {
pub fn new(state_manager: &Mutex<StateManager>) -> u16 { pub fn new(state_manager: &Mutex<StateManager>) -> u16 {
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_ECHO_INPUT};
let mut state = state_manager.lock().unwrap(); let mut state = state_manager.lock().unwrap();
{ {
@ -105,10 +106,8 @@ impl EnableRawModeCommand
impl IStateCommand for EnableRawModeCommand impl IStateCommand for EnableRawModeCommand
{ {
fn execute(&mut self, context: &Context) -> bool fn execute(&mut self) -> bool
{ {
use self::wincon::{ENABLE_LINE_INPUT,ENABLE_PROCESSED_INPUT, ENABLE_ECHO_INPUT};
let input_handle = kernel::get_input_handle(); let input_handle = kernel::get_input_handle();
let mut dw_mode: DWORD = 0; let mut dw_mode: DWORD = 0;
@ -127,7 +126,7 @@ impl IStateCommand for EnableRawModeCommand
true true
} }
fn undo(&mut self, context: &Context) -> bool fn undo(&mut self) -> bool
{ {
let output_handle = kernel::get_output_handle(); let output_handle = kernel::get_output_handle();
@ -150,18 +149,39 @@ impl IStateCommand for EnableRawModeCommand
/// This command is used for switching to alternate screen and back to main screen. /// This command is used for switching to alternate screen and back to main screen.
/// check https://docs.microsoft.com/en-us/windows/console/reading-and-writing-blocks-of-characters-and-attributes for more info /// check https://docs.microsoft.com/en-us/windows/console/reading-and-writing-blocks-of-characters-and-attributes for more info
#[derive(Clone, Copy)] pub struct ToAlternateScreenBufferCommand
pub struct ToAlternateScreenBufferCommand;
impl ICommand for ToAlternateScreenBufferCommand
{ {
fn new() -> Box<ToAlternateScreenBufferCommand> context: Rc<Context>
{ }
Box::from(ToAlternateScreenBufferCommand {})
}
fn execute(&mut self, context: &Context) -> bool impl ToAlternateScreenBufferCommand
{
pub fn new(context: Rc<Context>) -> u16
{ {
let key = 2;
let mut state = context.state_manager.lock().unwrap();
{
let command = ToAlternateScreenBufferCommand {context: context.clone()};
state.register_change(Box::from(command), key);
key
}
}
}
impl IStateCommand for ToAlternateScreenBufferCommand
{
fn execute(&mut self) -> bool
{
use super::super::super::kernel::windows_kernel::ansi_support;
use super::super::super::manager::WinApiScreenManager;
let does_support = ansi_support::try_enable_ansi_support();
let mut screen_manager = self.context.screen_manager.lock().unwrap();
screen_manager.toggle_is_alternate_screen(true);
let mut chi_buffer: [CHAR_INFO;160] = unsafe {mem::zeroed() }; let mut chi_buffer: [CHAR_INFO;160] = unsafe {mem::zeroed() };
let handle = kernel::get_output_handle(); let handle = kernel::get_output_handle();
@ -172,6 +192,13 @@ impl ICommand for ToAlternateScreenBufferCommand
// Make the new screen buffer the active screen buffer. // Make the new screen buffer the active screen buffer.
kernel::set_active_screen_buffer(new_handle); kernel::set_active_screen_buffer(new_handle);
let b: &mut WinApiScreenManager = match screen_manager.as_any().downcast_mut::<WinApiScreenManager>() {
Some(b) => { b },
None => panic!("&a isn't a B!")
};
b.set_alternate_handle(new_handle);
// Set the source rectangle. // Set the source rectangle.
let mut srct_read_rect = SMALL_RECT let mut srct_read_rect = SMALL_RECT
{ {
@ -214,10 +241,16 @@ impl ICommand for ToAlternateScreenBufferCommand
true true
} }
fn undo(&mut self, context: &Context) -> bool fn undo(&mut self) -> 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);
{
let mut screen_manager = self.context.screen_manager.lock().unwrap();
screen_manager.toggle_is_alternate_screen(false);
}
true true
} }
} }

View File

@ -1,13 +1,9 @@
//! This module contains the code for the context of the terminal. //! This module contains the code for the context of the terminal.
use { StateManager, ScreenManager };
use std::sync::Mutex; use std::sync::Mutex;
use std::rc::Rc; use std::rc::Rc;
use super::super::style;
use { StateManager, ScreenManager };
use std::fmt;
/// This type contains the context of the current terminal. The context surrounds the changed states of the terminal and can be used for managing the output of the terminal. /// 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
{ {
@ -39,46 +35,12 @@ impl Context
/// let color = terminal::color(&context); /// let color = terminal::color(&context);
/// ///
/// ``` /// ```
pub fn new() -> Context pub fn new() -> Rc<Context>
{ {
Context { Rc::new(Context {
screen_manager: Rc::new(Mutex::new(ScreenManager::new())), screen_manager: Rc::new(Mutex::new(ScreenManager::new())),
state_manager: Mutex::new(StateManager::new()) state_manager: Mutex::new(StateManager::new())
} })
}
/// 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)
} }
} }
@ -87,6 +49,6 @@ impl Drop for Context
fn drop(&mut self) fn drop(&mut self)
{ {
let mut changes = self.state_manager.lock().unwrap(); let mut changes = self.state_manager.lock().unwrap();
changes.restore_changes(&self); changes.restore_changes();
} }
} }

View File

@ -1,11 +1,9 @@
//! This module is used for registering, storing an restoring the terminal state changes. //! This module is used for registering, storing an restoring the terminal state changes.
use Context;
use super::commands::IStateCommand; use super::commands::IStateCommand;
use super::commands::shared_commands::EmptyCommand; use super::commands::shared_commands::EmptyCommand;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Mutex;
use std::collections::HashMap; use std::collections::HashMap;
/// Struct that stores the changed states of the terminal. /// Struct that stores the changed states of the terminal.
@ -25,12 +23,12 @@ impl StateManager
} }
/// Restore all changes that are made to the terminal. /// Restore all changes that are made to the terminal.
pub fn restore_changes(&mut self, context: &Context) pub fn restore_changes(&mut self)
{ {
for (id, item) in self.changed_states.iter_mut() for (id, item) in self.changed_states.iter_mut()
{ {
let mut item = item.lock().unwrap(); let mut item = item.lock().unwrap();
item.undo(&context); item.undo();
} }
} }

View File

@ -17,9 +17,9 @@ pub struct TerminalColor {
impl TerminalColor { impl TerminalColor {
/// Create new instance whereon color related actions can be performed. /// Create new instance whereon color related actions can be performed.
pub fn new(context: &Context ) -> TerminalColor { pub fn new(context: Rc<Context>) -> TerminalColor {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let color = functions::get_module::<Box<ITerminalColor>>(WinApiColor::new(), AnsiColor::new(), context); let color = functions::get_module::<Box<ITerminalColor>>(WinApiColor::new(), AnsiColor::new());
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let color = Some(AnsiColor::new() as Box<ITerminalColor>); let color = Some(AnsiColor::new() as Box<ITerminalColor>);
@ -127,6 +127,6 @@ impl TerminalColor {
/// ///
/// Check `/examples/version/color` in the libary for more specific examples. /// Check `/examples/version/color` in the libary for more specific examples.
/// ///
pub fn color(context: &Context) -> Box<TerminalColor> { pub fn color(context: Rc<Context>) -> Box<TerminalColor> {
Box::from(TerminalColor::new(context)) Box::from(TerminalColor::new(context))
} }

View File

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

View File

@ -1,10 +1,10 @@
//! This module contains the logic to style an object that contains some state witch can be styled. //! This module contains the logic to style an object that contains some state witch can be styled.
use Context;
use std::fmt; use std::fmt;
use std::io::Write; use std::io::Write;
use std::sync::Mutex;
use std::rc::Rc; use std::rc::Rc;
use { ScreenManager, Context};
#[cfg(unix)] #[cfg(unix)]
use super::super::Attribute; use super::super::Attribute;
@ -12,13 +12,13 @@ use super::super::Attribute;
use style::{Color, ObjectStyle}; use style::{Color, ObjectStyle};
/// Struct that contains both the style and the content wits can be styled. /// Struct that contains both the style and the content wits can be styled.
pub struct StyledObject<'a, D> { pub struct StyledObject<D> {
pub object_style: ObjectStyle, pub object_style: ObjectStyle,
pub content: D, pub content: D,
pub context: &'a Context pub context: Rc<Context>
} }
impl<'a, D> StyledObject<'a,D> { impl<D> StyledObject<D> {
/// Set the foreground of the styled object to the passed `Color` /// Set the foreground of the styled object to the passed `Color`
/// ///
/// #Example /// #Example
@ -39,7 +39,7 @@ impl<'a, D> StyledObject<'a,D> {
/// println!("{}", paint("I am colored green").with(Color::Green)); /// println!("{}", paint("I am colored green").with(Color::Green));
/// ///
/// ``` /// ```
pub fn with(mut self, foreground_color: Color) -> StyledObject<'a,D> { pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.fg(foreground_color); self.object_style = self.object_style.fg(foreground_color);
self self
} }
@ -64,7 +64,7 @@ impl<'a, D> StyledObject<'a,D> {
/// println!("{}", paint("I am colored green").on(Color::Green)) /// println!("{}", paint("I am colored green").on(Color::Green))
/// ///
/// ``` /// ```
pub fn on(mut self, background_color: Color) -> StyledObject<'a,D> { pub fn on(mut self, background_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.bg(background_color); self.object_style = self.object_style.bg(background_color);
self self
} }
@ -82,7 +82,7 @@ impl<'a, D> StyledObject<'a,D> {
/// ///
/// ``` /// ```
#[cfg(unix)] #[cfg(unix)]
pub fn attr(mut self, attr: Attribute) -> StyledObject<'a,D> pub fn attr(mut self, attr: Attribute) -> StyledObject<D>
{ {
&self.object_style.add_attr(attr); &self.object_style.add_attr(attr);
self self
@ -113,10 +113,10 @@ impl<'a, D> StyledObject<'a,D> {
macro_rules! impl_fmt macro_rules! impl_fmt
{ {
($name:ident) => { ($name:ident) => {
impl<'a, D: fmt::$name> fmt::$name for StyledObject<'a, D> { impl<D: fmt::$name> fmt::$name for StyledObject<D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{ {
let mut colored_terminal = super::super::color(&self.context); let mut colored_terminal = super::super::color(self.context.clone());
let mut reset = true; let mut reset = true;
if let Some(bg) = self.object_style.bg_color if let Some(bg) = self.object_style.bg_color
@ -132,7 +132,11 @@ macro_rules! impl_fmt
#[cfg(unix)] #[cfg(unix)]
for attr in self.object_style.attrs.iter() { for attr in self.object_style.attrs.iter() {
write!(f, csi!("{}m"), *attr as i16); let mutex = self.context.screen_manager;
{
let mut screen = mutex.lock().unwrap();
screen.write_ansi_str(format!(csi!("{}m"), *attr as i16)).expect("Flush failed");
}
reset = true; reset = true;
} }
@ -141,7 +145,8 @@ macro_rules! impl_fmt
let mutex = &self.context.screen_manager; let mutex = &self.context.screen_manager;
{ {
let mut screen = mutex.lock().unwrap(); let mut screen = mutex.lock().unwrap();
screen.stdout().flush().expect("Flush stdout failed");
screen.flush().expect("Flush failed");
} }
if reset if reset

View File

@ -3,66 +3,65 @@
use Context; use Context;
use shared::functions; use shared::functions;
use super::{ClearType, ITerminal}; use super::{ClearType, ITerminal, Rc};
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
{
context: Rc<Context>
}
impl AnsiTerminal { impl AnsiTerminal {
pub fn new() -> Box<AnsiTerminal> { pub fn new(context: Rc<Context>) -> Box<AnsiTerminal> {
Box::from(AnsiTerminal {}) Box::from(AnsiTerminal {context: context})
} }
} }
impl ITerminal for AnsiTerminal { impl ITerminal for AnsiTerminal {
fn clear(&self, clear_type: ClearType, context: &Context) { fn clear(&self, clear_type: ClearType)
{
let mut screen_manager = context.screen_manager.lock().unwrap(); let mut screen_manager = self.context.screen_manager.lock().unwrap();
{ {
let stdout = screen_manager.stdout();
match clear_type { match clear_type {
ClearType::All => { ClearType::All => {
write!(stdout, csi!("2J")); screen_manager.write_ansi_str(csi!("2J"));
}, },
ClearType::FromCursorDown => { ClearType::FromCursorDown => {
write!(stdout, csi!("J")); screen_manager.write_ansi_str(csi!("J"));
}, },
ClearType::FromCursorUp => { ClearType::FromCursorUp => {
write!(stdout, csi!("1J")); screen_manager.write_ansi_str(csi!("1J"));
}, },
ClearType::CurrentLine => { ClearType::CurrentLine => {
write!(stdout, csi!("2K")); screen_manager.write_ansi_str(csi!("2K"));
}, },
ClearType::UntilNewLine => { ClearType::UntilNewLine => {
write!(stdout, csi!("K")); screen_manager.write_ansi_str(csi!("K"));
}, },
}; };
} }
} }
fn terminal_size(&self, context: &Context) -> (u16, u16) { fn terminal_size(&self) -> (u16, u16) {
functions::get_terminal_size() functions::get_terminal_size()
} }
fn scroll_up(&self, count: i16, context: &Context) { fn scroll_up(&self, count: i16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.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, context: &Context) { fn scroll_down(&self, count: i16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.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, context: &Context) { fn set_size(&self, width: i16, height: i16) {
let mut screen = context.screen_manager.lock().unwrap(); let mut screen = self.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

@ -15,6 +15,7 @@ mod ansi_terminal;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use self::winapi_terminal::WinApiTerminal; use self::winapi_terminal::WinApiTerminal;
use self::ansi_terminal::AnsiTerminal; use self::ansi_terminal::AnsiTerminal;
use std::rc::Rc;
use Context; use Context;
pub use self::terminal::{ terminal}; pub use self::terminal::{ terminal};
@ -38,13 +39,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, context: &Context); fn clear(&self, clear_type: ClearType);
/// Get the terminal size (x,y) /// Get the terminal size (x,y)
fn terminal_size(&self, context: &Context) -> (u16, u16); fn terminal_size(&self) -> (u16, u16);
/// Scroll `n` lines up in the current terminal. /// Scroll `n` lines up in the current terminal.
fn scroll_up(&self, count: i16, context: &Context); fn scroll_up(&self, count: i16);
/// Scroll `n` lines down in the current terminal. /// Scroll `n` lines down in the current terminal.
fn scroll_down(&self, count: i16, context: &Context); fn scroll_down(&self, count: i16);
/// Resize terminal to the given width and height. /// Resize terminal to the given width and height.
fn set_size(&self,width: i16, height: i16, context: &Context); fn set_size(&self,width: i16, height: i16);
} }

View File

@ -3,25 +3,26 @@
use super::*; use super::*;
use Context; use Context;
use std::fmt;
use super::super::style; use super::super::style;
use super::super::shared::functions; use super::super::shared::functions;
use std::fmt;
use std::rc::Rc;
/// 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<'context> { pub struct Terminal {
terminal: Option<Box<ITerminal>>, terminal: Option<Box<ITerminal>>,
context: &'context Context context: Rc<Context>
} }
impl<'context> Terminal<'context> { impl Terminal {
/// 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(context: &'context Context) -> Terminal<'context> { pub fn new(context: Rc<Context>) -> Terminal {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let terminal = functions::get_module::<Box<ITerminal>>(WinApiTerminal::new(), AnsiTerminal::new(), context); let terminal = functions::get_module::<Box<ITerminal>>(WinApiTerminal::new(context.clone()), AnsiTerminal::new(context.clone()));
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let terminal = Some(AnsiTerminal::new() as Box<ITerminal>); let terminal = Some(AnsiTerminal::new(context.clone()) as Box<ITerminal>);
Terminal { terminal, context: context } Terminal { terminal, context: context }
@ -54,7 +55,7 @@ impl<'context> Terminal<'context> {
/// ``` /// ```
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.context); terminal.clear(clear_type);
} }
} }
@ -77,7 +78,7 @@ impl<'context> Terminal<'context> {
/// ``` /// ```
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.context) return terminal.terminal_size()
} }
(0,0) (0,0)
} }
@ -101,7 +102,7 @@ impl<'context> Terminal<'context> {
/// ``` /// ```
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.context); terminal.scroll_up(count);
} }
} }
@ -124,7 +125,7 @@ impl<'context> Terminal<'context> {
/// ``` /// ```
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.context); terminal.scroll_down(count);
} }
} }
@ -148,7 +149,7 @@ impl<'context> Terminal<'context> {
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.context); terminal.set_size(width,height);
} }
} }
@ -183,7 +184,7 @@ impl<'context> Terminal<'context> {
where where
D: fmt::Display, D: fmt::Display,
{ {
style::ObjectStyle::new().apply_to(val, &self.context) style::ObjectStyle::new().apply_to(val, self.context.clone())
} }
} }
@ -208,6 +209,6 @@ impl<'context> Terminal<'context> {
/// ///
/// ``` /// ```
/// ///
pub fn terminal<'context>(context: &'context Context) -> Box<Terminal<'context>> { pub fn terminal(context: Rc<Context>) -> Box<Terminal> {
Box::from(Terminal::new(&context)) Box::from(Terminal::new(context.clone()))
} }

View File

@ -3,44 +3,47 @@
use Context; use Context;
use cursor::cursor; use cursor::cursor;
use super::{ClearType, ITerminal}; use super::{ClearType, ITerminal, Rc};
use winapi::um::wincon::{SMALL_RECT, COORD, CONSOLE_SCREEN_BUFFER_INFO,}; use winapi::um::wincon::{SMALL_RECT, COORD, CONSOLE_SCREEN_BUFFER_INFO,};
use kernel::windows_kernel::{kernel, terminal}; use kernel::windows_kernel::{kernel, terminal};
/// This struct is an windows implementation for terminal related actions. /// This struct is an windows implementation for terminal related actions.
pub struct WinApiTerminal; pub struct WinApiTerminal
{
context: Rc<Context>
}
impl WinApiTerminal { impl WinApiTerminal {
pub fn new() -> Box<WinApiTerminal> { pub fn new(context: Rc<Context>) -> Box<WinApiTerminal> {
Box::from(WinApiTerminal {}) Box::from(WinApiTerminal { context })
} }
} }
impl ITerminal for WinApiTerminal { impl ITerminal for WinApiTerminal {
fn clear(&self, clear_type: ClearType, context: &Context) { fn clear(&self, clear_type: ClearType) {
let csbi = kernel::get_console_screen_buffer_info(); let csbi = kernel::get_console_screen_buffer_info();
let pos = cursor(&context).pos(); let pos = cursor(self.context.clone()).pos();
match clear_type match clear_type
{ {
ClearType::All => clear_entire_screen(csbi, &context), ClearType::All => clear_entire_screen(csbi, self.context.clone()),
ClearType::FromCursorDown => clear_after_cursor(pos,csbi,&context), ClearType::FromCursorDown => clear_after_cursor(pos,csbi, self.context.clone()),
ClearType::FromCursorUp => clear_before_cursor(pos, csbi, &context), ClearType::FromCursorUp => clear_before_cursor(pos, csbi, self.context.clone()),
ClearType::CurrentLine => clear_current_line(pos, csbi, &context), ClearType::CurrentLine => clear_current_line(pos, csbi, self.context.clone()),
ClearType::UntilNewLine => clear_until_line(pos, csbi,&context), ClearType::UntilNewLine => clear_until_line(pos, csbi,self.context.clone()),
}; };
} }
fn terminal_size(&self, context: &Context) -> (u16, u16) { fn terminal_size(&self) -> (u16, u16) {
terminal::terminal_size() terminal::terminal_size()
} }
fn scroll_up(&self, count: i16, context: &Context) { fn scroll_up(&self, count: i16) {
// yet to be inplemented // yet to be inplemented
} }
fn scroll_down(&self, count: i16, context: &Context) { fn scroll_down(&self, count: i16) {
let csbi = kernel::get_console_screen_buffer_info(); let csbi = kernel::get_console_screen_buffer_info();
let mut srct_window; let mut srct_window;
@ -60,7 +63,7 @@ impl ITerminal for WinApiTerminal {
} }
/// Set the current terminal size /// Set the current terminal size
fn set_size(&self, width: i16, height: i16, context: &Context) { fn set_size(&self, width: i16, height: i16) {
if width <= 0 if width <= 0
{ {
panic!("Cannot set the terminal width lower than 1"); panic!("Cannot set the terminal width lower than 1");
@ -136,7 +139,7 @@ impl ITerminal for WinApiTerminal {
} }
} }
pub fn clear_after_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Context) { pub fn clear_after_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: Rc<Context>) {
let (mut x,mut y) = pos; let (mut x,mut y) = pos;
// if cursor position is at the outer right position // if cursor position is at the outer right position
@ -154,7 +157,7 @@ pub fn clear_after_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, cont
clear(start_location,cells_to_write); clear(start_location,cells_to_write);
} }
pub fn clear_before_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Context) { pub fn clear_before_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: Rc<Context>) {
let (xpos,ypos) = pos; let (xpos,ypos) = pos;
// one cell after cursor position // one cell after cursor position
@ -170,7 +173,7 @@ pub fn clear_before_cursor(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, con
clear(start_location, cells_to_write); clear(start_location, cells_to_write);
} }
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Context) { pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, context: Rc<Context>) {
// position x at start // position x at start
let x = 0; let x = 0;
// position y at start // position y at start
@ -185,10 +188,10 @@ pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Context)
clear( start_location, cells_to_write); clear( start_location, cells_to_write);
// put the cursor back at (0, 0) // put the cursor back at (0, 0)
cursor(&context).goto(0, 0); cursor(context.clone()).goto(0, 0);
} }
pub fn clear_current_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Context) pub fn clear_current_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: Rc<Context>)
{ {
// position x at start // position x at start
let x = 0; let x = 0;
@ -204,10 +207,10 @@ pub fn clear_current_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, cont
clear(start_location, cells_to_write); clear(start_location, cells_to_write);
// put the cursor back at 1 cell on current row // put the cursor back at 1 cell on current row
cursor(&context).goto(0, y); cursor(context.clone()).goto(0, y);
} }
pub fn clear_until_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: &Context) pub fn clear_until_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, context: Rc<Context>)
{ {
let (x,y) = pos; let (x,y) = pos;
@ -219,7 +222,7 @@ pub fn clear_until_line(pos: (u16,u16), csbi: CONSOLE_SCREEN_BUFFER_INFO, contex
clear(start_location, cells_to_write); clear(start_location, cells_to_write);
// put the cursor back at original cursor position // put the cursor back at original cursor position
cursor(&context).goto(x,y); cursor(context.clone()).goto(x,y);
} }
fn clear( fn clear(