diff --git a/module/core/format_tools/src/format/output_format/table.rs b/module/core/format_tools/src/format/output_format/table.rs index e96af36f20..5662f8c9fa 100644 --- a/module/core/format_tools/src/format/output_format/table.rs +++ b/module/core/format_tools/src/format/output_format/table.rs @@ -223,7 +223,7 @@ impl TableOutputFormat for Table for islice in 0..height { - if irow > 0 + if irow > 0 || islice > 0 { write!( c.buf, "{}", row_separator )?; } @@ -247,7 +247,7 @@ impl TableOutputFormat for Table write!( c.buf, "{}", cell_prefix )?; - println!( "icol : {icol} | irow : {irow} | width : {width} | cell_width : {cell_width} | slice.len() : {}", slice.len() ); + // println!( "icol : {icol} | irow : {irow} | width : {width} | cell_width : {cell_width} | slice.len() : {}", slice.len() ); let lspaces = if cell_width > width { 0 diff --git a/module/core/format_tools/src/format/print.rs b/module/core/format_tools/src/format/print.rs index 78ac91b294..3e50b676a4 100644 --- a/module/core/format_tools/src/format/print.rs +++ b/module/core/format_tools/src/format/print.rs @@ -159,6 +159,10 @@ mod private /// Formats the table and writes the result to the provided context. fn fmt< 'context >( &'data self, c : & mut Context< 'context > ) -> fmt::Result; + /// Formats the table and writes the result to the provided context. + /// Also limits the table width. + fn fmt_limit< 'context >( &'data self, c : & mut Context< 'context >, limit_width : usize ) -> fmt::Result; + /// Converts the table to a string representation. /// /// # Returns @@ -169,6 +173,16 @@ mod private self.table_to_string_with_format( &output_format::Table::default() ) } + /// Converts the table to a string representation with limited width requirement. + /// + /// # Returns + /// + /// A `String` containing the formatted table. + fn table_to_string_limit( &'data self, limit_width : usize ) -> String + { + self.table_to_string_with_format_limit( &output_format::Table::default(), limit_width ) + } + /// Converts the table to a string representation specifying printer. /// /// # Returns @@ -194,6 +208,31 @@ mod private output } + /// Converts the table to a string representation specifying printer with limited width requirement. + /// + /// # Returns + /// + /// A `String` containing the formatted table. + fn table_to_string_with_format_limit< 'context, Styles >( &'data self, styles : &'context Styles, limit_width : usize ) -> String + where + Styles : TableOutputFormat, + { + let mut output = String::new(); + let printer = Printer + { + output_format : styles, + filter_col : Default::default(), + filter_row : Default::default(), + }; + let mut context = Context + { + buf : &mut output, + printer, + }; + Self::fmt_limit( self, &mut context, limit_width ).expect( "Table formatting failed" ); + output + } + } /// A trait for formatting tables. @@ -210,12 +249,27 @@ mod private fn fmt< 'a >( &'data self, c : &mut Context< 'a > ) -> fmt::Result { + InputExtract::extract + ( + self, + c.printer.filter_col, + c.printer.filter_row, + 0, + | x | + { + c.printer.output_format.extract_write( x, c ) + } + ) + } + fn fmt_limit< 'a >( &'data self, c : &mut Context< 'a >, limit_width : usize ) -> fmt::Result + { InputExtract::extract ( self, c.printer.filter_col, c.printer.filter_row, + limit_width, | x | { c.printer.output_format.extract_write( x, c ) @@ -370,6 +424,7 @@ mod private table : &'t Table, filter_col : &'context ( dyn FilterCol + 'context ), filter_row : &'context ( dyn FilterRow + 'context ), + limit_width : usize, callback : impl for< 'a2 > FnOnce( &'a2 InputExtract< 'a2 > ) -> fmt::Result, ) -> fmt::Result @@ -403,6 +458,61 @@ mod private let filter_col_need_args = filter_col.need_args(); // let filter_row_need_args = filter_row.need_args(); + let col_count = if let Some( iter ) = table.header() + { + let mut r = 0; + + for (_, col) in iter + { + if filter_col_need_args + { + if filter_col.filter_col( col ) + { + r += 1; + } + } + else + { + if filter_col.filter_col( "" ) + { + r += 1; + } + } + } + + r + } + else if let Some( row ) = table.rows().next() + { + let mut r = 0; + + for ( col, _ ) in row.cells() + { + if filter_col_need_args + { + if filter_col.filter_col( col.borrow() ) + { + r += 1; + } + } + else + { + if filter_col.filter_col( "" ) + { + r += 1; + } + } + } + + r + } + else + { + 0 + }; + + let limit_column_width = limit_width / col_count.max(1); + let mut row_add = | row_iter : &'_ mut dyn _IteratorTrait< Item = ( &'t CellKey, Cow< 't, str > ) >, typ : LineType | { @@ -439,7 +549,7 @@ mod private ncol_vis += 1; - let sz = string::size( &val ); + let sz = string::size_with_limit( &val, limit_column_width ); key_to_ikey .entry( key ) @@ -575,7 +685,7 @@ mod private for icol in 0 .. x.col_descriptors.len() { let cell = &row_data[ icol ]; - string::lines( cell.0.as_ref() ) + string::lines_with_limit( cell.0.as_ref(), limit_column_width ) .enumerate() .for_each( | ( layer, s ) | { diff --git a/module/core/format_tools/src/format/string.rs b/module/core/format_tools/src/format/string.rs index 619d1690c2..1cf3986af0 100644 --- a/module/core/format_tools/src/format/string.rs +++ b/module/core/format_tools/src/format/string.rs @@ -84,6 +84,35 @@ mod private [ width, height ] } + pub fn size_with_limit< S : AsRef< str > > + ( + src : S, + limit_width : usize, + ) + -> [ usize; 2 ] + { + if limit_width == 0 + { + return size( src ); + } + + let text = src.as_ref(); + let mut height = 0; + let mut width = 0; + + for line in lines_with_limit( text, limit_width ) + { + height += 1; + let line_length = line.len(); + if line_length > width + { + width = line_length; + } + } + + [ width, height ] + } + /// Returns an iterator over the lines of a string slice. /// /// This function provides an iterator that yields each line of the input string slice. @@ -114,6 +143,16 @@ mod private Lines::new( src.as_ref() ) } + pub fn lines_with_limit< S : AsRef< str > + ?Sized > + ( + src : & S, + limit_width : usize + ) + -> LinesWithLimit< '_ > + { + LinesWithLimit::new( src.as_ref(), limit_width ) + } + /// An iterator over the lines of a string slice. /// /// This struct implements the `Iterator` trait, allowing you to iterate over the lines @@ -128,6 +167,7 @@ mod private has_trailing_newline : bool, finished : bool, } + impl< 'a > Lines< 'a > { fn new( input : &'a str ) -> Self @@ -172,6 +212,61 @@ mod private } } + #[ derive( Debug ) ] + pub struct LinesWithLimit< 'a > + { + lines : Lines< 'a >, + limit_width : usize, + cur : Option< &'a str >, + } + + impl< 'a > LinesWithLimit< 'a > + { + fn new( input : &'a str, limit_width : usize ) -> Self + { + LinesWithLimit + { + lines : lines( input ), + limit_width, + cur : None, + } + } + } + + impl< 'a > Iterator for LinesWithLimit< 'a > + { + type Item = &'a str; + + fn next( &mut self ) -> Option< Self::Item > + { + if self.cur.is_none() || self.cur.is_some_and( str::is_empty ) + { + self.cur = self.lines.next(); + } + + match self.cur + { + None => return None, + + Some( cur ) => + { + if self.limit_width == 0 + { + self.cur = None; + Some( cur ) + } + else + { + let (chunk, rest) = cur.split_at(self.limit_width.min(cur.len())); + self.cur = Some( rest ); + + Some(chunk) + } + } + } + } + } + } #[ allow( unused_imports ) ] @@ -189,8 +284,11 @@ pub mod own pub use private:: { size, + size_with_limit, lines, Lines, + lines_with_limit, + LinesWithLimit, }; }