Use default ANSI for windows, if current windows does not support ANSI switch back to WINAPI. Unix is not tested yet. Notice that currently the console will be set to another mode and that ther is no way back, when ansi is enabled. Storing the old state of the terminal and enable the client to switsh back to the old state will likely be inplemented in crossterm 0.3.0
This commit is contained in:
parent
4212e728d5
commit
215d0cfa83
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,7 @@ pub mod cursor;
|
||||
pub mod terminal;
|
||||
|
||||
fn main() {
|
||||
terminal::clear_all_lines();
|
||||
cursor::print();
|
||||
color::paint_background();
|
||||
color::paint_foreground();
|
||||
color::paint_foreground_and_background();
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ pub fn clear_until_new_line()
|
||||
print_test_data();
|
||||
|
||||
// Set terminal cursor position (see example for more info).
|
||||
crossterm_cursor::cursor().goto(4,7);
|
||||
crossterm_cursor::cursor().goto(4,20);
|
||||
|
||||
// Clear all the cells until next line.
|
||||
terminal.clear(ClearType::UntilNewLine);
|
||||
@ -92,7 +92,7 @@ pub fn print_terminal_size()
|
||||
// Get terminal
|
||||
let mut terminal = terminal();
|
||||
// Get terminal size
|
||||
let terminal_size = terminal.terminal_size().unwrap();
|
||||
let terminal_size = terminal.terminal_size();
|
||||
// Print results
|
||||
print!("X: {}, y: {}", terminal_size.0, terminal_size.1);
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ use std::fmt::Display;
|
||||
use Construct;
|
||||
use super::base_cursor::ITerminalCursor;
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::AnsiCursor;
|
||||
#[cfg(windows)]
|
||||
use super::WinApiCursor;
|
||||
|
||||
/// Struct that stores an specific platform implementation for cursor related actions.
|
||||
@ -19,12 +17,25 @@ pub struct TerminalCursor {
|
||||
impl TerminalCursor {
|
||||
/// Create new cursor instance whereon cursor related actions can be performed.
|
||||
pub fn new() -> TerminalCursor {
|
||||
let cursor: Option<Box<ITerminalCursor>> = {
|
||||
#[cfg(unix)]
|
||||
Some(AnsiCursor::new());
|
||||
let mut cursor: Option<Box<ITerminalCursor>> = None;
|
||||
|
||||
let mut does_support = true;
|
||||
if cfg!(target_os = "windows") {
|
||||
#[cfg(windows)]
|
||||
Some(WinApiCursor::new())
|
||||
};
|
||||
use kernel::windows_kernel::kernel::try_enable_ansi_support;
|
||||
|
||||
does_support = try_enable_ansi_support();
|
||||
// this returns an bool if the current windows console supports ansi.
|
||||
if !does_support
|
||||
{
|
||||
cursor = Some(WinApiCursor::new());
|
||||
}
|
||||
}
|
||||
|
||||
if does_support
|
||||
{
|
||||
cursor = Some(AnsiCursor::new());
|
||||
}
|
||||
|
||||
TerminalCursor { terminal_cursor: cursor }
|
||||
}
|
||||
|
@ -1,14 +1,10 @@
|
||||
mod base_cursor;
|
||||
mod cursor;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod ansi_cursor;
|
||||
#[cfg(windows)]
|
||||
mod winapi_cursor;
|
||||
|
||||
#[cfg(unix)]
|
||||
use self::ansi_cursor::AnsiCursor;
|
||||
#[cfg(windows)]
|
||||
use self::winapi_cursor::WinApiCursor;
|
||||
|
||||
pub use self::cursor::{ cursor, TerminalCursor };
|
||||
|
@ -9,15 +9,15 @@ use super::base_color::ITerminalColor;
|
||||
|
||||
/// This struct is an ansi implementation for color related actions.
|
||||
#[derive(Debug)]
|
||||
pub struct ANSIColor;
|
||||
pub struct AnsiColor;
|
||||
|
||||
impl Construct for ANSIColor {
|
||||
fn new() -> Box<ANSIColor> {
|
||||
Box::from(ANSIColor {})
|
||||
impl Construct for AnsiColor {
|
||||
fn new() -> Box<AnsiColor> {
|
||||
Box::from(AnsiColor {})
|
||||
}
|
||||
}
|
||||
|
||||
impl ITerminalColor for ANSIColor {
|
||||
impl ITerminalColor for AnsiColor {
|
||||
fn set_fg(&self, fg_color: Color) {
|
||||
let mut some_writer = io::stdout();
|
||||
write!(&mut some_writer, csi!("{}m"), self.color_value(fg_color, ColorType::Foreground));
|
||||
@ -47,7 +47,7 @@ impl ITerminalColor for ANSIColor {
|
||||
},
|
||||
}
|
||||
|
||||
let rgb_val;
|
||||
let rgb_val: String;
|
||||
|
||||
let color_val = match color {
|
||||
Color::Black => "5;0",
|
||||
@ -65,7 +65,9 @@ impl ITerminalColor for ANSIColor {
|
||||
Color::DarkCyan => "5;6",
|
||||
Color::Grey => "5;15",
|
||||
Color::White => "5;7",
|
||||
#[cfg(unix)]
|
||||
Color::Rgb{r,g,b} => { rgb_val = format!("2;{};{};{}", r,g,b); rgb_val.as_str()},
|
||||
#[cfg(unix)]
|
||||
Color::AnsiValue(val) => { rgb_val = format!("5;{}",val); rgb_val.as_str() }
|
||||
};
|
||||
|
||||
|
@ -9,9 +9,7 @@ use crossterm_style::{ObjectStyle, StyledObject};
|
||||
use super::base_color::ITerminalColor;
|
||||
use super::super::Color;
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::ANSIColor;
|
||||
#[cfg(windows)]
|
||||
use super::AnsiColor;
|
||||
use super::WinApiColor;
|
||||
|
||||
/// Struct that stores an specific platform implementation for color related actions.
|
||||
@ -22,12 +20,25 @@ pub struct TerminalColor {
|
||||
impl TerminalColor {
|
||||
/// Create new instance whereon color related actions can be performed.
|
||||
pub fn new() -> TerminalColor {
|
||||
let color: Option<Box<ITerminalColor>> = {
|
||||
#[cfg(unix)]
|
||||
Some(ANSIColor::new());
|
||||
let mut color: Option<Box<ITerminalColor>> = None;
|
||||
|
||||
let mut does_support = true;
|
||||
if cfg!(target_os = "windows") {
|
||||
#[cfg(windows)]
|
||||
Some(WinApiColor::new())
|
||||
};
|
||||
use kernel::windows_kernel::kernel::try_enable_ansi_support;
|
||||
|
||||
does_support = try_enable_ansi_support();
|
||||
// this returns an bool if the current windows console supports ansi.
|
||||
if !does_support
|
||||
{
|
||||
color = Some(WinApiColor::new());
|
||||
}
|
||||
}
|
||||
|
||||
if does_support
|
||||
{
|
||||
color = Some(AnsiColor::new());
|
||||
}
|
||||
|
||||
TerminalColor { terminal_color: color }
|
||||
}
|
||||
|
@ -1,12 +1,8 @@
|
||||
pub mod base_color;
|
||||
pub mod color;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod ansi_color;
|
||||
#[cfg(windows)]
|
||||
mod winapi_color;
|
||||
|
||||
#[cfg(unix)]
|
||||
use self::ansi_color::ANSIColor;
|
||||
#[cfg(windows)]
|
||||
use self::ansi_color::AnsiColor;
|
||||
use self::winapi_color::WinApiColor;
|
||||
|
@ -3,21 +3,20 @@ use std::io::Write;
|
||||
|
||||
use Construct;
|
||||
use super::base_terminal::{ClearType, ITerminal};
|
||||
use kernel::linux_kernel::terminal::*;
|
||||
use shared::functions::resize_terminal;
|
||||
|
||||
/// This struct is an ansi implementation for terminal related actions.
|
||||
pub struct UnixTerminal;
|
||||
pub struct AnsiTerminal ;
|
||||
|
||||
impl Construct for UnixTerminal {
|
||||
fn new() -> Box<UnixTerminal> {
|
||||
Box::from(UnixTerminal {})
|
||||
impl Construct for AnsiTerminal {
|
||||
fn new() -> Box<AnsiTerminal> {
|
||||
Box::from(AnsiTerminal {})
|
||||
}
|
||||
}
|
||||
|
||||
impl ITerminal for UnixTerminal {
|
||||
impl ITerminal for AnsiTerminal {
|
||||
fn clear(&self, clear_type: ClearType) {
|
||||
let mut some_writer = io::stdout();
|
||||
|
||||
match clear_type {
|
||||
ClearType::All => {
|
||||
write!(&mut some_writer, csi!("2J"));
|
||||
@ -37,8 +36,8 @@ impl ITerminal for UnixTerminal {
|
||||
};
|
||||
}
|
||||
|
||||
fn terminal_size(&self) -> Option<(u16, u16)> {
|
||||
terminal_size()
|
||||
fn terminal_size(&self) -> (u16, u16) {
|
||||
resize_terminal()
|
||||
}
|
||||
|
||||
fn scroll_up(&self, count: i16) {
|
||||
|
@ -11,7 +11,7 @@ pub trait ITerminal {
|
||||
/// Clear the current cursor by specifying the clear type
|
||||
fn clear(&self, clear_type: ClearType);
|
||||
/// Get the terminal size (x,y)
|
||||
fn terminal_size(&self) -> Option<(u16, u16)>;
|
||||
fn terminal_size(&self) -> (u16, u16);
|
||||
/// Scroll `n` lines up in the current terminal.
|
||||
fn scroll_up(&self, count: i16);
|
||||
/// Scroll `n` lines down in the current terminal.
|
||||
|
@ -1,14 +1,10 @@
|
||||
mod base_terminal;
|
||||
mod terminal;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod ansi_terminal;
|
||||
#[cfg(windows)]
|
||||
mod winapi_terminal;
|
||||
|
||||
#[cfg(unix)]
|
||||
use self::ansi_terminal::UnixTerminal;
|
||||
#[cfg(windows)]
|
||||
use self::ansi_terminal::AnsiTerminal;
|
||||
use self::winapi_terminal::WinApiTerminal;
|
||||
|
||||
pub use self::base_terminal::ClearType;
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! With this module you can perform actions that are terminal related.
|
||||
//! Like clearing and scrolling in the terminal or getting the size of the terminal.
|
||||
|
||||
|
||||
use Construct;
|
||||
use super::base_terminal::{ClearType, ITerminal};
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::UnixTerminal;
|
||||
#[cfg(windows)]
|
||||
use super::AnsiTerminal;
|
||||
use super::WinApiTerminal;
|
||||
|
||||
/// Struct that stores an specific platform implementation for terminal related actions.
|
||||
@ -17,13 +16,25 @@ pub struct Terminal {
|
||||
impl Terminal {
|
||||
/// Create new terminal instance whereon terminal related actions can be performed.
|
||||
pub fn new() -> Terminal {
|
||||
let term: Option<Box<ITerminal>> =
|
||||
let mut term: Option<Box<ITerminal>> = None;
|
||||
|
||||
let mut does_support = true;
|
||||
if cfg!(target_os = "windows") {
|
||||
use kernel::windows_kernel::kernel::try_enable_ansi_support;
|
||||
|
||||
does_support = try_enable_ansi_support();
|
||||
// this returns an bool if the current windows console supports ansi.
|
||||
if !does_support
|
||||
{
|
||||
term = Some(WinApiTerminal::new());
|
||||
}
|
||||
}
|
||||
|
||||
if does_support
|
||||
{
|
||||
#[cfg(unix)]
|
||||
Some(UnixTerminal::new());
|
||||
#[cfg(windows)]
|
||||
Some(WinApiTerminal::new())
|
||||
};
|
||||
println!("This console does support ansi");
|
||||
term = Some(AnsiTerminal::new());
|
||||
}
|
||||
|
||||
Terminal { terminal: term }
|
||||
}
|
||||
@ -72,13 +83,11 @@ impl Terminal {
|
||||
/// println!("{:?}", size);
|
||||
///
|
||||
/// ```
|
||||
pub fn terminal_size(&mut self) -> Option<(u16, u16)> {
|
||||
pub fn terminal_size(&mut self) -> (u16, u16) {
|
||||
if let Some(ref terminal) = self.terminal {
|
||||
let a = terminal.terminal_size();
|
||||
a
|
||||
} else {
|
||||
None
|
||||
return terminal.terminal_size()
|
||||
}
|
||||
(0,0)
|
||||
}
|
||||
|
||||
/// Scroll `n` lines up in the current terminal.
|
||||
|
@ -14,6 +14,7 @@ impl Construct for WinApiTerminal {
|
||||
|
||||
impl ITerminal for WinApiTerminal {
|
||||
fn clear(&self, clear_type: ClearType) {
|
||||
println! ("Windows!!!");
|
||||
match clear_type
|
||||
{
|
||||
ClearType::All => terminal::clear_entire_screen(),
|
||||
@ -24,7 +25,7 @@ impl ITerminal for WinApiTerminal {
|
||||
};
|
||||
}
|
||||
|
||||
fn terminal_size(&self) -> Option<(u16, u16)> {
|
||||
fn terminal_size(&self) -> (u16, u16) {
|
||||
terminal::terminal_size()
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub struct UnixSize {
|
||||
}
|
||||
|
||||
/// Gets the current terminal size
|
||||
pub fn terminal_size() -> Option<(u16,u16)> {
|
||||
pub fn terminal_size() -> (u16,u16) {
|
||||
// http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
|
||||
let us = UnixSize {
|
||||
rows: 0,
|
||||
@ -29,6 +29,6 @@ pub fn terminal_size() -> Option<(u16,u16)> {
|
||||
// because crossterm works starts counting at 0 and unix terminal starts at cell 1 you have subtract one to get 0-based results.
|
||||
Some((us.cols -1, us.rows -1))
|
||||
} else {
|
||||
None
|
||||
(0,0)
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
///! Notice that this feature is not used. But will be implemented later.
|
||||
|
||||
use super::kernel;
|
||||
|
||||
/// Enables ansi for windows terminals.
|
||||
pub fn enable_ansi_support() {
|
||||
let enable_ansi_code: u32 = 7;
|
||||
kernel::set_console_mode(enable_ansi_code);
|
||||
}
|
@ -7,6 +7,7 @@ static mut SAVED_CURSOR_POS:(i16,i16) = (0,0);
|
||||
pub fn set(x: i16, y: i16)
|
||||
{
|
||||
kernel::set_console_cursor_position(x, y );
|
||||
|
||||
}
|
||||
|
||||
/// Reset to saved cursor position
|
||||
|
@ -1,17 +1,19 @@
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use winapi::um::winbase::STD_OUTPUT_HANDLE;
|
||||
use winapi::um::winbase::{STD_OUTPUT_HANDLE, STD_INPUT_HANDLE };
|
||||
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
||||
use winapi::um::processenv::{GetStdHandle};
|
||||
use winapi::um::consoleapi::{SetConsoleMode};
|
||||
use winapi::um::consoleapi::{SetConsoleMode,GetConsoleMode};
|
||||
use winapi::um::wincon::{ SetConsoleWindowInfo, SetConsoleCursorPosition, SetConsoleTextAttribute, SetConsoleScreenBufferSize,
|
||||
GetLargestConsoleWindowSize, GetConsoleScreenBufferInfo,
|
||||
FillConsoleOutputCharacterA, FillConsoleOutputAttribute,
|
||||
CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT, COORD
|
||||
FillConsoleOutputCharacterA, FillConsoleOutputAttribute, ENABLE_VIRTUAL_TERMINAL_PROCESSING,ENABLE_VIRTUAL_TERMINAL_INPUT,
|
||||
CONSOLE_SCREEN_BUFFER_INFO, SMALL_RECT, COORD, DISABLE_NEWLINE_AUTO_RETURN
|
||||
};
|
||||
|
||||
use super::{Empty};
|
||||
|
||||
static mut CONSOLE_OUTPUT_HANDLE: Option<HANDLE> = None;
|
||||
static mut CONSOLE_INPUT_HANDLE: Option<HANDLE> = None;
|
||||
|
||||
/// Get the std_output_handle of the console
|
||||
pub fn get_output_handle() -> HANDLE {
|
||||
@ -20,18 +22,43 @@ pub fn get_output_handle() -> HANDLE {
|
||||
handle
|
||||
} else {
|
||||
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if !is_valid_handle(&handle)
|
||||
{
|
||||
panic!("Cannot get output handle")
|
||||
}
|
||||
|
||||
CONSOLE_OUTPUT_HANDLE = Some(handle);
|
||||
handle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the std_input_handle of the console
|
||||
pub fn get_input_handle() -> HANDLE {
|
||||
unsafe {
|
||||
if let Some(handle) = CONSOLE_INPUT_HANDLE {
|
||||
handle
|
||||
} else {
|
||||
let handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
if !is_valid_handle(&handle)
|
||||
{
|
||||
panic!("Cannot get input handle")
|
||||
}
|
||||
|
||||
CONSOLE_INPUT_HANDLE = Some(handle);
|
||||
handle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the console handle is an invalid handle value.
|
||||
pub fn is_valid_handle(handle: &HANDLE) -> bool {
|
||||
if *handle == INVALID_HANDLE_VALUE {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +77,26 @@ pub fn get_console_screen_buffer_info() -> CONSOLE_SCREEN_BUFFER_INFO {
|
||||
csbi
|
||||
}
|
||||
|
||||
/// Enables ansi for windows terminals.
|
||||
pub fn try_enable_ansi_support() -> bool {
|
||||
|
||||
let output_handle = get_output_handle();
|
||||
|
||||
let mut dw_mode: DWORD = 0;
|
||||
if !get_console_mode(&output_handle, &mut dw_mode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dw_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if !set_console_mode(&output_handle, dw_mode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn get_largest_console_window_size() -> COORD
|
||||
{
|
||||
let output_handle = get_output_handle();
|
||||
@ -64,12 +111,19 @@ pub fn get_original_console_color() -> u16 {
|
||||
console_buffer_info.wAttributes as u16
|
||||
}
|
||||
|
||||
pub fn set_console_mode(console_mode: u32)
|
||||
pub fn set_console_mode(handle: &HANDLE, console_mode: u32) -> bool
|
||||
{
|
||||
let output_handle = get_output_handle();
|
||||
|
||||
unsafe {
|
||||
SetConsoleMode(output_handle, console_mode);
|
||||
let success = SetConsoleMode(*handle, console_mode);
|
||||
return is_true(success);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_console_mode(handle: &HANDLE, current_mode: &mut u32) -> bool
|
||||
{
|
||||
unsafe {
|
||||
let success = GetConsoleMode(*handle, &mut *current_mode);
|
||||
return is_true(success);
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,9 +224,9 @@ pub fn fill_console_output_attribute(cells_written: &mut u32, start_location: CO
|
||||
fn is_true(value: i32) -> bool
|
||||
{
|
||||
if value == 0{
|
||||
false
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
pub mod cursor;
|
||||
pub mod color;
|
||||
pub mod ansi_support;
|
||||
pub mod kernel;
|
||||
pub mod terminal;
|
||||
mod winapi_extentions;
|
||||
|
@ -2,13 +2,13 @@ use super::{cursor, kernel};
|
||||
use winapi::um::wincon::{SMALL_RECT, COORD};
|
||||
|
||||
/// Get the terminal size (y,x)
|
||||
pub fn terminal_size() -> Option<(u16, u16)> {
|
||||
pub fn terminal_size() -> (u16, u16) {
|
||||
let csbi = kernel::get_console_screen_buffer_info();
|
||||
|
||||
Some((
|
||||
(
|
||||
(csbi.srWindow.Right - csbi.srWindow.Left) as u16,
|
||||
(csbi.srWindow.Bottom - csbi.srWindow.Top) as u16,
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/// Scroll down `n` rows
|
||||
|
9
src/shared/functions.rs
Normal file
9
src/shared/functions.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#[cfg(unix)]
|
||||
use kernel::linux_kernel::terminal::terminal_size;
|
||||
#[cfg(windows)]
|
||||
use kernel::windows_kernel::terminal::terminal_size;
|
||||
|
||||
pub fn resize_terminal() -> (u16,u16)
|
||||
{
|
||||
terminal_size()
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
pub mod traits;
|
||||
pub mod functions;
|
||||
|
Loading…
Reference in New Issue
Block a user