minicrossterm/crossterm_terminal/src/terminal/ansi_terminal.rs

128 lines
3.7 KiB
Rust

//! This is an `ANSI escape code` specific implementation for terminal related action.
//! This module is used for windows 10 terminals and unix terminals by default.
use crossterm_cursor::TerminalCursor;
use crossterm_utils::{csi, write_cout, Result};
use crate::sys::get_terminal_size;
use super::{ClearType, ITerminal};
pub static CLEAR_ALL: &'static str = csi!("2J");
pub static CLEAR_FROM_CURSOR_DOWN: &'static str = csi!("J");
pub static CLEAR_FROM_CURSOR_UP: &'static str = csi!("1J");
pub static CLEAR_FROM_CURRENT_LINE: &'static str = csi!("2K");
pub static CLEAR_UNTIL_NEW_LINE: &'static str = csi!("K");
pub fn get_scroll_up_ansi(count: u16) -> String {
format!(csi!("{}S"), count)
}
pub fn get_scroll_down_ansi(count: u16) -> String {
format!(csi!("{}T"), count)
}
pub fn get_set_size_ansi(width: u16, height: u16) -> String {
format!(csi!("8;{};{}t"), height, width)
}
/// This struct is an ansi escape code implementation for terminal related actions.
pub struct AnsiTerminal;
impl AnsiTerminal {
pub fn new() -> AnsiTerminal {
AnsiTerminal
}
}
impl ITerminal for AnsiTerminal {
fn clear(&self, clear_type: ClearType) -> Result<()> {
match clear_type {
ClearType::All => {
write_cout!(CLEAR_ALL)?;
TerminalCursor::new().goto(0, 0)?;
}
ClearType::FromCursorDown => {
write_cout!(CLEAR_FROM_CURSOR_DOWN)?;
}
ClearType::FromCursorUp => {
write_cout!(CLEAR_FROM_CURSOR_UP)?;
}
ClearType::CurrentLine => {
write_cout!(CLEAR_FROM_CURRENT_LINE)?;
}
ClearType::UntilNewLine => {
write_cout!(CLEAR_UNTIL_NEW_LINE)?;
}
};
Ok(())
}
fn size(&self) -> Result<(u16, u16)> {
get_terminal_size()
}
fn scroll_up(&self, count: u16) -> Result<()> {
write_cout!(get_scroll_up_ansi(count))?;
Ok(())
}
fn scroll_down(&self, count: u16) -> Result<()> {
write_cout!(get_scroll_down_ansi(count))?;
Ok(())
}
fn set_size(&self, width: u16, height: u16) -> Result<()> {
write_cout!(get_set_size_ansi(width, height))?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::{thread, time};
use super::{AnsiTerminal, ITerminal};
/* ======================== ANSI =========================== */
#[test]
// TODO - Test is disabled, because it's failing on Travis CI
#[ignore]
fn test_resize_ansi() {
if try_enable_ansi() {
let terminal = AnsiTerminal::new();
let (width, height) = terminal.size().unwrap();
terminal.set_size(35, 35).unwrap();
// see issue: https://github.com/eminence/terminal-size/issues/11
thread::sleep(time::Duration::from_millis(30));
assert_eq!((35, 35), terminal.size().unwrap());
// reset to previous size
terminal.set_size(width, height).unwrap();
// see issue: https://github.com/eminence/terminal-size/issues/11
thread::sleep(time::Duration::from_millis(30));
assert_eq!((width, height), terminal.size().unwrap());
}
}
fn try_enable_ansi() -> bool {
#[cfg(windows)]
{
if cfg!(target_os = "windows") {
use crossterm_utils::sys::winapi::ansi::set_virtual_terminal_processing;
// if it is not listed we should try with WinApi to check if we do support ANSI-codes.
match set_virtual_terminal_processing(true) {
Ok(_) => return true,
Err(_) => return false,
}
}
}
true
}
}