Skip to content

Commit dbd3aaa

Browse files
committed
stty: Wrap parameters when using --all
Do the same as GNU stty when it has to prints the parameter, doing proper text wrapping
1 parent 4ee588e commit dbd3aaa

1 file changed

Lines changed: 124 additions & 42 deletions

File tree

src/uu/stty/src/stty.rs

Lines changed: 124 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,67 @@ fn print_special_setting(setting: &PrintSetting, fd: i32) -> nix::Result<()> {
492492
Ok(())
493493
}
494494

495-
fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
495+
struct WrappedPrinter {
496+
width: usize,
497+
current: usize,
498+
first_in_line: bool,
499+
}
500+
501+
impl WrappedPrinter {
502+
fn new(term_size: &Option<TermSize>) -> Self {
503+
let columns = match term_size {
504+
Some(term_size) => term_size.columns,
505+
None => {
506+
const DEFAULT_TERM_WIDTH: u16 = 80;
507+
508+
std::env::var_os("COLUMNS")
509+
.and_then(|s| s.to_str()?.parse().ok())
510+
.filter(|&c| c > 0)
511+
.unwrap_or(DEFAULT_TERM_WIDTH)
512+
}
513+
};
514+
515+
Self {
516+
width: columns.max(1) as usize,
517+
current: 0,
518+
first_in_line: true,
519+
}
520+
}
521+
522+
fn print(&mut self, token: &str) {
523+
let token_len = self.prefix().chars().count() + token.chars().count();
524+
if self.current > 0 && self.current + token_len > self.width {
525+
println!();
526+
self.current = 0;
527+
self.first_in_line = true;
528+
}
529+
530+
print!("{}{}", self.prefix(), token);
531+
self.current += token_len;
532+
self.first_in_line = false;
533+
}
534+
535+
fn prefix(&self) -> &str {
536+
if self.first_in_line { "" } else { " " }
537+
}
538+
539+
fn flush(&mut self) {
540+
if self.current > 0 {
541+
println!();
542+
self.current = 0;
543+
self.first_in_line = false;
544+
}
545+
}
546+
}
547+
548+
fn print_terminal_size(
549+
termios: &Termios,
550+
opts: &Options,
551+
window_size: &Option<TermSize>,
552+
term_size: &Option<TermSize>,
553+
) -> nix::Result<()> {
496554
let speed = cfgetospeed(termios);
555+
let mut printer = WrappedPrinter::new(window_size);
497556

498557
// BSDs use a u32 for the baud rate, so we can simply print it.
499558
#[cfg(any(
@@ -518,17 +577,15 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
518577
)))]
519578
for (text, baud_rate) in BAUD_RATES {
520579
if *baud_rate == speed {
521-
print!("{} ", translate!("stty-output-speed", "speed" => (*text)));
580+
printer.print(&translate!("stty-output-speed", "speed" => (*text)));
522581
break;
523582
}
524583
}
525584

526585
if opts.all {
527-
let mut size = TermSize::default();
528-
unsafe { tiocgwinsz(opts.file.as_raw_fd(), &raw mut size)? };
529-
print!(
530-
"{} ",
531-
translate!("stty-output-rows-columns", "rows" => size.rows, "columns" => size.columns)
586+
let term_size = term_size.as_ref().expect("terminal size should be set");
587+
printer.print(
588+
&translate!("stty-output-rows-columns", "rows" => term_size.rows, "columns" => term_size.columns),
532589
);
533590
}
534591

@@ -538,10 +595,9 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
538595
// so we get the underlying libc::termios struct to get that information.
539596
let libc_termios: nix::libc::termios = termios.clone().into();
540597
let line = libc_termios.c_line;
541-
print!("{}", translate!("stty-output-line", "line" => line));
598+
printer.print(&translate!("stty-output-line", "line" => line));
542599
}
543-
544-
println!();
600+
printer.flush();
545601
Ok(())
546602
}
547603

@@ -647,39 +703,41 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
647703
Ok(format!("{meta_prefix}{ctrl_prefix}{character}"))
648704
}
649705

