128 lines
3.7 KiB
Rust
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
|
|
}
|
|
|
|
}
|