mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
added configurable terminal size
This commit is contained in:
parent
a4d5defeef
commit
d8b3b41850
2 changed files with 56 additions and 15 deletions
|
@ -1228,7 +1228,10 @@ pub struct UCommand {
|
||||||
limits: Vec<(rlimit::Resource, u64, u64)>,
|
limits: Vec<(rlimit::Resource, u64, u64)>,
|
||||||
stderr_to_stdout: bool,
|
stderr_to_stdout: bool,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
|
#[cfg(unix)]
|
||||||
terminal_simulation: bool,
|
terminal_simulation: bool,
|
||||||
|
#[cfg(unix)]
|
||||||
|
terminal_size: Option<libc::winsize>,
|
||||||
tmpd: Option<Rc<TempDir>>, // drop last
|
tmpd: Option<Rc<TempDir>>, // drop last
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,14 +1410,27 @@ impl UCommand {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set if process should be run in a simulated terminal (unix: pty, windows: ConPTY[not yet supported])
|
/// Set if process should be run in a simulated terminal
|
||||||
|
///
|
||||||
/// This is useful to test behavior that is only active if [`stdout.is_terminal()`] is [`true`].
|
/// This is useful to test behavior that is only active if [`stdout.is_terminal()`] is [`true`].
|
||||||
|
/// (unix: pty, windows: ConPTY[not yet supported])
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn terminal_simulation(&mut self, enable: bool) -> &mut Self {
|
pub fn terminal_simulation(&mut self, enable: bool) -> &mut Self {
|
||||||
self.terminal_simulation = enable;
|
self.terminal_simulation = enable;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set if process should be run in a simulated terminal with specific size
|
||||||
|
///
|
||||||
|
/// This is useful to test behavior that is only active if [`stdout.is_terminal()`] is [`true`].
|
||||||
|
/// And the size of the terminal matters additionally.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn terminal_size(&mut self, win_size: libc::winsize) -> &mut Self {
|
||||||
|
self.terminal_simulation(true);
|
||||||
|
self.terminal_size = Some(win_size);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn read_from_pty(pty_fd: std::os::fd::OwnedFd, out: File) {
|
fn read_from_pty(pty_fd: std::os::fd::OwnedFd, out: File) {
|
||||||
let read_file = std::fs::File::from(pty_fd);
|
let read_file = std::fs::File::from(pty_fd);
|
||||||
|
@ -1427,7 +1443,7 @@ impl UCommand {
|
||||||
Err(e) if e.raw_os_error().unwrap_or_default() == 5 => {}
|
Err(e) if e.raw_os_error().unwrap_or_default() == 5 => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Unexpected error: {:?}", e);
|
eprintln!("Unexpected error: {:?}", e);
|
||||||
assert!(false);
|
panic!("error forwarding output of pty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1600,12 +1616,12 @@ impl UCommand {
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
if self.terminal_simulation {
|
if self.terminal_simulation {
|
||||||
let terminal_size = libc::winsize {
|
let terminal_size = self.terminal_size.unwrap_or(libc::winsize {
|
||||||
ws_col: 80,
|
ws_col: 80,
|
||||||
ws_row: 30,
|
ws_row: 30,
|
||||||
ws_xpixel: 800,
|
ws_xpixel: 80 * 8,
|
||||||
ws_ypixel: 300,
|
ws_ypixel: 30 * 10,
|
||||||
};
|
});
|
||||||
|
|
||||||
let OpenptyResult {
|
let OpenptyResult {
|
||||||
slave: pi_slave,
|
slave: pi_slave,
|
||||||
|
@ -2147,17 +2163,15 @@ impl UChild {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(stdout) = self.captured_stdout.as_mut() {
|
if let Some(stdout) = self.captured_stdout.as_mut() {
|
||||||
stdout
|
if let Some(handle) = stdout.reader_thread_handle.take() {
|
||||||
.reader_thread_handle
|
handle.join().unwrap();
|
||||||
.take()
|
}
|
||||||
.map(|handle| handle.join().unwrap());
|
|
||||||
output.stdout = stdout.output_bytes();
|
output.stdout = stdout.output_bytes();
|
||||||
}
|
}
|
||||||
if let Some(stderr) = self.captured_stderr.as_mut() {
|
if let Some(stderr) = self.captured_stderr.as_mut() {
|
||||||
stderr
|
if let Some(handle) = stderr.reader_thread_handle.take() {
|
||||||
.reader_thread_handle
|
handle.join().unwrap();
|
||||||
.take()
|
}
|
||||||
.map(|handle| handle.join().unwrap());
|
|
||||||
output.stderr = stderr.output_bytes();
|
output.stderr = stderr.output_bytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3597,7 +3611,33 @@ mod tests {
|
||||||
.succeeds();
|
.succeeds();
|
||||||
std::assert_eq!(
|
std::assert_eq!(
|
||||||
String::from_utf8_lossy(out.stdout()),
|
String::from_utf8_lossy(out.stdout()),
|
||||||
"stdin is atty\r\nstdout is atty\r\nstderr is atty\r\n"
|
"stdin is atty\r\nstdout is atty\r\nstderr is atty\r\nterminal size: 30 80\r\n"
|
||||||
|
);
|
||||||
|
std::assert_eq!(
|
||||||
|
String::from_utf8_lossy(out.stderr()),
|
||||||
|
"This is an error message.\r\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[test]
|
||||||
|
fn test_simulation_of_terminal_size_information() {
|
||||||
|
let scene = TestScenario::new("util");
|
||||||
|
|
||||||
|
let out = scene
|
||||||
|
.ccmd("env")
|
||||||
|
.arg("sh")
|
||||||
|
.arg("is_atty.sh")
|
||||||
|
.terminal_size(libc::winsize {
|
||||||
|
ws_col: 40,
|
||||||
|
ws_row: 10,
|
||||||
|
ws_xpixel: 40 * 8,
|
||||||
|
ws_ypixel: 10 * 10,
|
||||||
|
})
|
||||||
|
.succeeds();
|
||||||
|
std::assert_eq!(
|
||||||
|
String::from_utf8_lossy(out.stdout()),
|
||||||
|
"stdin is atty\r\nstdout is atty\r\nstderr is atty\r\nterminal size: 10 40\r\n"
|
||||||
);
|
);
|
||||||
std::assert_eq!(
|
std::assert_eq!(
|
||||||
String::from_utf8_lossy(out.stderr()),
|
String::from_utf8_lossy(out.stderr()),
|
||||||
|
|
1
tests/fixtures/util/is_atty.sh
vendored
1
tests/fixtures/util/is_atty.sh
vendored
|
@ -14,6 +14,7 @@ fi
|
||||||
|
|
||||||
if [ -t 2 ] ; then
|
if [ -t 2 ] ; then
|
||||||
echo "stderr is atty"
|
echo "stderr is atty"
|
||||||
|
echo "terminal size: $(stty size)"
|
||||||
else
|
else
|
||||||
echo "stderr is not atty"
|
echo "stderr is not atty"
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue