termsize_alt/
nix.rs

1extern crate libc;
2extern crate atty;
3
4use self::libc::{STDOUT_FILENO, TIOCGWINSZ, c_ushort};
5use self::libc::ioctl;
6use self::super::Size;
7
8/// A representation of the size of the current terminal
9#[repr(C)]
10#[derive(Debug)]
11pub struct UnixSize {
12    /// number of rows
13    pub rows: c_ushort,
14    /// number of columns
15    pub cols: c_ushort,
16    x: c_ushort,
17    y: c_ushort,
18}
19
20/// Gets the current terminal size
21pub fn get() -> Option<Size> {
22    // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
23    if atty::isnt(atty::Stream::Stdout) {
24        return None;
25    }
26    let us = UnixSize {
27        rows: 0,
28        cols: 0,
29        x: 0,
30        y: 0,
31    };
32    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ.into(), &us) };
33    if r == 0 {
34        Some(Size {
35            rows: us.rows,
36            cols: us.cols,
37        })
38    } else {
39        None
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::get;
46    use super::super::Size;
47    use std::process::{Command, Output, Stdio};
48
49    #[cfg(target_os = "macos")]
50    fn stty_size() -> Output {
51        Command::new("stty")
52            .arg("-f")
53            .arg("/dev/stderr")
54            .arg("size")
55            .stderr(Stdio::inherit())
56            .output()
57            .unwrap()
58    }
59
60    #[cfg(not(target_os = "macos"))]
61    fn stty_size() -> Output {
62        Command::new("stty")
63            .arg("-F")
64            .arg("/dev/stderr")
65            .arg("size")
66            .stderr(Stdio::inherit())
67            .output()
68            .unwrap()
69    }
70
71    #[test]
72    fn test_shell() {
73        let output = stty_size();
74        assert!(output.status.success());
75        let stdout = String::from_utf8(output.stdout).unwrap();
76        let mut data = stdout.split_whitespace();
77        let rs = data.next().unwrap().parse::<u16>().unwrap();
78        let cs = data.next().unwrap().parse::<u16>().unwrap();
79        if let Some(Size { rows, cols }) = get() {
80            assert_eq!(rows, rs);
81            assert_eq!(cols, cs);
82        }
83    }
84}