@@ -542,8 +542,71 @@ fn print_special_setting(setting: &PrintSetting, fd: i32) -> nix::Result<()> {
542542 Ok ( ( ) )
543543}
544544
545- fn print_terminal_size ( termios : & Termios , opts : & Options ) -> nix:: Result < ( ) > {
545+ /// Handles line wrapping for stty output to fit within terminal width
546+ struct WrappedPrinter {
547+ width : usize ,
548+ current : usize ,
549+ first_in_line : bool ,
550+ }
551+
552+ impl WrappedPrinter {
553+ /// Creates a new printer with the specified terminal width.
554+ /// If term_size is None (typically when output is piped), falls back to
555+ /// the COLUMNS environment variable or a default width of 80 columns.
556+ fn new ( term_size : Option < & TermSize > ) -> Self {
557+ let columns = match term_size {
558+ Some ( term_size) => term_size. columns ,
559+ None => {
560+ const DEFAULT_TERM_WIDTH : u16 = 80 ;
561+
562+ std:: env:: var_os ( "COLUMNS" )
563+ . and_then ( |s| s. to_str ( ) ?. parse ( ) . ok ( ) )
564+ . filter ( |& c| c > 0 )
565+ . unwrap_or ( DEFAULT_TERM_WIDTH )
566+ }
567+ } ;
568+
569+ Self {
570+ width : columns. max ( 1 ) as usize ,
571+ current : 0 ,
572+ first_in_line : true ,
573+ }
574+ }
575+
576+ fn print ( & mut self , token : & str ) {
577+ let token_len = self . prefix ( ) . chars ( ) . count ( ) + token. chars ( ) . count ( ) ;
578+ if self . current > 0 && self . current + token_len > self . width {
579+ println ! ( ) ;
580+ self . current = 0 ;
581+ self . first_in_line = true ;
582+ }
583+
584+ print ! ( "{}{}" , self . prefix( ) , token) ;
585+ self . current += token_len;
586+ self . first_in_line = false ;
587+ }
588+
589+ fn prefix ( & self ) -> & str {
590+ if self . first_in_line { "" } else { " " }
591+ }
592+
593+ fn flush ( & mut self ) {
594+ if self . current > 0 {
595+ println ! ( ) ;
596+ self . current = 0 ;
597+ self . first_in_line = false ;
598+ }
599+ }
600+ }
601+
602+ fn print_terminal_size (
603+ termios : & Termios ,
604+ opts : & Options ,
605+ window_size : Option < & TermSize > ,
606+ term_size : Option < & TermSize > ,
607+ ) -> nix:: Result < ( ) > {
546608 let speed = cfgetospeed ( termios) ;
609+ let mut printer = WrappedPrinter :: new ( window_size) ;
547610
548611 // BSDs use a u32 for the baud rate, so we can simply print it.
549612 #[ cfg( any(
@@ -554,7 +617,7 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
554617 target_os = "netbsd" ,
555618 target_os = "openbsd"
556619 ) ) ]
557- print ! ( "{} " , translate!( "stty-output-speed" , "speed" => speed) ) ;
620+ printer . print ( & translate ! ( "stty-output-speed" , "speed" => speed) ) ;
558621
559622 // Other platforms need to use the baud rate enum, so printing the right value
560623 // becomes slightly more complicated.
@@ -568,17 +631,15 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
568631 ) ) ) ]
569632 for ( text, baud_rate) in BAUD_RATES {
570633 if * baud_rate == speed {
571- print ! ( "{} " , translate!( "stty-output-speed" , "speed" => ( * text) ) ) ;
634+ printer . print ( & translate ! ( "stty-output-speed" , "speed" => ( * text) ) ) ;
572635 break ;
573636 }
574637 }
575638
576639 if opts. all {
577- let mut size = TermSize :: default ( ) ;
578- unsafe { tiocgwinsz ( opts. file . as_raw_fd ( ) , & raw mut size) ? } ;
579- print ! (
580- "{} " ,
581- translate!( "stty-output-rows-columns" , "rows" => size. rows, "columns" => size. columns)
640+ let term_size = term_size. as_ref ( ) . expect ( "terminal size should be set" ) ;
641+ printer. print (
642+ & translate ! ( "stty-output-rows-columns" , "rows" => term_size. rows, "columns" => term_size. columns) ,
582643 ) ;
583644 }
584645
@@ -588,10 +649,9 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
588649 // so we get the underlying libc::termios struct to get that information.
589650 let libc_termios: nix:: libc:: termios = termios. clone ( ) . into ( ) ;
590651 let line = libc_termios. c_line ;
591- print ! ( "{}" , translate!( "stty-output-line" , "line" => line) ) ;
652+ printer . print ( & translate ! ( "stty-output-line" , "line" => line) ) ;
592653 }
593-
594- println ! ( ) ;
654+ printer. flush ( ) ;
595655 Ok ( ( ) )
596656}
597657
@@ -759,39 +819,41 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
759819 Ok ( format ! ( "{meta_prefix}{ctrl_prefix}{character}" ) )
760820}
761821
762- fn print_control_chars ( termios : & Termios , opts : & Options ) -> nix:: Result < ( ) > {
822+ fn print_control_chars (
823+ termios : & Termios ,
824+ opts : & Options ,
825+ term_size : Option < & TermSize > ,
826+ ) -> nix:: Result < ( ) > {
763827 if !opts. all {
764828 // Print only control chars that differ from sane defaults
765- let mut printed = false ;
829+ let mut printer = WrappedPrinter :: new ( term_size ) ;
766830 for ( text, cc_index) in CONTROL_CHARS {
767831 let current_val = termios. control_chars [ * cc_index as usize ] ;
768832 let sane_val = get_sane_control_char ( * cc_index) ;
769833
770834 if current_val != sane_val {
771- print ! ( "{text} = {}; " , control_char_to_string( current_val) ?) ;
772- printed = true ;
835+ printer. print ( & format ! (
836+ "{text} = {};" ,
837+ control_char_to_string( current_val) ?
838+ ) ) ;
773839 }
774840 }
775-
776- if printed {
777- println ! ( ) ;
778- }
841+ printer. flush ( ) ;
779842 return Ok ( ( ) ) ;
780843 }
781844
845+ let mut printer = WrappedPrinter :: new ( term_size) ;
782846 for ( text, cc_index) in CONTROL_CHARS {
783- print ! (
784- "{text} = {}; " ,
847+ printer . print ( & format ! (
848+ "{text} = {};" ,
785849 control_char_to_string( termios. control_chars[ * cc_index as usize ] ) ?
786- ) ;
850+ ) ) ;
787851 }
788- println ! (
789- "{}" ,
790- translate!( "stty-output-min-time" ,
852+ printer. print ( & translate ! ( "stty-output-min-time" ,
791853 "min" => termios. control_chars[ S :: VMIN as usize ] ,
792854 "time" => termios. control_chars[ S :: VTIME as usize ]
793- )
794- ) ;
855+ ) ) ;
856+ printer . flush ( ) ;
795857 Ok ( ( ) )
796858}
797859
@@ -809,22 +871,48 @@ fn print_in_save_format(termios: &Termios) {
809871 println ! ( ) ;
810872}
811873
874+ /// Gets terminal size using the tiocgwinsz ioctl system call.
875+ /// This queries the kernel for the current terminal window dimensions.
876+ fn get_terminal_size ( fd : RawFd ) -> nix:: Result < TermSize > {
877+ let mut term_size = TermSize :: default ( ) ;
878+ unsafe { tiocgwinsz ( fd, & raw mut term_size) } . map ( |_| term_size)
879+ }
880+
812881fn print_settings ( termios : & Termios , opts : & Options ) -> nix:: Result < ( ) > {
813882 if opts. save {
814883 print_in_save_format ( termios) ;
815884 } else {
816- print_terminal_size ( termios, opts) ?;
817- print_control_chars ( termios, opts) ?;
818- print_flags ( termios, opts, CONTROL_FLAGS ) ;
819- print_flags ( termios, opts, INPUT_FLAGS ) ;
820- print_flags ( termios, opts, OUTPUT_FLAGS ) ;
821- print_flags ( termios, opts, LOCAL_FLAGS ) ;
885+ let device_fd = opts. file . as_raw_fd ( ) ;
886+ let term_size = if opts. all {
887+ Some ( get_terminal_size ( device_fd) ?)
888+ } else {
889+ get_terminal_size ( device_fd) . ok ( )
890+ } ;
891+
892+ let stdout_fd = stdout ( ) . as_raw_fd ( ) ;
893+ let window_size = if device_fd == stdout_fd {
894+ & term_size
895+ } else {
896+ & get_terminal_size ( stdout_fd) . ok ( )
897+ } ;
898+
899+ print_terminal_size ( termios, opts, window_size. as_ref ( ) , term_size. as_ref ( ) ) ?;
900+ print_control_chars ( termios, opts, window_size. as_ref ( ) ) ?;
901+ print_flags ( termios, opts, CONTROL_FLAGS , window_size. as_ref ( ) ) ;
902+ print_flags ( termios, opts, INPUT_FLAGS , window_size. as_ref ( ) ) ;
903+ print_flags ( termios, opts, OUTPUT_FLAGS , window_size. as_ref ( ) ) ;
904+ print_flags ( termios, opts, LOCAL_FLAGS , window_size. as_ref ( ) ) ;
822905 }
823906 Ok ( ( ) )
824907}
825908
826- fn print_flags < T : TermiosFlag > ( termios : & Termios , opts : & Options , flags : & [ Flag < T > ] ) {
827- let mut printed = false ;
909+ fn print_flags < T : TermiosFlag > (
910+ termios : & Termios ,
911+ opts : & Options ,
912+ flags : & [ Flag < T > ] ,
913+ term_size : Option < & TermSize > ,
914+ ) {
915+ let mut printer = WrappedPrinter :: new ( term_size) ;
828916 for & Flag {
829917 name,
830918 flag,
@@ -839,20 +927,17 @@ fn print_flags<T: TermiosFlag>(termios: &Termios, opts: &Options, flags: &[Flag<
839927 let val = flag. is_in ( termios, group) ;
840928 if group. is_some ( ) {
841929 if val && ( !sane || opts. all ) {
842- print ! ( "{name} " ) ;
843- printed = true ;
930+ printer. print ( name) ;
844931 }
845932 } else if opts. all || val != sane {
846933 if !val {
847- print ! ( "-" ) ;
934+ printer. print ( & format ! ( "-{name}" ) ) ;
935+ continue ;
848936 }
849- print ! ( "{name} " ) ;
850- printed = true ;
937+ printer. print ( name) ;
851938 }
852939 }
853- if printed {
854- println ! ( ) ;
855- }
940+ printer. flush ( ) ;
856941}
857942
858943/// Apply a single setting
0 commit comments