Error handling (#69)

* Implemented an error module for crossterm and fixed a lot of warnings.
This commit is contained in:
Timon 2019-01-01 13:27:50 -08:00 committed by GitHub
parent ff9b5d9a39
commit ad3efbd34d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 342 additions and 264 deletions

View File

@ -18,7 +18,7 @@ pub fn paint_foreground() {
// Or print inline // Or print inline
println!( println!(
"Colored text: {}", "Colored text: {}",
style("Red foreground").with(Color::Blue) style("Blue foreground").with(Color::Blue)
); );
} }

View File

@ -15,14 +15,11 @@ mod input;
mod terminal; mod terminal;
fn main() { fn main() {
use input::keyboard::input; let cursor = crossterm::cursor();
cursor.goto(5,5);
// color::print_all_foreground_colors(); let integer = 10;
// color::print_all_background_colors(); let float: f32 = integert as f32;
use terminal::alternate_screen; println!("5.515151");
// color::print_all_background_colors();
// color::print_all_foreground_colors();
alternate_screen::print_wait_screen_on_alternate_window();
} }

View File

@ -78,7 +78,7 @@ impl RawModeCommand {
pub fn enable(&mut self) -> Result<()> { pub fn enable(&mut self) -> Result<()> {
let console_mode = ConsoleMode::new()?; let console_mode = ConsoleMode::new()?;
let mut dw_mode = console_mode.mode()?; let dw_mode = console_mode.mode()?;
let new_mode = dw_mode & !self.mask; let new_mode = dw_mode & !self.mask;
@ -91,7 +91,7 @@ impl RawModeCommand {
pub fn disable(&self) -> Result<()> { pub fn disable(&self) -> Result<()> {
let console_mode = ConsoleMode::new()?; let console_mode = ConsoleMode::new()?;
let mut dw_mode = console_mode.mode()?; let dw_mode = console_mode.mode()?;
let new_mode = dw_mode | self.mask; let new_mode = dw_mode | self.mask;
@ -114,7 +114,7 @@ impl ToAlternateScreenCommand {
impl IAlternateScreenCommand for ToAlternateScreenCommand { impl IAlternateScreenCommand for ToAlternateScreenCommand {
fn enable(&self, _stdout: &mut TerminalOutput) -> Result<()> { fn enable(&self, _stdout: &mut TerminalOutput) -> Result<()> {
let alternate_screen = ScreenBuffer::create(); let alternate_screen = ScreenBuffer::create();
alternate_screen.show(); alternate_screen.show()?;
Ok(()) Ok(())
} }

51
src/common/error.rs Normal file
View File

@ -0,0 +1,51 @@
//! Module containing error handling logic.
use std::{
fmt::{self, Display, Formatter},
io,
};
/// The `crossterm` result type.
pub type Result<T> = std::result::Result<T, ErrorKind>;
/// Wrapper for all errors who could occur in `crossterm`.
#[derive(Debug)]
pub enum ErrorKind {
IoError(io::Error),
FmtError(fmt::Error),
ResizingTerminalFailure(String),
#[doc(hidden)]
__Nonexhaustive,
}
impl std::error::Error for ErrorKind {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
ErrorKind::IoError(ref e) => Some(e),
_ => None,
}
}
}
impl Display for ErrorKind {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
ErrorKind::IoError(_) => write!(fmt, "IO-error occurred"),
ErrorKind::ResizingTerminalFailure(_) => write!(fmt, "Cannot resize the terminal"),
_ => write!(fmt, "Some error has occurred"),
}
}
}
impl From<io::Error> for ErrorKind {
fn from(e: io::Error) -> ErrorKind {
ErrorKind::IoError(e)
}
}
impl From<fmt::Error> for ErrorKind {
fn from(e: fmt::Error) -> ErrorKind {
ErrorKind::FmtError(e)
}
}

View File

@ -64,18 +64,18 @@ pub fn exit_terminal() {
/// If the current platform is unix it will return the ansi implementation. /// If the current platform is unix it will return the ansi implementation.
pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> 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 does_support = false; let mut does_support = false;
// if !windows_supportable() { if !windows_supportable() {
// 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(); does_support = try_enable_ansi_support();
//
// uncomment this line when you want to use the winapi implementation. // uncomment this line when you want to use the winapi implementation.
// does_support = false; // does_support = false;
if !does_support { if !does_support {
term = Some(winapi_impl); term = Some(winapi_impl);
}
} }
// }
if does_support { if does_support {
term = Some(unix_impl); term = Some(unix_impl);

View File

@ -6,8 +6,9 @@ pub mod commands;
pub mod functions; pub mod functions;
pub mod screen; pub mod screen;
pub mod traits; pub mod traits;
pub mod error;
mod crossterm; mod crossterm;
pub use self::crossterm::Crossterm; pub use self::crossterm::Crossterm;
use TerminalOutput; use TerminalOutput;

View File

@ -44,8 +44,7 @@ impl AlternateScreen {
functions::get_module::<Box<commands::IAlternateScreenCommand + Sync + Send>>( functions::get_module::<Box<commands::IAlternateScreenCommand + Sync + Send>>(
Box::from(commands::win_commands::ToAlternateScreenCommand::new()), Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
Box::from(commands::shared_commands::ToAlternateScreenCommand::new()), Box::from(commands::shared_commands::ToAlternateScreenCommand::new()),
) ).unwrap();
.unwrap();
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let command = Box::from(commands::shared_commands::ToAlternateScreenCommand::new()); let command = Box::from(commands::shared_commands::ToAlternateScreenCommand::new());
@ -72,6 +71,6 @@ impl AlternateScreen {
impl Drop for AlternateScreen { impl Drop for AlternateScreen {
/// This will switch back to main screen on drop. /// This will switch back to main screen on drop.
fn drop(&mut self) { fn drop(&mut self) {
self.to_main_screen(); self.to_main_screen().unwrap();
} }
} }

View File

@ -165,7 +165,7 @@ impl Drop for Screen {
/// If the current screen is in raw mode we need to disable it when the instance goes out of scope. /// If the current screen is in raw mode we need to disable it when the instance goes out of scope.
fn drop(&mut self) { fn drop(&mut self) {
if self.stdout.is_in_raw_mode && self.drop { if self.stdout.is_in_raw_mode && self.drop {
RawScreen::disable_raw_modes(); RawScreen::disable_raw_modes().unwrap();
} }
} }
} }

View File

@ -5,10 +5,11 @@ use std::sync::{Once, ONCE_INIT};
static mut HAS_BEEN_TRIED_TO_ENABLE: bool = false; static mut HAS_BEEN_TRIED_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 ENABLE_ANSI: Once = ONCE_INIT;
use common::commands::win_commands::EnableAnsiCommand; use common::commands::win_commands::EnableAnsiCommand;
use common::commands::IEnableAnsiCommand; use common::commands::IEnableAnsiCommand;
static ENABLE_ANSI: 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() -> bool { pub fn try_enable_ansi_support() -> bool {
ENABLE_ANSI.call_once(|| { ENABLE_ANSI.call_once(|| {

View File

@ -1,15 +1,11 @@
//! This module contains the `windows` (unsafe) logic. //! This module contains the `windows` (unsafe) logic.
#[allow(unused)]
mod reading;
pub mod ansi_support; pub mod ansi_support;
mod cursor; mod cursor;
pub mod reading;
pub mod writing; pub mod writing;
use winapi::um::{
wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT},
winnt::HANDLE,
};
pub use self::cursor::Cursor; pub use self::cursor::Cursor;
pub use crossterm_winapi::{ pub use crossterm_winapi::{
Console, ConsoleMode, Coord, Handle, HandleType, ScreenBuffer, ScreenBufferInfo, Size, Console, ConsoleMode, Coord, Handle, HandleType, ScreenBuffer, ScreenBufferInfo, Size,
@ -19,4 +15,4 @@ pub use crossterm_winapi::{
/// Exit the current process. /// Exit the current process.
pub fn exit() { pub fn exit() {
::std::process::exit(256); ::std::process::exit(256);
} }

View File

@ -1,4 +1,4 @@
use crossterm_winapi::{Handle, HandleType}; use crossterm_winapi::Handle;
use std::{ use std::{
io::{self, Write}, io::{self, Write},
@ -50,7 +50,7 @@ pub fn read_line(buf: &mut Vec<u8>) -> io::Result<usize> {
.filter(|&x| x != 10 || x != 13) .filter(|&x| x != 10 || x != 13)
.collect::<Vec<u8>>(); .collect::<Vec<u8>>();
buf.write(a); buf.write(a)?;
Ok(num as usize) Ok(num as usize)
} }

View File

@ -12,6 +12,7 @@ use std::io::{self, Result};
use std::str; use std::str;
/// Write console output. /// Write console output.
#[allow(unused)]
pub fn write_console_output( pub fn write_console_output(
write_buffer: &HANDLE, write_buffer: &HANDLE,
copy_buffer: &mut [CHAR_INFO; 160], copy_buffer: &mut [CHAR_INFO; 160],

View File

@ -3,6 +3,7 @@
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position etc. //! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position etc.
use super::*; use super::*;
use common::error::Result;
/// 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 {}
@ -14,51 +15,61 @@ impl AnsiCursor {
} }
impl ITerminalCursor for AnsiCursor { impl ITerminalCursor for AnsiCursor {
fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc<TerminalOutput>>) { fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(stdout, format!(csi!("{};{}H"), y + 1, x + 1)); functions::write(stdout, format!(csi!("{};{}H"), y + 1, x + 1))?;
Ok(())
} }
fn pos(&self) -> (u16, u16) { fn pos(&self) -> (u16, u16) {
functions::get_cursor_position() functions::get_cursor_position()
} }
fn move_up(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) { fn move_up(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(stdout, format!(csi!("{}A"), count)); functions::write(stdout, format!(csi!("{}A"), count))?;
Ok(())
} }
fn move_right(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) { fn move_right(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(stdout, format!(csi!("{}C"), count)); functions::write(stdout, format!(csi!("{}C"), count))?;
Ok(())
} }
fn move_down(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) { fn move_down(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(stdout, format!(csi!("{}B"), count)); functions::write(stdout, format!(csi!("{}B"), count))?;
Ok(())
} }
fn move_left(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) { fn move_left(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(stdout, format!(csi!("{}D"), count)); functions::write(stdout, format!(csi!("{}D"), count))?;
Ok(())
} }
fn save_position(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn save_position(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write_str(stdout, csi!("s")); functions::write_str(stdout, csi!("s"))?;
Ok(())
} }
fn reset_position(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn reset_position(&self, stdout: &Option<&Arc<TerminalOutput>>)-> Result<()> {
functions::write_str(stdout, csi!("u")); functions::write_str(stdout, csi!("u"))?;
Ok(())
} }
fn hide(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn hide(&self, stdout: &Option<&Arc<TerminalOutput>>)-> Result<()> {
functions::write_str(stdout, csi!("?25l")); functions::write_str(stdout, csi!("?25l"))?;
Ok(())
} }
fn show(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn show(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>{
functions::write_str(stdout, csi!("?25h")); functions::write_str(stdout, csi!("?25h"))?;
Ok(())
} }
fn blink(&self, blink: bool, stdout: &Option<&Arc<TerminalOutput>>) { fn blink(&self, blink: bool, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>{
if blink { if blink {
functions::write_str(stdout, csi!("?12h")); functions::write_str(stdout, csi!("?12h"))?;
} else { } else {
functions::write_str(stdout, csi!("?12l")); functions::write_str(stdout, csi!("?12l"))?;
} }
Ok(())
} }
} }

View File

@ -4,6 +4,7 @@
//! Note that positions of the cursor are 0 -based witch means that the coordinates (cells) 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 common::error::Result;
use Screen; use Screen;
/// Struct that stores a platform-specific implementation for cursor related actions. /// Struct that stores a platform-specific implementation for cursor related actions.
@ -94,8 +95,8 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.goto(4,5); /// cursor.goto(4,5);
/// ///
/// ``` /// ```
pub fn goto(&self, x: u16, y: u16) { pub fn goto(&self, x: u16, y: u16) -> Result<()> {
self.terminal_cursor.goto(x, y, &self.stdout); self.terminal_cursor.goto(x, y, &self.stdout)
} }
/// Get current cursor position (x,y) in the terminal. /// Get current cursor position (x,y) in the terminal.
@ -119,7 +120,7 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.move_up(3); /// cursor.move_up(3);
/// ``` /// ```
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor<'stdout> {
self.terminal_cursor.move_up(count, &self.stdout); self.terminal_cursor.move_up(count, &self.stdout).unwrap();
self self
} }
@ -132,7 +133,7 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.move_right(3); /// cursor.move_right(3);
/// ``` /// ```
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor<'stdout> {
self.terminal_cursor.move_right(count, &self.stdout); self.terminal_cursor.move_right(count, &self.stdout).unwrap();
self self
} }
@ -145,7 +146,7 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.move_down(3); /// cursor.move_down(3);
/// ``` /// ```
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor<'stdout> {
self.terminal_cursor.move_down(count, &self.stdout); self.terminal_cursor.move_down(count, &self.stdout).unwrap();
self self
} }
@ -158,7 +159,7 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.move_left(3); /// cursor.move_left(3);
/// ``` /// ```
pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'stdout> { pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor<'stdout> {
self.terminal_cursor.move_left(count, &self.stdout); self.terminal_cursor.move_left(count, &self.stdout).unwrap();
self self
} }
@ -171,8 +172,8 @@ impl<'stdout> TerminalCursor<'stdout> {
/// ///
/// cursor.safe_position(); /// cursor.safe_position();
/// ``` /// ```
pub fn save_position(&self) { pub fn save_position(&self) -> Result<()> {
self.terminal_cursor.save_position(&self.stdout); self.terminal_cursor.save_position(&self.stdout)
} }
/// Return to saved cursor position /// Return to saved cursor position
@ -184,8 +185,8 @@ impl<'stdout> TerminalCursor<'stdout> {
/// ///
/// cursor.reset_position(); /// cursor.reset_position();
/// ``` /// ```
pub fn reset_position(&self) { pub fn reset_position(&self) -> Result<()> {
self.terminal_cursor.reset_position(&self.stdout); self.terminal_cursor.reset_position(&self.stdout)
} }
/// Hide de cursor in the console. /// Hide de cursor in the console.
@ -194,8 +195,8 @@ impl<'stdout> TerminalCursor<'stdout> {
/// let cursor = cursor(); /// let cursor = cursor();
/// cursor.hide(); /// cursor.hide();
/// ``` /// ```
pub fn hide(&self) { pub fn hide(&self) -> Result<()> {
self.terminal_cursor.hide(&self.stdout); self.terminal_cursor.hide(&self.stdout)
} }
/// Show the cursor in the console. /// Show the cursor in the console.
@ -206,8 +207,8 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.show(); /// cursor.show();
/// ///
/// ``` /// ```
pub fn show(&self) { pub fn show(&self) -> Result<()> {
self.terminal_cursor.show(&self.stdout); self.terminal_cursor.show(&self.stdout)
} }
/// Enable or disable blinking of the terminal. /// Enable or disable blinking of the terminal.
@ -219,8 +220,8 @@ impl<'stdout> TerminalCursor<'stdout> {
/// cursor.blink(true); /// cursor.blink(true);
/// cursor.blink(false); /// cursor.blink(false);
/// ``` /// ```
pub fn blink(&self, blink: bool) { pub fn blink(&self, blink: bool) -> Result<()> {
self.terminal_cursor.blink(blink, &self.stdout); self.terminal_cursor.blink(blink, &self.stdout)
} }
} }

View File

@ -17,7 +17,7 @@ use self::ansi_cursor::AnsiCursor;
use self::winapi_cursor::WinApiCursor; use self::winapi_cursor::WinApiCursor;
pub use self::cursor::{cursor, from_screen, TerminalCursor}; pub use self::cursor::{cursor, from_screen, TerminalCursor};
use common::error::Result;
use super::functions; use super::functions;
use std::sync::Arc; use std::sync::Arc;
use TerminalOutput; use TerminalOutput;
@ -32,25 +32,25 @@ use TerminalOutput;
///! so that cursor related actions can be performed on both UNIX and Windows systems. ///! so that cursor related actions can be performed on both UNIX and Windows systems.
trait ITerminalCursor: Sync + Send { trait ITerminalCursor: Sync + Send {
/// Goto some location (x,y) in the context. /// Goto some location (x,y) in the context.
fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc<TerminalOutput>>); fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Get the location (x,y) of the current cursor in the context /// Get the location (x,y) of the current cursor in the context
fn pos(&self) -> (u16, u16); fn pos(&self) -> (u16, u16);
/// Move cursor n times up /// Move cursor n times up
fn move_up(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>); fn move_up(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Move the cursor `n` times to the right. /// Move the cursor `n` times to the right.
fn move_right(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>); fn move_right(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Move the cursor `n` times down. /// Move the cursor `n` times down.
fn move_down(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>); fn move_down(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Move the cursor `n` times left. /// Move the cursor `n` times left.
fn move_left(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>); fn move_left(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct. /// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct.
fn save_position(&self, stdout: &Option<&Arc<TerminalOutput>>); fn save_position(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Return to saved cursor position /// Return to saved cursor position
fn reset_position(&self, stdout: &Option<&Arc<TerminalOutput>>); fn reset_position(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Hide the terminal cursor. /// Hide the terminal cursor.
fn hide(&self, stdout: &Option<&Arc<TerminalOutput>>); fn hide(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Show the terminal cursor /// Show the terminal cursor
fn show(&self, stdout: &Option<&Arc<TerminalOutput>>); fn show(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Enable or disable the blinking of the cursor. /// Enable or disable the blinking of the cursor.
fn blink(&self, blink: bool, stdout: &Option<&Arc<TerminalOutput>>); fn blink(&self, blink: bool, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
} }

View File

@ -2,8 +2,8 @@
//! 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. //! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position.
use kernel::windows_kernel::Cursor; use kernel::windows_kernel::{Cursor, Handle};
use common::error::Result;
use super::*; use super::*;
/// This struct is a windows implementation for cursor related actions. /// This struct is a windows implementation for cursor related actions.
@ -16,9 +16,10 @@ impl WinApiCursor {
} }
impl ITerminalCursor for WinApiCursor { impl ITerminalCursor for WinApiCursor {
fn goto(&self, x: u16, y: u16, _stdout: &Option<&Arc<TerminalOutput>>) { fn goto(&self, x: u16, y: u16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let cursor = Cursor::new().unwrap(); let cursor = Cursor::new()?;
cursor.goto(x as i16, y as i16); cursor.goto(x as i16, y as i16)?;
Ok(())
} }
fn pos(&self) -> (u16, u16) { fn pos(&self) -> (u16, u16) {
@ -26,41 +27,49 @@ impl ITerminalCursor for WinApiCursor {
cursor.position().unwrap().into() cursor.position().unwrap().into()
} }
fn move_up(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) { fn move_up(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let (xpos, ypos) = self.pos(); let (xpos, ypos) = self.pos();
self.goto(xpos, ypos - count, _stdout); self.goto(xpos, ypos - count, _stdout)?;
Ok(())
} }
fn move_right(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) { fn move_right(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let (xpos, ypos) = self.pos(); let (xpos, ypos) = self.pos();
self.goto(xpos + count, ypos, _stdout); self.goto(xpos + count, ypos, _stdout)?;
Ok(())
} }
fn move_down(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) { fn move_down(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let (xpos, ypos) = self.pos(); let (xpos, ypos) = self.pos();
self.goto(xpos, ypos + count, _stdout); self.goto(xpos, ypos + count, _stdout)?;
Ok(())
} }
fn move_left(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) { fn move_left(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let (xpos, ypos) = self.pos(); let (xpos, ypos) = self.pos();
self.goto(xpos - count, ypos, _stdout); self.goto(xpos - count, ypos, _stdout)?;
Ok(())
} }
fn save_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) { fn save_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
Cursor::save_cursor_pos(); Cursor::save_cursor_pos()?;
Ok(())
} }
fn reset_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) { fn reset_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
Cursor::reset_to_saved_position(); Cursor::reset_to_saved_position()?;
Ok(())
} }
fn hide(&self, _stdout: &Option<&Arc<TerminalOutput>>) { fn hide(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
Cursor::new().unwrap().set_visibility(false); Cursor::from(Handle::current_out_handle()?).set_visibility(false)?;
Ok(())
} }
fn show(&self, _stdout: &Option<&Arc<TerminalOutput>>) { fn show(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
Cursor::new().unwrap().set_visibility(true); Cursor::from(Handle::current_out_handle()?).set_visibility(true)?;
Ok(())
} }
fn blink(&self, _blink: bool, _stdout: &Option<&Arc<TerminalOutput>>) {} fn blink(&self, _blink: bool, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> { Ok(()) }
} }

View File

@ -73,7 +73,9 @@ impl ITerminalInput for WindowsInput {
return; return;
} }
tx.send(Ok(pressed_char as u8)); if let Err(_) = tx.send(Ok(pressed_char as u8)) {
println!("Could not send pressed char to receiver.")
}
} }
}); });
@ -110,7 +112,9 @@ impl ITerminalInput for WindowsInput {
return; return;
} }
tx.send(Ok(pressed_char as u8)); if let Err(_) = tx.send(Ok(pressed_char as u8)) {
println!("Could not send pressed char to receiver.")
}
} }
}); });
@ -118,14 +122,6 @@ impl ITerminalInput for WindowsInput {
} }
} }
fn is_line_end(key: char) -> bool {
if key as u8 == 13 {
return true;
}
return false;
}
extern "C" { extern "C" {
fn _getwche() -> INT; fn _getwche() -> INT;
fn _getwch() -> INT; fn _getwch() -> INT;

View File

@ -18,7 +18,7 @@ impl IStdout for WinApiOutput {
} }
fn write(&self, buf: &[u8]) -> io::Result<usize> { fn write(&self, buf: &[u8]) -> io::Result<usize> {
let handle = Handle::current_out_handle().unwrap(); let handle = Handle::current_out_handle()?;
writing::write_char_buffer(&handle, buf) writing::write_char_buffer(&handle, buf)
} }

View File

@ -2,6 +2,7 @@
//! 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 super::*; use super::*;
use common::error::Result;
/// This struct is an ANSI escape code implementation for color related actions. /// This struct is an ANSI escape code implementation for color related actions.
pub struct AnsiColor; pub struct AnsiColor;
@ -13,28 +14,31 @@ impl AnsiColor {
} }
impl ITerminalColor for AnsiColor { impl ITerminalColor for AnsiColor {
fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) { fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write( functions::write(
stdout, stdout,
format!( format!(
csi!("{}m"), csi!("{}m"),
self.color_value(fg_color, ColorType::Foreground) self.color_value(fg_color, ColorType::Foreground)
), ),
); )?;
Ok(())
} }
fn set_bg(&self, bg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) { fn set_bg(&self, bg_color: Color, stdout: &Option<&Arc<TerminalOutput>>)-> Result<()> {
functions::write( functions::write(
stdout, stdout,
format!( format!(
csi!("{}m"), csi!("{}m"),
self.color_value(bg_color, ColorType::Background) self.color_value(bg_color, ColorType::Background)
), ),
); )?;
Ok(())
} }
fn reset(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn reset(&self, stdout: &Option<&Arc<TerminalOutput>>)-> Result<()>{
functions::write_str(stdout, csi!("0m")); functions::write_str(stdout, csi!("0m"))?;
Ok(())
} }
fn color_value(&self, color: Color, color_type: ColorType) -> String { fn color_value(&self, color: Color, color_type: ColorType) -> String {
@ -77,4 +81,4 @@ impl ITerminalColor for AnsiColor {
ansi_value.push_str(color_val); ansi_value.push_str(color_val);
ansi_value ansi_value
} }
} }

View File

@ -94,8 +94,8 @@ impl<'stdout> TerminalColor<'stdout> {
/// // crossterm provides to set the background from &str or String /// // crossterm provides to set the background from &str or String
/// colored_terminal.set_fg(Color::from("Red")); /// colored_terminal.set_fg(Color::from("Red"));
/// ``` /// ```
pub fn set_fg(&self, color: Color) { pub fn set_fg(&self, color: Color)-> Result<()> {
self.color.set_fg(color, &self.stdout); self.color.set_fg(color, &self.stdout)
} }
/// Set the background color to the given color. /// Set the background color to the given color.
@ -108,8 +108,8 @@ impl<'stdout> TerminalColor<'stdout> {
/// // crossterm provides to set the background from &str or String /// // crossterm provides to set the background from &str or String
/// colored_terminal.set_bg(Color::from("Red")); /// colored_terminal.set_bg(Color::from("Red"));
/// ``` /// ```
pub fn set_bg(&self, color: Color) { pub fn set_bg(&self, color: Color) -> Result<()>{
self.color.set_bg(color, &self.stdout); self.color.set_bg(color, &self.stdout)
} }
/// Reset the terminal colors and attributes to default. /// Reset the terminal colors and attributes to default.
@ -118,8 +118,8 @@ impl<'stdout> TerminalColor<'stdout> {
/// let colored_terminal = color(); /// let colored_terminal = color();
/// colored_terminal.reset(); /// colored_terminal.reset();
/// ``` /// ```
pub fn reset(&self) { pub fn reset(&self)-> Result<()> {
self.color.reset(&self.stdout); self.color.reset(&self.stdout)
} }
/// Get available color count. /// Get available color count.

View File

@ -22,7 +22,7 @@ pub use self::color::{color, from_screen, TerminalColor};
pub use self::objectstyle::ObjectStyle; pub use self::objectstyle::ObjectStyle;
pub use self::styledobject::DisplayableObject; pub use self::styledobject::DisplayableObject;
pub use self::styledobject::StyledObject; pub use self::styledobject::StyledObject;
use super::functions; use common::{functions, error::Result};
use TerminalOutput; use TerminalOutput;
@ -36,11 +36,11 @@ use TerminalOutput;
/// so that color-related actions can be performed on both UNIX and Windows systems. /// so that color-related actions can be performed on both UNIX and Windows systems.
trait ITerminalColor { trait ITerminalColor {
/// Set the foreground color to the given color. /// Set the foreground color to the given color.
fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>); fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Set the background color to the given color. /// Set the background color to the given color.
fn set_bg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>); fn set_bg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Reset the terminal color to default. /// Reset the terminal color to default.
fn reset(&self, stdout: &Option<&Arc<TerminalOutput>>); fn reset(&self, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>;
/// Gets an value that represents an color from the given `Color` and `ColorType`. /// Gets an value that represents an color from the given `Color` and `ColorType`.
fn color_value(&self, color: Color, color_type: ColorType) -> String; fn color_value(&self, color: Color, color_type: ColorType) -> String;
} }
@ -153,7 +153,7 @@ impl FromStr for Color {
type Err = (); type Err = ();
/// Convert a string to an Color value /// Convert a string to an Color value
fn from_str(src: &str) -> Result<Self, Self::Err> { fn from_str(src: &str) -> ::std::result::Result<Self, Self::Err> {
let src = src.to_lowercase(); let src = src.to_lowercase();
match src.as_ref() { match src.as_ref() {

View File

@ -5,6 +5,8 @@ use Screen;
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::io::Write; use std::io::Write;
use common::error::Result;
use std::result;
use super::Attribute; use super::Attribute;
@ -146,36 +148,37 @@ impl<'a, D: Display + 'a> StyledObject<D> {
/// ///
/// You should take not that `StyledObject` implements `Display`. You don't need to call paint unless you are on alternate screen. /// You should take not that `StyledObject` implements `Display`. You don't need to call paint unless you are on alternate screen.
/// Checkout `into_displayable()` for more information about this. /// Checkout `into_displayable()` for more information about this.
pub fn paint(&self, screen: &Screen) { pub fn paint(&self, screen: &Screen) -> Result<()> {
let colored_terminal = from_screen(&screen); let colored_terminal = from_screen(&screen);
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 {
colored_terminal.set_bg(bg); colored_terminal.set_bg(bg)?;
reset = true; reset = true;
} }
if let Some(fg) = self.object_style.fg_color { if let Some(fg) = self.object_style.fg_color {
colored_terminal.set_fg(fg); colored_terminal.set_fg(fg)?;
reset = true; reset = true;
} }
for attr in self.object_style.attrs.iter() { for attr in self.object_style.attrs.iter() {
screen screen
.stdout .stdout
.write_string(format!(csi!("{}m"), *attr as i16)); .write_string(format!(csi!("{}m"), *attr as i16))?;
reset = true; reset = true;
} }
use std::fmt::Write; use std::fmt::Write;
let mut content = String::new(); let mut content = String::new();
write!(content, "{}", self.content).unwrap(); write!(content, "{}", self.content)?;
screen.stdout.write_string(content); screen.stdout.write_string(content)?;
screen.stdout.flush(); screen.stdout.flush()?;
if reset { if reset {
colored_terminal.reset(); colored_terminal.reset()?;
} }
Ok(())
} }
/// This converts an styled object into an `DisplayableObject` witch implements: `Display` and could be used inside the write function of the standard library. /// This converts an styled object into an `DisplayableObject` witch implements: `Display` and could be used inside the write function of the standard library.
@ -198,30 +201,30 @@ impl<'a, D: Display + 'a> StyledObject<D> {
} }
impl<D: Display> Display for StyledObject<D> { impl<D: Display> Display for StyledObject<D> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut Formatter) -> result::Result<(), fmt::Error> {
let colored_terminal = color(); let colored_terminal = color();
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 {
colored_terminal.set_bg(bg); colored_terminal.set_bg(bg).unwrap();
reset = true; reset = true;
} }
if let Some(fg) = self.object_style.fg_color { if let Some(fg) = self.object_style.fg_color {
colored_terminal.set_fg(fg); colored_terminal.set_fg(fg).unwrap();
reset = true; reset = true;
} }
for attr in self.object_style.attrs.iter() { for attr in self.object_style.attrs.iter() {
write!(f, "{}", format!(csi!("{}m"), *attr as i16)); write!(f, "{}", format!(csi!("{}m"), *attr as i16))?;
reset = true; reset = true;
} }
fmt::Display::fmt(&self.content, f)?; fmt::Display::fmt(&self.content, f)?;
std::io::stdout().flush().expect("Flush stdout failed"); std::io::stdout().flush().unwrap();
if reset { if reset {
colored_terminal.reset(); colored_terminal.reset().unwrap();
std::io::stdout().flush().expect("Flush stdout failed"); std::io::stdout().flush().unwrap();
} }
Ok(()) Ok(())
} }
@ -248,8 +251,8 @@ impl<'a, D: Display + 'a> DisplayableObject<'a, D> {
} }
impl<'a, D: Display + 'a> Display for DisplayableObject<'a, D> { impl<'a, D: Display + 'a> Display for DisplayableObject<'a, D> {
fn fmt(&self, _f: &mut Formatter) -> Result<(), fmt::Error> { fn fmt(&self, _f: &mut Formatter) -> result::Result<(), fmt::Error> {
self.styled_object.paint(&self.screen); self.styled_object.paint(&self.screen).unwrap();
Ok(()) Ok(())
} }
} }

View File

@ -6,6 +6,7 @@ use kernel::windows_kernel::{Console, Handle, HandleType, ScreenBuffer};
use std::io; use std::io;
use std::sync::{Once, ONCE_INIT}; use std::sync::{Once, ONCE_INIT};
use winapi::um::wincon; use winapi::um::wincon;
use common::error::Result;
/// This struct is a WinApi implementation for color related actions. /// This struct is a WinApi implementation for color related actions.
pub struct WinApiColor; pub struct WinApiColor;
@ -17,14 +18,14 @@ impl WinApiColor {
} }
impl ITerminalColor for WinApiColor { impl ITerminalColor for WinApiColor {
fn set_fg(&self, fg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) { fn set_fg(&self, fg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>{
// init the original color in case it is not set. // init the original color in case it is not set.
let _ = init_console_color().unwrap(); let _ = init_console_color()?;
let color_value = &self.color_value(fg_color, ColorType::Foreground); let color_value = &self.color_value(fg_color, ColorType::Foreground);
let screen_buffer = ScreenBuffer::current().unwrap(); let screen_buffer = ScreenBuffer::current()?;
let csbi = screen_buffer.info().unwrap(); let csbi = screen_buffer.info()?;
// Notice that the color values are stored in wAttribute. // Notice that the color values are stored in wAttribute.
// So we need to use bitwise operators to check if the values exists or to get current console colors. // So we need to use bitwise operators to check if the values exists or to get current console colors.
@ -40,18 +41,19 @@ impl ITerminalColor for WinApiColor {
} }
Console::from(**screen_buffer.get_handle()) Console::from(**screen_buffer.get_handle())
.set_text_attribute(color) .set_text_attribute(color)?;
.unwrap();
Ok(())
} }
fn set_bg(&self, bg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) { fn set_bg(&self, bg_color: Color, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
// init the original color in case it is not set. // init the original color in case it is not set.
let _ = init_console_color().unwrap(); let _ = init_console_color()?;
let color_value = &self.color_value(bg_color, ColorType::Background); let color_value = &self.color_value(bg_color, ColorType::Background);
let screen_buffer = ScreenBuffer::current().unwrap(); let screen_buffer = ScreenBuffer::current()?;
let csbi = screen_buffer.info().unwrap(); let csbi = screen_buffer.info()?;
// Notice that the color values are stored in wAttribute. // Notice that the color values are stored in wAttribute.
// So wee need to use bitwise operators to check if the values exists or to get current console colors. // So wee need to use bitwise operators to check if the values exists or to get current console colors.
@ -67,16 +69,18 @@ impl ITerminalColor for WinApiColor {
} }
Console::from(**screen_buffer.get_handle()) Console::from(**screen_buffer.get_handle())
.set_text_attribute(color) .set_text_attribute(color)?;
.unwrap();
Ok(())
} }
fn reset(&self, _stdout: &Option<&Arc<TerminalOutput>>) { fn reset(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
// init the original color in case it is not set. // init the original color in case it is not set.
let original_color = original_console_color(); let original_color = original_console_color();
Console::from(Handle::new(HandleType::CurrentOutputHandle).unwrap()) Console::from(Handle::new(HandleType::CurrentOutputHandle)?)
.set_text_attribute(original_color) .set_text_attribute(original_color)?;
.unwrap();
Ok(())
} }
/// This will get the winapi color value from the Color and ColorType struct /// This will get the winapi color value from the Color and ColorType struct

View File

@ -2,6 +2,7 @@
//! 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 super::*; use super::*;
use common::error::Result;
/// This struct is an ansi escape code implementation for terminal related actions. /// This struct is an ansi escape code implementation for terminal related actions.
pub struct AnsiTerminal; pub struct AnsiTerminal;
@ -14,41 +15,45 @@ impl AnsiTerminal {
} }
impl ITerminal for AnsiTerminal { impl ITerminal for AnsiTerminal {
fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc<TerminalOutput>>) { fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
match clear_type { match clear_type {
ClearType::All => { ClearType::All => {
functions::write_str(&stdout, csi!("2J")); functions::write_str(&stdout, csi!("2J"))?;
TerminalCursor::new().goto(0, 0); TerminalCursor::new().goto(0, 0)?;
} }
ClearType::FromCursorDown => { ClearType::FromCursorDown => {
functions::write_str(&stdout, csi!("J")); functions::write_str(&stdout, csi!("J"))?;
} }
ClearType::FromCursorUp => { ClearType::FromCursorUp => {
functions::write_str(&stdout, csi!("1J")); functions::write_str(&stdout, csi!("1J"))?;
} }
ClearType::CurrentLine => { ClearType::CurrentLine => {
functions::write_str(&stdout, csi!("2K")); functions::write_str(&stdout, csi!("2K"))?;
} }
ClearType::UntilNewLine => { ClearType::UntilNewLine => {
functions::write_str(&stdout, csi!("K")); functions::write_str(&stdout, csi!("K"))?;
} }
}; };
Ok(())
} }
fn terminal_size(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16) { fn terminal_size(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16) {
functions::get_terminal_size() functions::get_terminal_size()
} }
fn scroll_up(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) { fn scroll_up(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>{
functions::write(&stdout, format!(csi!("{}S"), count)); functions::write(&stdout, format!(csi!("{}S"), count))?;
Ok(())
} }
fn scroll_down(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) { fn scroll_down(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(&stdout, format!(csi!("{}T"), count)); functions::write(&stdout, format!(csi!("{}T"), count))?;
Ok(())
} }
fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc<TerminalOutput>>) { fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
functions::write(&stdout, format!(csi!("8;{};{}t"), height, width)); functions::write(&stdout, format!(csi!("8;{};{}t"), height, width))?;
Ok(())
} }
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) {

View File

@ -15,7 +15,7 @@ use self::winapi_terminal::WinApiTerminal;
pub use self::terminal::{from_screen, terminal, Terminal}; pub use self::terminal::{from_screen, terminal, Terminal};
use super::functions; use common::{functions, error};
use std::sync::Arc; use std::sync::Arc;
use {Screen, TerminalOutput}; use {Screen, TerminalOutput};
@ -38,15 +38,15 @@ pub enum ClearType {
/// so that terminal related actions can be preformed on both Unix and Windows systems. /// so that terminal related actions can be preformed on both Unix and Windows systems.
trait ITerminal { 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, stdout: &Option<&Arc<TerminalOutput>>); fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc<TerminalOutput>>) -> error::Result<()>;
/// Get the terminal size (x,y) /// Get the terminal size (x,y)
fn terminal_size(&self, stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16); fn terminal_size(&self, stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16);
/// Scroll `n` lines up in the current terminal. /// Scroll `n` lines up in the current terminal.
fn scroll_up(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>); fn scroll_up(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) -> error::Result<()>;
/// Scroll `n` lines down in the current terminal. /// Scroll `n` lines down in the current terminal.
fn scroll_down(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>); fn scroll_down(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) -> error::Result<()>;
/// Resize terminal to the given width and height. /// Resize terminal to the given width and height.
fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc<TerminalOutput>>); fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc<TerminalOutput>>) -> error::Result<()>;
/// Close the current terminal /// Close the current terminal
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>); fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>);
} }

