Skip to content

Commit 3a7385c

Browse files
3v1n0ChrisDryden
authored andcommitted
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 b2d1117 commit 3a7385c

File tree

1 file changed

+124
-42
lines changed

1 file changed

+124
-42
lines changed

src/uu/stty/src/stty.rs

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

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

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

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

@@ -539,10 +596,9 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
539596
// so we get the underlying libc::termios struct to get that information.
540597
let libc_termios: nix::libc::termios = termios.clone().into();
541598
let line = libc_termios.c_line;
542-
print!("{}", translate!("stty-output-line", "line" => line));
599+
printer.print(&translate!("stty-output-line", "line" => line));
543600
}
544-
545-
println!();
601+
printer.flush();
546602
Ok(())
547603
}
548604

@@ -710,39 +766,41 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
710766
Ok(format!("{meta_prefix}{ctrl_prefix}{character}"))
711767
}
712768

713-
fn print_control_chars(termios: &Termios, opts: &Options) -> nix::Result<()> {
769+
fn print_control_chars(
770+
termios: &Termios,
771+
opts: &Options,
772+
term_size: &Option<TermSize>,
773+
) -> nix::Result<()> {
714774
if !opts.all {
715775
// Print only control chars that differ from sane defaults
716-
let mut printed = false;
776+
let mut printer = WrappedPrinter::new(term_size);
717777
for (text, cc_index) in CONTROL_CHARS {
718778
let current_val = termios.control_chars[*cc_index as usize];
719779
let sane_val = get_sane_control_char(*cc_index);
720780

721781
if current_val != sane_val {
722-
print!("{text} = {}; ", control_char_to_string(current_val)?);
723-
printed = true;
782+
printer.print(&format!(
783+
"{text} = {};",
784+
control_char_to_string(current_val)?
785+
));
724786
}
725787
}
726-
727-
if printed {
728-
println!();
729-
}
788+
printer.flush();
730789
return Ok(());
731790
}
732791

792+
let mut printer = WrappedPrinter::new(term_size);
733793
for (text, cc_index) in CONTROL_CHARS {
734-
print!(
735-
"{text} = {}; ",
794+
printer.print(&format!(
795+
"{text} = {};",
736796
control_char_to_string(termios.control_chars[*cc_index as usize])?
737-
);
797+
));
738798
}
739-
println!(
740-
"{}",
741-
translate!("stty-output-min-time",
799+
printer.print(&translate!("stty-output-min-time",
742800
"min" => termios.control_chars[S::VMIN as usize],
743801
"time" => termios.control_chars[S::VTIME as usize]
744-
)
745-
);
802+
));
803+
printer.flush();
746804
Ok(())
747805
}
748806

@@ -764,18 +822,45 @@ fn print_settings(termios: &Termios, opts: &Options) -> nix::Result<()> {
764822
if opts.save {
765823
print_in_save_format(termios);
766824
} else {
767-
print_terminal_size(termios, opts)?;
768-
print_control_chars(termios, opts)?;
769-
print_flags(termios, opts, CONTROL_FLAGS);
770-
print_flags(termios, opts, INPUT_FLAGS);
771-
print_flags(termios, opts, OUTPUT_FLAGS);
772-
print_flags(termios, opts, LOCAL_FLAGS);
825+
let device_fd = opts.file.as_raw_fd();
826+
let term_size = {
827+
let mut term_size = TermSize::default();
828+
let term_size =
829+
unsafe { tiocgwinsz(device_fd, &raw mut term_size) }.map(|_| term_size);
830+
if opts.all {
831+
Some(term_size?)
832+
} else {
833+
term_size.ok()
834+
}
835+
};
836+
837+
let stdout_fd = stdout().as_raw_fd();
838+
let window_size = if device_fd != stdout_fd {
839+
let mut term_size = TermSize::default();
840+
&unsafe { tiocgwinsz(stdout_fd, &raw mut term_size) }
841+
.map(|_| term_size)
842+
.ok()
843+
} else {
844+
&term_size
845+
};
846+
847+
print_terminal_size(termios, opts, &window_size, &term_size)?;
848+
print_control_chars(termios, opts, &window_size)?;
849+
print_flags(termios, opts, CONTROL_FLAGS, &window_size);
850+
print_flags(termios, opts, INPUT_FLAGS, &window_size);
851+
print_flags(termios, opts, OUTPUT_FLAGS, &window_size);
852+
print_flags(termios, opts, LOCAL_FLAGS, &window_size);
773853
}
774854
Ok(())
775855
}
776856

777-
fn print_flags<T: TermiosFlag>(termios: &Termios, opts: &Options, flags: &[Flag<T>]) {
778-
let mut printed = false;
857+
fn print_flags<T: TermiosFlag>(
858+
termios: &Termios,
859+
opts: &Options,
860+
flags: &[Flag<T>],
861+
term_size: &Option<TermSize>,
862+
) {
863+
let mut printer = WrappedPrinter::new(term_size);
779864
for &Flag {
780865
name,
781866
flag,
@@ -790,20 +875,17 @@ fn print_flags<T: TermiosFlag>(termios: &Termios, opts: &Options, flags: &[Flag<
790875
let val = flag.is_in(termios, group);
791876
if group.is_some() {
792877
if val && (!sane || opts.all) {
793-
print!("{name} ");
794-
printed = true;
878+
printer.print(name);
795879
}
796880
} else if opts.all || val != sane {
797881
if !val {
798-
print!("-");
882+
printer.print(&format!("-{name}"));
883+
continue;
799884
}
800-
print!("{name} ");
801-
printed = true;
885+
printer.print(name);
802886
}
803887
}
804-
if printed {
805-
println!();
806-
}
888+
printer.flush();
807889
}
808890

809891
/// Apply a single setting

0 commit comments

Comments
 (0)