650-
fn print_control_chars(termios: &Termios, opts: &Options) -> nix::Result<()> {
706+
fn print_control_chars(
707+
termios: &Termios,
708+
opts: &Options,
709+
term_size: &Option<TermSize>,
710+
) -> nix::Result<()> {
651711
if !opts.all {
652712
// Print only control chars that differ from sane defaults
653-
let mut printed = false;
713+
let mut printer = WrappedPrinter::new(term_size);
654714
for (text, cc_index) in CONTROL_CHARS {
655715
let current_val = termios.control_chars[*cc_index as usize];
656716
let sane_val = get_sane_control_char(*cc_index);
657717

658718
if current_val != sane_val {
659-
print!("{text} = {}; ", control_char_to_string(current_val)?);
660-
printed = true;
719+
printer.print(&format!(
720+
"{text} = {};",
721+
control_char_to_string(current_val)?
722+
));
661723
}
662724
}
663-
664-
if printed {
665-
println!();
666-
}
725+
printer.flush();
667726
return Ok(());
668727
}
669728

729+
let mut printer = WrappedPrinter::new(term_size);
670730
for (text, cc_index) in CONTROL_CHARS {
671-
print!(
672-
"{text} = {}; ",
731+
printer.print(&format!(
732+
"{text} = {};",
673733
control_char_to_string(termios.control_chars[*cc_index as usize])?
674-
);
734+
));
675735
}
676-
println!(
677-
"{}",
678-
translate!("stty-output-min-time",
736+
printer.print(&translate!("stty-output-min-time",
679737
"min" => termios.control_chars[S::VMIN as usize],
680738
"time" => termios.control_chars[S::VTIME as usize]
681-
)
682-
);
739+
));
740+
printer.flush();
683741
Ok(())
684742
}
685743

@@ -701,18 +759,45 @@ fn print_settings(termios: &Termios, opts: &Options) -> nix::Result<()> {
701759
if opts.save {
702760
print_in_save_format(termios);
703761
} else {
704-
print_terminal_size(termios, opts)?;
705-
print_control_chars(termios, opts)?;
706-
print_flags(termios, opts, CONTROL_FLAGS);
707-
print_flags(termios, opts, INPUT_FLAGS);
708-
print_flags(termios, opts, OUTPUT_FLAGS);
709-
print_flags(termios, opts, LOCAL_FLAGS);
762+
let device_fd = opts.file.as_raw_fd();
763+
let term_size = {
764+
let mut term_size = TermSize::default();
765+
let term_size =
766+
unsafe { tiocgwinsz(device_fd, &raw mut term_size) }.map(|_| term_size);
767+
if opts.all {
768+
Some(term_size?)
769+
} else {
770+
term_size.ok()
771+
}
772+
};
773+
774+
let stdout_fd = stdout().as_raw_fd();
775+
let window_size = if device_fd != stdout_fd {
776+
let mut term_size = TermSize::default();
777+
&unsafe { tiocgwinsz(stdout_fd, &raw mut term_size) }
778+
.map(|_| term_size)
779+
.ok()
780+
} else {
781+
&term_size
782+
};
783+
784+
print_terminal_size(termios, opts, &window_size, &term_size)?;
785+
print_control_chars(termios, opts, &window_size)?;
786+
print_flags(termios, opts, CONTROL_FLAGS, &window_size);
787+
print_flags(termios, opts, INPUT_FLAGS, &window_size);
788+
print_flags(termios, opts, OUTPUT_FLAGS, &window_size);
789+
print_flags(termios, opts, LOCAL_FLAGS, &window_size);
710790
}
711791
Ok(())
712792
}
713793

714-
fn print_flags<T: TermiosFlag>(termios: &Termios, opts: &Options, flags: &[Flag<T>]) {
715-
let mut printed = false;
794+
fn print_flags<T: TermiosFlag>(
795+
termios: &Termios,
796+
opts: &Options,
797+
flags: &[Flag<T>],
798+
term_size: &Option<TermSize>,
799+
) {
800+
let mut printer = WrappedPrinter::new(term_size);
716801
for &Flag {
717802
name,
718803
flag,
@@ -727,20 +812,17 @@ fn print_flags<T: TermiosFlag>(termios: &Termios, opts: &Options, flags: &[Flag<
727812
let val = flag.is_in(termios, group);
728813
if group.is_some() {
729814
if val && (!sane || opts.all) {
730-
print!("{name} ");
731-
printed = true;
815+
printer.print(name);
732816
}
733817
} else if opts.all || val != sane {
734818
if !val {
735-
print!("-");
819+
printer.print(&format!("-{name}"));
820+
continue;
736821
}
737-
print!("{name} ");
738-
printed = true;
822+
printer.print(name);
739823
}
740824
}
741-
if printed {
742-
println!();
743-
}
825+
printer.flush();
744826
}
745827

746828
/// Apply a single setting

0 commit comments

Comments
 (0)