117 lines
2.8 KiB
Rust
117 lines
2.8 KiB
Rust
use libc;
|
|
use self::libc::{STDOUT_FILENO, TIOCGWINSZ, c_ushort, ioctl};
|
|
pub use self::libc::termios as Termios;
|
|
use crossterm_state::commands::{NoncanonicaModeCommand, IContextCommand};
|
|
use std::io;
|
|
use std::mem;
|
|
|
|
|
|
/// A representation of the size of the current terminal
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct UnixSize {
|
|
/// number of rows
|
|
pub rows: c_ushort,
|
|
/// number of columns
|
|
pub cols: c_ushort,
|
|
x: c_ushort,
|
|
y: c_ushort,
|
|
}
|
|
|
|
/// Gets the current terminal size
|
|
pub fn terminal_size() -> (u16,u16) {
|
|
// http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
|
|
let us = UnixSize {
|
|
rows: 0,
|
|
cols: 0,
|
|
x: 0,
|
|
y: 0,
|
|
};
|
|
let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &us) };
|
|
if r == 0 {
|
|
// 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 {
|
|
(0,0)
|
|
}
|
|
}
|
|
|
|
/// Get the current cursor position
|
|
pub fn pos() -> (u16,u16)
|
|
{
|
|
use std::io::Error;
|
|
use std::io::{ Write,Read };
|
|
|
|
let command = NoncanonicalModeCommand::new();
|
|
command.execute();
|
|
|
|
// This code is original written by term_cursor credits to them.
|
|
let mut stdout = io::stdout();
|
|
|
|
// Write command
|
|
stdout.write(b"\x1B[6n")?;
|
|
stdout.flush()?;
|
|
|
|
// Read back result
|
|
let mut buf = [0u8; 2];
|
|
// Expect `ESC[`
|
|
io::stdin().read_exact(&mut buf)?;
|
|
if buf[0] != 0x1B || buf[1] as char != '[' {
|
|
return (0,0);
|
|
}
|
|
|
|
// Read rows and cols through a ad-hoc integer parsing function
|
|
let read_num = || -> Result<(i32, char), Error> {
|
|
let mut num = 0;
|
|
let mut c;
|
|
|
|
loop {
|
|
let mut buf = [0u8; 1];
|
|
io::stdin().read_exact(&mut buf)?;
|
|
c = buf[0] as char;
|
|
if let Some(d) = c.to_digit(10) {
|
|
num = if num == 0 { 0 } else { num * 10 };
|
|
num += d as i32;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok((num, c))
|
|
};
|
|
|
|
// Read rows and expect `;`
|
|
let (rows, c) = read_num()?;
|
|
if c != ';' {
|
|
return (0,0);
|
|
}
|
|
|
|
// Read cols
|
|
let (cols, c) = read_num()?;
|
|
|
|
// Expect `R`
|
|
let res = if c == 'R' { Ok((cols, rows)) } else { return (0,0); };
|
|
|
|
command.undo();
|
|
res
|
|
}
|
|
|
|
pub fn set_terminal_mode(terminal: &Termios) -> io::Result<()>
|
|
{
|
|
extern "C" {
|
|
pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *const Termios) -> c_int;
|
|
}
|
|
cvt(unsafe { tcsetattr(0, 0, termios) }).and(Ok(()))
|
|
}
|
|
|
|
pub fn get_terminal_mode() -> io::Result<Termios>
|
|
{
|
|
extern "C" {
|
|
pub fn tcgetattr(fd: c_int, termptr: *mut Termios) -> c_int;
|
|
}
|
|
unsafe {
|
|
let mut termios = mem::zeroed();
|
|
cvt(tcgetattr(0, &mut termios))?;
|
|
Ok(termios)
|
|
}
|
|
} |