1extern crate libc;
2
3use std::io::IsTerminal;
4
5use self::{
6 super::Size,
7 libc::{c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ},
8};
9
10#[repr(C)]
12#[derive(Debug)]
13pub struct UnixSize {
14 pub rows: c_ushort,
16 pub cols: c_ushort,
18 x: c_ushort,
19 y: c_ushort,
20}
21
22pub fn get() -> Option<Size> {
24 if !std::io::stdout().is_terminal() {
26 return None;
27 }
28 let mut us = UnixSize {
29 rows: 0,
30 cols: 0,
31 x: 0,
32 y: 0,
33 };
34 let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut us) };
35 if r == 0 {
36 Some(Size {
37 rows: us.rows,
38 cols: us.cols,
39 })
40 } else {
41 None
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::{super::Size, get};
48 use std::process::{Command, Output, Stdio};
49
50 #[cfg(target_os = "macos")]
51 fn stty_size() -> Output {
52 Command::new("stty")
53 .arg("-f")
54 .arg("/dev/stderr")
55 .arg("size")
56 .stderr(Stdio::inherit())
57 .output()
58 .expect("expected stty output")
59 }
60
61 #[cfg(not(target_os = "macos"))]
62 fn stty_size() -> Output {
63 Command::new("stty")
64 .arg("-F")
65 .arg("/dev/stderr")
66 .arg("size")
67 .stderr(Stdio::inherit())
68 .output()
69 .expect("expected stty output")
70 }
71
72 #[test]
73 fn test_shell() {
74 let output = stty_size();
75 assert!(output.status.success());
76 let stdout = String::from_utf8(output.stdout).expect("expected utf8");
77 let mut data = stdout.split_whitespace();
78 let rs = data
79 .next()
80 .expect("expected row")
81 .parse::<u16>()
82 .expect("expected u16 col");
83 let cs = data
84 .next()
85 .expect("expected col")
86 .parse::<u16>()
87 .expect("expected u16 col");
88 if let Some(Size { rows, cols }) = get() {
89 assert_eq!(rows, rs);
90 assert_eq!(cols, cs);
91 }
92 }
93}