1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
// yt - A fully featured command line YouTube client
//
// Copyright (C) 2025 softprops <d.tangren@gmail.com>
// SPDX-License-Identifier: MIT
//
// This file is part of Yt.
//
// You should have received a copy of the License along with this program.
// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
extern crate libc;
use std::io::IsTerminal;
use self::{
super::Size,
libc::{c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ},
};
/// 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 get() -> Option<Size> {
// http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
if !std::io::stdout().is_terminal() {
return None;
}
let mut us = UnixSize {
rows: 0,
cols: 0,
x: 0,
y: 0,
};
let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut us) };
if r == 0 {
Some(Size {
rows: us.rows,
cols: us.cols,
})
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::{super::Size, get};
use std::process::{Command, Output, Stdio};
#[cfg(target_os = "macos")]
fn stty_size() -> Output {
Command::new("stty")
.arg("-f")
.arg("/dev/stderr")
.arg("size")
.stderr(Stdio::inherit())
.output()
.expect("expected stty output")
}
#[cfg(not(target_os = "macos"))]
fn stty_size() -> Output {
Command::new("stty")
.arg("-F")
.arg("/dev/stderr")
.arg("size")
.stderr(Stdio::inherit())
.output()
.expect("expected stty output")
}
#[test]
fn test_shell() {
let output = stty_size();
assert!(output.status.success());
let stdout = String::from_utf8(output.stdout).expect("expected utf8");
let mut data = stdout.split_whitespace();
let rs = data
.next()
.expect("expected row")
.parse::<u16>()
.expect("expected u16 col");
let cs = data
.next()
.expect("expected col")
.parse::<u16>()
.expect("expected u16 col");
if let Some(Size { rows, cols }) = get() {
assert_eq!(rows, rs);
assert_eq!(cols, cs);
}
}
}
|