View File

@ -2,7 +2,7 @@
//! Like clearing and scrolling in the terminal or getting the window size from the terminal. //! Like clearing and scrolling in the terminal or getting the window size from the terminal.
use super::*; use super::*;
use common::error::Result;
use std::fmt; use std::fmt;
/// Struct that stores a platform-specific platform implementation for terminal related actions. /// Struct that stores a platform-specific platform implementation for terminal related actions.
@ -93,8 +93,8 @@ impl<'stdout> Terminal<'stdout> {
/// // clear all cells from cursor position until new line in terminal. /// // clear all cells from cursor position until new line in terminal.
/// term.clear(terminal::ClearType::UntilNewLine); /// term.clear(terminal::ClearType::UntilNewLine);
/// ``` /// ```
pub fn clear(&self, clear_type: ClearType) { pub fn clear(&self, clear_type: ClearType) -> Result<()> {
self.terminal.clear(clear_type, &self.screen); self.terminal.clear(clear_type, &self.screen)
} }
/// Get the terminal size (x,y). /// Get the terminal size (x,y).
@ -117,8 +117,8 @@ impl<'stdout> Terminal<'stdout> {
/// // scroll up by 5 lines /// // scroll up by 5 lines
/// let size = term.scroll_up(5); /// let size = term.scroll_up(5);
/// ``` /// ```
pub fn scroll_up(&self, count: i16) { pub fn scroll_up(&self, count: i16) -> Result<()> {
self.terminal.scroll_up(count, &self.screen); self.terminal.scroll_up(count, &self.screen)
} }
/// Scroll `n` lines up in the current terminal. /// Scroll `n` lines up in the current terminal.
@ -129,8 +129,8 @@ impl<'stdout> Terminal<'stdout> {
/// // scroll down by 5 lines /// // scroll down by 5 lines
/// let size = term.scroll_down(5); /// let size = term.scroll_down(5);
/// ``` /// ```
pub fn scroll_down(&self, count: i16) { pub fn scroll_down(&self, count: i16) -> Result<()> {
self.terminal.scroll_down(count, &self.screen); self.terminal.scroll_down(count, &self.screen)
} }
/// Set the terminal size. Note that not all terminals can be set to a very small scale. /// Set the terminal size. Note that not all terminals can be set to a very small scale.
@ -141,8 +141,8 @@ impl<'stdout> Terminal<'stdout> {
/// // 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);
/// ``` /// ```
pub fn set_size(&self, width: i16, height: i16) { pub fn set_size(&self, width: i16, height: i16) -> Result<()> {
self.terminal.set_size(width, height, &self.screen); self.terminal.set_size(width, height, &self.screen)
} }
/// Exit the current process. /// Exit the current process.
@ -163,11 +163,12 @@ impl<'stdout> Terminal<'stdout> {
/// ///
/// let size = term.write("Some text \n Some text on new line"); /// let size = term.write("Some text \n Some text on new line");
/// ``` /// ```
pub fn write<D: fmt::Display>(&self, value: D) { pub fn write<D: fmt::Display>(&self, value: D) -> Result<usize> {
use std::fmt::Write; use std::fmt::Write;
let mut string = String::new(); let mut string = String::new();
write!(string, "{}", value).unwrap(); write!(string, "{}", value)?;
functions::write(&self.screen, string); let size = functions::write(&self.screen, string)?;
Ok(size)
} }
} }

View File

@ -4,7 +4,7 @@
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead. //! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
use super::*; use super::*;
use common::error::{Result, ErrorKind};
use kernel::windows_kernel::{Console, Coord, Cursor, Handle, ScreenBuffer, Size}; use kernel::windows_kernel::{Console, Coord, Cursor, Handle, ScreenBuffer, Size};
/// This struct is an winapi implementation for terminal related actions. /// This struct is an winapi implementation for terminal related actions.
@ -17,9 +17,9 @@ impl WinApiTerminal {
} }
impl ITerminal for WinApiTerminal { impl ITerminal for WinApiTerminal {
fn clear(&self, clear_type: ClearType, _stdout: &Option<&Arc<TerminalOutput>>) { fn clear(&self, clear_type: ClearType, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let screen_buffer = ScreenBuffer::current().unwrap(); let screen_buffer = ScreenBuffer::current()?;
let csbi = screen_buffer.info().unwrap(); let csbi = screen_buffer.info()?;
let pos = csbi.cursor_pos(); let pos = csbi.cursor_pos();
let buffer_size = csbi.buffer_size(); let buffer_size = csbi.buffer_size();
@ -27,13 +27,14 @@ impl ITerminal for WinApiTerminal {
match clear_type { match clear_type {
ClearType::All => { ClearType::All => {
clear_entire_screen(buffer_size, current_attribute); clear_entire_screen(buffer_size, current_attribute)?;
} }
ClearType::FromCursorDown => clear_after_cursor(pos, buffer_size, current_attribute), ClearType::FromCursorDown => clear_after_cursor(pos, buffer_size, current_attribute)?,
ClearType::FromCursorUp => clear_before_cursor(pos, buffer_size, current_attribute), ClearType::FromCursorUp => clear_before_cursor(pos, buffer_size, current_attribute)?,
ClearType::CurrentLine => clear_current_line(pos, buffer_size, current_attribute), ClearType::CurrentLine => clear_current_line(pos, buffer_size, current_attribute)?,
ClearType::UntilNewLine => clear_until_line(pos, buffer_size, current_attribute), ClearType::UntilNewLine => clear_until_line(pos, buffer_size, current_attribute)?,
}; };
Ok(())
} }
fn terminal_size(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16) { fn terminal_size(&self, _stdout: &Option<&Arc<TerminalOutput>>) -> (u16, u16) {
@ -41,53 +42,51 @@ impl ITerminal for WinApiTerminal {
csbi.info().unwrap().terminal_size().into() csbi.info().unwrap().terminal_size().into()
} }
fn scroll_up(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) { fn scroll_up(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
let csbi = ScreenBuffer::current().unwrap(); let csbi = ScreenBuffer::current()?;
let mut window = csbi.info().unwrap().terminal_window(); let mut window = csbi.info()?.terminal_window();
// Check whether the window is too close to the screen buffer top // Check whether the window is too close to the screen buffer top
if window.top >= count { if window.top >= count {
window.top -= count; // move top down window.top -= count; // move top down
window.bottom = count; // move bottom down window.bottom = count; // move bottom down
Console::new() Console::new()?.set_console_info(false, window)?;
.unwrap()
.set_console_info(false, window)
.unwrap();
} }
Ok(())
} }
fn scroll_down(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) { fn scroll_down(&self, count: i16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()>{
let csbi = ScreenBuffer::current().unwrap(); let screen_buffer = ScreenBuffer::current()?;
let mut window = csbi.info().unwrap().terminal_window(); let csbi = screen_buffer.info()?;
let buffer_size = csbi.info().unwrap().buffer_size(); let mut window = csbi.terminal_window();
let buffer_size =csbi.buffer_size();
// Check whether the window is too close to the screen buffer top // Check whether the window is too close to the screen buffer top
if window.bottom < buffer_size.height - count { if window.bottom < buffer_size.height - count {
window.top += count; // move top down window.top += count; // move top down
window.bottom += count; // move bottom down window.bottom += count; // move bottom down
Console::new() Console::new()?
.unwrap() .set_console_info(false, window)?;
.set_console_info(false, window)
.unwrap();
} }
Ok(())
} }
/// Set the current terminal size /// Set the current terminal size
fn set_size(&self, width: i16, height: i16, _stdout: &Option<&Arc<TerminalOutput>>) { fn set_size(&self, width: i16, height: i16, _stdout: &Option<&Arc<TerminalOutput>>) -> Result<()> {
if width <= 0 { if width <= 0 {
panic!("Cannot set the terminal width lower than 1"); return Err(ErrorKind::ResizingTerminalFailure(String::from("Cannot set the terminal width lower than 1")));
} }
if height <= 0 { if height <= 0 {
panic!("Cannot set the terminal height lower then 1") return Err(ErrorKind::ResizingTerminalFailure(String::from("Cannot set the terminal height lower then 1")));
} }
// Get the position of the current console window // Get the position of the current console window
let screen_buffer = ScreenBuffer::current().unwrap(); let screen_buffer = ScreenBuffer::current()?;
let console = Console::from(**screen_buffer.get_handle()); let console = Console::from(**screen_buffer.get_handle());
let csbi = screen_buffer.info().unwrap(); let csbi = screen_buffer.info()?;
let current_size = csbi.buffer_size(); let current_size = csbi.buffer_size();
let window = csbi.terminal_window(); let window = csbi.terminal_window();
@ -100,7 +99,7 @@ impl ITerminal for WinApiTerminal {
if current_size.width < window.left + width { if current_size.width < window.left + width {
if window.left >= i16::max_value() - width { if window.left >= i16::max_value() - width {
panic!("Argument out of range when setting terminal width."); return Err(ErrorKind::ResizingTerminalFailure(String::from("Argument out of range when setting terminal width.")));
} }
new_size.width = window.left + width; new_size.width = window.left + width;
@ -108,7 +107,7 @@ impl ITerminal for WinApiTerminal {
} }
if current_size.height < window.top + height { if current_size.height < window.top + height {
if window.top >= i16::max_value() - height { if window.top >= i16::max_value() - height {
panic!("Argument out of range when setting terminal height"); return Err(ErrorKind::ResizingTerminalFailure(String::from("Argument out of range when setting terminal height.")));
} }
new_size.height = window.top + height; new_size.height = window.top + height;
@ -117,7 +116,7 @@ impl ITerminal for WinApiTerminal {
if resize_buffer { if resize_buffer {
if let Err(_) = screen_buffer.set_size(new_size.width, new_size.height) { if let Err(_) = screen_buffer.set_size(new_size.width, new_size.height) {
panic!("Something went wrong when setting screen buffer size."); return Err(ErrorKind::ResizingTerminalFailure(String::from("Something went wrong when setting screen buffer size.")));
} }
} }
@ -125,29 +124,25 @@ impl ITerminal for WinApiTerminal {
// Preserve the position, but change the size. // Preserve the position, but change the size.
window.bottom = window.top + height; window.bottom = window.top + height;
window.right = window.left + width; window.right = window.left + width;
console.set_console_info(true, window).unwrap(); console.set_console_info(true, window)?;
// If we resized the buffer, un-resize it. // If we resized the buffer, un-resize it.
if resize_buffer { if resize_buffer {
if let Err(_) = screen_buffer.set_size(current_size.width, current_size.height) { if let Err(_) = screen_buffer.set_size(current_size.width, current_size.height) {
panic!("Something went wrong when setting screen buffer size."); return Err(ErrorKind::ResizingTerminalFailure(String::from("Something went wrong when setting screen buffer size.")));
} }
} }
let bounds = console.largest_window_size(); let bounds = console.largest_window_size();
if width > bounds.x { if width > bounds.x {
panic!( return Err(ErrorKind::ResizingTerminalFailure(format!("Argument width: {} out of range when setting terminal width.", width)));
"Argument width: {} out of range when setting terminal width.",
width
);
} }
if height > bounds.y { if height > bounds.y {
panic!( return Err(ErrorKind::ResizingTerminalFailure(format!("Argument height: {} out of range when setting terminal height", width)));
"Argument height: {} out of range when setting terminal height",
height
);
} }
Ok(())
} }
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) { fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) {
@ -160,7 +155,7 @@ impl ITerminal for WinApiTerminal {
} }
} }
pub fn clear_after_cursor(location: Coord, buffer_size: Size, current_attribute: u16) { pub fn clear_after_cursor(location: Coord, buffer_size: Size, current_attribute: u16) -> Result<()> {
let (mut x, mut y) = (location.x, location.y); let (mut x, mut y) = (location.x, location.y);
// if cursor position is at the outer right position // if cursor position is at the outer right position
@ -175,10 +170,10 @@ pub fn clear_after_cursor(location: Coord, buffer_size: Size, current_attribute:
// get sum cells before cursor // get sum cells before cursor
let cells_to_write = buffer_size.width as u32 * buffer_size.height as u32; let cells_to_write = buffer_size.width as u32 * buffer_size.height as u32;
clear(start_location, cells_to_write, current_attribute); clear(start_location, cells_to_write, current_attribute)
} }
pub fn clear_before_cursor(location: Coord, buffer_size: Size, current_attribute: u16) { pub fn clear_before_cursor(location: Coord, buffer_size: Size, current_attribute: u16) -> Result<()> {
let (xpos, ypos) = (location.x, location.y); let (xpos, ypos) = (location.x, location.y);
// one cell after cursor position // one cell after cursor position
@ -193,10 +188,10 @@ pub fn clear_before_cursor(location: Coord, buffer_size: Size, current_attribute
let cells_to_write = (buffer_size.width as u32 * ypos as u32) + (xpos as u32 + 1); let cells_to_write = (buffer_size.width as u32 * ypos as u32) + (xpos as u32 + 1);
// clear everything before cursor position // clear everything before cursor position
clear(start_location, cells_to_write, current_attribute); clear(start_location, cells_to_write, current_attribute)
} }
pub fn clear_entire_screen(buffer_size: Size, current_attribute: u16) { pub fn clear_entire_screen(buffer_size: Size, current_attribute: u16) -> Result<()> {
// get sum cells before cursor // get sum cells before cursor
let cells_to_write = buffer_size.width as u32 * buffer_size.height as u32; let cells_to_write = buffer_size.width as u32 * buffer_size.height as u32;
@ -204,14 +199,15 @@ pub fn clear_entire_screen(buffer_size: Size, current_attribute: u16) {
let start_location = Coord::new(0, 0); let start_location = Coord::new(0, 0);
// clear the entire screen // clear the entire screen
clear(start_location, cells_to_write, current_attribute); clear(start_location, cells_to_write, current_attribute)?;
// put the cursor back at cell 0,0 // put the cursor back at cell 0,0
let cursor = Cursor::new().unwrap(); let cursor = Cursor::new()?;
cursor.goto(0, 0); cursor.goto(0, 0)?;
Ok(())
} }
pub fn clear_current_line(location: Coord, buffer_size: Size, current_attribute: u16) { pub fn clear_current_line(location: Coord, buffer_size: Size, current_attribute: u16) -> Result<()> {
// location where to start clearing // location where to start clearing
let start_location = Coord::new(0, location.y); let start_location = Coord::new(0, location.y);
@ -219,14 +215,15 @@ pub fn clear_current_line(location: Coord, buffer_size: Size, current_attribute:
let cells_to_write = buffer_size.width as u32; let cells_to_write = buffer_size.width as u32;
// clear the whole current line // clear the whole current line
clear(start_location, cells_to_write, current_attribute); clear(start_location, cells_to_write, current_attribute)?;
// put the cursor back at cell 1 on current row // put the cursor back at cell 1 on current row
let cursor = Cursor::new().unwrap(); let cursor = Cursor::new()?;
cursor.goto(0, location.y); cursor.goto(0, location.y)?;
Ok(())
} }
pub fn clear_until_line(location: Coord, buffer_size: Size, current_attribute: u16) { pub fn clear_until_line(location: Coord, buffer_size: Size, current_attribute: u16) -> Result<()> {
let (x, y) = (location.x, location.y); let (x, y) = (location.x, location.y);
// location where to start clearing // location where to start clearing
@ -236,19 +233,20 @@ pub fn clear_until_line(location: Coord, buffer_size: Size, current_attribute: u
let cells_to_write = (buffer_size.width - x as i16) as u32; let cells_to_write = (buffer_size.width - x as i16) as u32;
// clear until the current line // clear until the current line
clear(start_location, cells_to_write, current_attribute); clear(start_location, cells_to_write, current_attribute)?;
// put the cursor back at original cursor position before we did the clearing // put the cursor back at original cursor position before we did the clearing
let cursor = Cursor::new().unwrap(); let cursor = Cursor::new()?;
cursor.goto(x, y); cursor.goto(x, y)?;
Ok(())
} }
fn clear(start_location: Coord, cells_to_write: u32, current_attribute: u16) { fn clear(start_location: Coord, cells_to_write: u32, current_attribute: u16) -> Result<()> {
let console = Console::from(Handle::current_out_handle().unwrap()); let console = Console::from(Handle::current_out_handle()?);
let _ = console let _ = console
.fill_whit_character(start_location, cells_to_write, ' ') .fill_whit_character(start_location, cells_to_write, ' ')?;
.unwrap();
console console
.fill_whit_attribute(start_location, cells_to_write, current_attribute) .fill_whit_attribute(start_location, cells_to_write, current_attribute)?;
.unwrap();
Ok(())
} }