Merge pull request #119 from redox-os/redox_termios
Move system specific features into sys module
This commit is contained in:
commit
792274a641
|
@ -2,7 +2,7 @@ use std::io::{self, Read};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use tty;
|
use sys::tty::get_tty;
|
||||||
|
|
||||||
/// Construct an asynchronous handle to the TTY standard input.
|
/// Construct an asynchronous handle to the TTY standard input.
|
||||||
///
|
///
|
||||||
|
@ -17,7 +17,7 @@ use tty;
|
||||||
pub fn async_stdin() -> AsyncReader {
|
pub fn async_stdin() -> AsyncReader {
|
||||||
let (send, recv) = mpsc::channel();
|
let (send, recv) = mpsc::channel();
|
||||||
|
|
||||||
thread::spawn(move || for i in tty::get_tty().unwrap().bytes() {
|
thread::spawn(move || for i in get_tty().unwrap().bytes() {
|
||||||
if send.send(i).is_err() {
|
if send.send(i).is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ use raw::CONTROL_SEQUENCE_TIMEOUT;
|
||||||
derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
|
derive_csi_sequence!("Hide the cursor.", Hide, "?25l");
|
||||||
derive_csi_sequence!("Show the cursor.", Show, "?25h");
|
derive_csi_sequence!("Show the cursor.", Show, "?25h");
|
||||||
|
|
||||||
|
derive_csi_sequence!("Restore the cursor.", Restore, "u");
|
||||||
|
derive_csi_sequence!("Save the cursor.", Save, "s");
|
||||||
|
|
||||||
/// Goto some position ((1,1)-based).
|
/// Goto some position ((1,1)-based).
|
||||||
///
|
///
|
||||||
/// # Why one-based?
|
/// # Why one-based?
|
||||||
|
|
46
src/lib.rs
46
src/lib.rs
|
@ -11,27 +11,20 @@
|
||||||
//! For more information refer to the [README](https://github.com/ticki/termion).
|
//! For more information refer to the [README](https://github.com/ticki/termion).
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
mod termios;
|
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "redox")]
|
||||||
extern crate redox_termios;
|
#[path="sys/redox/mod.rs"]
|
||||||
|
mod sys;
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(unix)]
|
||||||
extern crate syscall;
|
#[path="sys/unix/mod.rs"]
|
||||||
|
mod sys;
|
||||||
|
|
||||||
|
pub use sys::size::terminal_size;
|
||||||
|
pub use sys::tty::{is_tty, get_tty};
|
||||||
|
|
||||||
mod async;
|
mod async;
|
||||||
pub use async::{AsyncReader, async_stdin};
|
pub use async::{AsyncReader, async_stdin};
|
||||||
|
|
||||||
mod size;
|
|
||||||
pub use size::terminal_size;
|
|
||||||
|
|
||||||
mod tty;
|
|
||||||
pub use tty::{is_tty, get_tty};
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
pub mod clear;
|
pub mod clear;
|
||||||
|
@ -43,3 +36,26 @@ pub mod raw;
|
||||||
pub mod screen;
|
pub mod screen;
|
||||||
pub mod scroll;
|
pub mod scroll;
|
||||||
pub mod style;
|
pub mod style;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::sys;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_terminal_attr() {
|
||||||
|
sys::attr::get_terminal_attr().unwrap();
|
||||||
|
sys::attr::get_terminal_attr().unwrap();
|
||||||
|
sys::attr::get_terminal_attr().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_terminal_attr() {
|
||||||
|
let ios = sys::attr::get_terminal_attr().unwrap();
|
||||||
|
sys::attr::set_terminal_attr(&ios).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_size() {
|
||||||
|
sys::size::terminal_size().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
61
src/raw.rs
61
src/raw.rs
|
@ -25,6 +25,9 @@
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
|
use sys::Termios;
|
||||||
|
use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr};
|
||||||
|
|
||||||
/// The timeout of an escape code control sequence, in milliseconds.
|
/// The timeout of an escape code control sequence, in milliseconds.
|
||||||
pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
|
pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
|
||||||
|
|
||||||
|
@ -32,34 +35,14 @@ pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
|
||||||
/// dropped.
|
/// dropped.
|
||||||
///
|
///
|
||||||
/// Restoring will entirely bring back the old TTY state.
|
/// Restoring will entirely bring back the old TTY state.
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
pub struct RawTerminal<W: Write> {
|
|
||||||
output: W,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
impl<W: Write> Drop for RawTerminal<W> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = write!(self, csi!("?82l"));
|
|
||||||
let _ = self.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
use termios::Termios;
|
|
||||||
/// A terminal restorer, which keeps the previous state of the terminal, and restores it, when
|
|
||||||
/// dropped.
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
pub struct RawTerminal<W: Write> {
|
pub struct RawTerminal<W: Write> {
|
||||||
prev_ios: Termios,
|
prev_ios: Termios,
|
||||||
output: W,
|
output: W,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
impl<W: Write> Drop for RawTerminal<W> {
|
impl<W: Write> Drop for RawTerminal<W> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
use termios::set_terminal_attr;
|
set_terminal_attr(&self.prev_ios).unwrap();
|
||||||
set_terminal_attr(&mut self.prev_ios as *mut _);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,36 +86,18 @@ pub trait IntoRawMode: Write + Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Write> IntoRawMode for W {
|
impl<W: Write> IntoRawMode for W {
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
fn into_raw_mode(self) -> io::Result<RawTerminal<W>> {
|
fn into_raw_mode(self) -> io::Result<RawTerminal<W>> {
|
||||||
use termios::{cfmakeraw, get_terminal_attr, set_terminal_attr};
|
let mut ios = get_terminal_attr()?;
|
||||||
|
|
||||||
let (mut ios, exit) = get_terminal_attr();
|
|
||||||
let prev_ios = ios;
|
let prev_ios = ios;
|
||||||
if exit != 0 {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "Unable to get Termios attribute."));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
raw_terminal_attr(&mut ios);
|
||||||
cfmakeraw(&mut ios);
|
|
||||||
}
|
|
||||||
|
|
||||||
if set_terminal_attr(&mut ios as *mut _) != 0 {
|
set_terminal_attr(&ios)?;
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "Unable to set Termios attribute."))
|
|
||||||
} else {
|
|
||||||
let res = RawTerminal {
|
|
||||||
prev_ios: prev_ios,
|
|
||||||
output: self,
|
|
||||||
};
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
Ok(RawTerminal {
|
||||||
fn into_raw_mode(mut self) -> io::Result<RawTerminal<W>> {
|
prev_ios: prev_ios,
|
||||||
write!(self, csi!("?82h"))?;
|
output: self,
|
||||||
self.flush()?;
|
})
|
||||||
Ok(RawTerminal { output: self })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +110,8 @@ mod test {
|
||||||
fn test_into_raw_mode() {
|
fn test_into_raw_mode() {
|
||||||
let mut out = stdout().into_raw_mode().unwrap();
|
let mut out = stdout().into_raw_mode().unwrap();
|
||||||
|
|
||||||
out.write_all(b"this is a test, muahhahahah").unwrap();
|
out.write_all(b"this is a test, muahhahahah\r\n").unwrap();
|
||||||
|
|
||||||
|
drop(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
85
src/size.rs
85
src/size.rs
|
@ -1,85 +0,0 @@
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
use libc::c_ushort;
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
#[repr(C)]
|
|
||||||
struct TermSize {
|
|
||||||
row: c_ushort,
|
|
||||||
col: c_ushort,
|
|
||||||
_x: c_ushort,
|
|
||||||
_y: c_ushort,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since attributes on non-item statements is not stable yet, we use a function.
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
#[cfg(target_pointer_width = "64")]
|
|
||||||
#[cfg(not(target_env = "musl"))]
|
|
||||||
fn tiocgwinsz() -> u64 {
|
|
||||||
use termios::TIOCGWINSZ;
|
|
||||||
TIOCGWINSZ as u64
|
|
||||||
}
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
#[cfg(target_pointer_width = "32")]
|
|
||||||
#[cfg(not(target_env = "musl"))]
|
|
||||||
fn tiocgwinsz() -> u32 {
|
|
||||||
use termios::TIOCGWINSZ;
|
|
||||||
TIOCGWINSZ as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_env = "musl", target_os = "android"))]
|
|
||||||
fn tiocgwinsz() -> i32 {
|
|
||||||
use termios::TIOCGWINSZ;
|
|
||||||
TIOCGWINSZ as i32
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the terminal.
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
pub fn terminal_size() -> io::Result<(u16, u16)> {
|
|
||||||
use libc::ioctl;
|
|
||||||
use libc::STDOUT_FILENO;
|
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
unsafe {
|
|
||||||
let mut size: TermSize = mem::zeroed();
|
|
||||||
|
|
||||||
if ioctl(STDOUT_FILENO, tiocgwinsz(), &mut size as *mut _) == 0 {
|
|
||||||
Ok((size.col as u16, size.row as u16))
|
|
||||||
} else {
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "Unable to get the terminal size."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the terminal.
|
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
pub fn terminal_size() -> io::Result<(u16, u16)> {
|
|
||||||
use redox_termios;
|
|
||||||
use syscall;
|
|
||||||
|
|
||||||
if let Ok(fd) = syscall::dup(1, b"winsize") {
|
|
||||||
let mut winsize = redox_termios::Winsize::default();
|
|
||||||
let res = syscall::read(fd, &mut winsize);
|
|
||||||
let _ = syscall::close(fd);
|
|
||||||
if let Ok(count) = res {
|
|
||||||
if count == winsize.len() {
|
|
||||||
return Ok((winsize.ws_col, winsize.ws_row));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "Unable to get the terminal size."))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_size() {
|
|
||||||
assert!(terminal_size().is_ok());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use super::{cvt, syscall, Termios};
|
||||||
|
|
||||||
|
pub fn get_terminal_attr() -> io::Result<Termios> {
|
||||||
|
let mut termios = Termios::default();
|
||||||
|
|
||||||
|
let fd = cvt(syscall::dup(0, b"termios"))?;
|
||||||
|
let res = cvt(syscall::read(fd, &mut termios));
|
||||||
|
let _ = syscall::close(fd);
|
||||||
|
|
||||||
|
if res? == termios.len() {
|
||||||
|
Ok(termios)
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "Unable to get the terminal attributes."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_terminal_attr(termios: &Termios) -> io::Result<()> {
|
||||||
|
let fd = cvt(syscall::dup(0, b"termios"))?;
|
||||||
|
let res = cvt(syscall::write(fd, termios));
|
||||||
|
let _ = syscall::close(fd);
|
||||||
|
|
||||||
|
if res? == termios.len() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "Unable to set the terminal attributes."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw_terminal_attr(ios: &mut Termios) {
|
||||||
|
ios.make_raw()
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
extern crate redox_termios;
|
||||||
|
extern crate syscall;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub use self::redox_termios::Termios;
|
||||||
|
|
||||||
|
pub mod attr;
|
||||||
|
pub mod size;
|
||||||
|
pub mod tty;
|
||||||
|
|
||||||
|
// Support function for converting syscall error to io error
|
||||||
|
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
|
||||||
|
result.map_err(|err| io::Error::from_raw_os_error(err.errno))
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use super::{cvt, redox_termios, syscall};
|
||||||
|
|
||||||
|
/// Get the size of the terminal.
|
||||||
|
pub fn terminal_size() -> io::Result<(u16, u16)> {
|
||||||
|
let mut winsize = redox_termios::Winsize::default();
|
||||||
|
|
||||||
|
let fd = cvt(syscall::dup(1, b"winsize"))?;
|
||||||
|
let res = cvt(syscall::read(fd, &mut winsize));
|
||||||
|
let _ = syscall::close(fd);
|
||||||
|
|
||||||
|
if res? == winsize.len() {
|
||||||
|
Ok((winsize.ws_col, winsize.ws_row))
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "Unable to get the terminal size."))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,10 @@
|
||||||
use std::{fs, io};
|
use std::{env, fs, io};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
/// Is this stream a TTY?
|
use super::syscall;
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
unsafe { libc::isatty(stream.as_raw_fd()) == 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this stream a TTY?
|
/// Is this stream a TTY?
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
|
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
|
||||||
use syscall;
|
|
||||||
|
|
||||||
if let Ok(fd) = syscall::dup(stream.as_raw_fd(), b"termios") {
|
if let Ok(fd) = syscall::dup(stream.as_raw_fd(), b"termios") {
|
||||||
let _ = syscall::close(fd);
|
let _ = syscall::close(fd);
|
||||||
true
|
true
|
||||||
|
@ -25,17 +16,7 @@ pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
|
||||||
/// Get the TTY device.
|
/// Get the TTY device.
|
||||||
///
|
///
|
||||||
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
|
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
pub fn get_tty() -> io::Result<fs::File> {
|
pub fn get_tty() -> io::Result<fs::File> {
|
||||||
use std::env;
|
|
||||||
let tty = try!(env::var("TTY").map_err(|x| io::Error::new(io::ErrorKind::NotFound, x)));
|
let tty = try!(env::var("TTY").map_err(|x| io::Error::new(io::ErrorKind::NotFound, x)));
|
||||||
fs::OpenOptions::new().read(true).write(true).open(tty)
|
fs::OpenOptions::new().read(true).write(true).open(tty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the TTY device.
|
|
||||||
///
|
|
||||||
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
|
|
||||||
#[cfg(not(target_os = "redox"))]
|
|
||||||
pub fn get_tty() -> io::Result<fs::File> {
|
|
||||||
fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
use std::{io, mem};
|
||||||
|
|
||||||
|
use super::{cvt, Termios};
|
||||||
|
use super::libc::c_int;
|
||||||
|
|
||||||
|
pub fn get_terminal_attr() -> 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_terminal_attr(termios: &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 raw_terminal_attr(termios: &mut Termios) {
|
||||||
|
extern "C" {
|
||||||
|
pub fn cfmakeraw(termptr: *mut Termios);
|
||||||
|
}
|
||||||
|
unsafe { cfmakeraw(termios) }
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub use self::libc::termios as Termios;
|
||||||
|
|
||||||
|
pub mod attr;
|
||||||
|
pub mod size;
|
||||||
|
pub mod tty;
|
||||||
|
|
||||||
|
// Support functions for converting libc return values to io errors {
|
||||||
|
trait IsMinusOne {
|
||||||
|
fn is_minus_one(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_is_minus_one {
|
||||||
|
($($t:ident)*) => ($(impl IsMinusOne for $t {
|
||||||
|
fn is_minus_one(&self) -> bool {
|
||||||
|
*self == -1
|
||||||
|
}
|
||||||
|
})*)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_is_minus_one! { i8 i16 i32 i64 isize }
|
||||||
|
|
||||||
|
fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
|
||||||
|
if t.is_minus_one() {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// } End of support functions
|
|
@ -0,0 +1,48 @@
|
||||||
|
use std::{io, mem};
|
||||||
|
|
||||||
|
use super::cvt;
|
||||||
|
use super::libc::{c_ushort, ioctl, STDOUT_FILENO};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct TermSize {
|
||||||
|
row: c_ushort,
|
||||||
|
col: c_ushort,
|
||||||
|
_x: c_ushort,
|
||||||
|
_y: c_ushort,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub const TIOCGWINSZ: usize = 0x00005413;
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "linux"))]
|
||||||
|
pub const TIOCGWINSZ: usize = 0x40087468;
|
||||||
|
|
||||||
|
// Since attributes on non-item statements is not stable yet, we use a function.
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
#[cfg(not(target_os = "redox"))]
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
#[cfg(not(target_env = "musl"))]
|
||||||
|
fn tiocgwinsz() -> u64 {
|
||||||
|
TIOCGWINSZ as u64
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
#[cfg(not(target_os = "redox"))]
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
#[cfg(not(target_env = "musl"))]
|
||||||
|
fn tiocgwinsz() -> u32 {
|
||||||
|
TIOCGWINSZ as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_env = "musl", target_os = "android"))]
|
||||||
|
fn tiocgwinsz() -> i32 {
|
||||||
|
TIOCGWINSZ as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the size of the terminal.
|
||||||
|
pub fn terminal_size() -> io::Result<(u16, u16)> {
|
||||||
|
unsafe {
|
||||||
|
let mut size: TermSize = mem::zeroed();
|
||||||
|
cvt(ioctl(STDOUT_FILENO, tiocgwinsz(), &mut size as *mut _))?;
|
||||||
|
Ok((size.col as u16, size.row as u16))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
use std::{fs, io};
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
use super::libc;
|
||||||
|
|
||||||
|
|
||||||
|
/// Is this stream a TTY?
|
||||||
|
pub fn is_tty<T: AsRawFd>(stream: &T) -> bool {
|
||||||
|
unsafe { libc::isatty(stream.as_raw_fd()) == 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the TTY device.
|
||||||
|
///
|
||||||
|
/// This allows for getting stdio representing _only_ the TTY, and not other streams.
|
||||||
|
pub fn get_tty() -> io::Result<fs::File> {
|
||||||
|
fs::OpenOptions::new().read(true).write(true).open("/dev/tty")
|
||||||
|
}
|
|
@ -1,45 +0,0 @@
|
||||||
use libc::c_int;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
pub use libc::termios as Termios;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub const TIOCGWINSZ: usize = 0x00005413;
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
|
||||||
pub const TIOCGWINSZ: usize = 0x40087468;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
pub fn tcgetattr(fd: c_int, termptr: *mut Termios) -> c_int;
|
|
||||||
pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *mut Termios) -> c_int;
|
|
||||||
pub fn cfmakeraw(termptr: *mut Termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_terminal_attr() -> (Termios, c_int) {
|
|
||||||
unsafe {
|
|
||||||
let mut ios = mem::zeroed();
|
|
||||||
let attr = tcgetattr(0, &mut ios);
|
|
||||||
(ios, attr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_terminal_attr(ios: *mut Termios) -> c_int {
|
|
||||||
unsafe { tcsetattr(0, 0, ios) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_terminal_attr() {
|
|
||||||
get_terminal_attr();
|
|
||||||
get_terminal_attr();
|
|
||||||
get_terminal_attr();
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_set_terminal_attr() {
|
|
||||||
let mut ios = get_terminal_attr().0;
|
|
||||||
set_terminal_attr(&mut ios as *mut _);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue