diff --git a/module/core/format_tools/src/format/filter.rs b/module/core/format_tools/src/format/filter.rs index 1551721570..6430ee9f07 100644 --- a/module/core/format_tools/src/format/filter.rs +++ b/module/core/format_tools/src/format/filter.rs @@ -13,21 +13,6 @@ mod private borrow::Cow, }; - /// Represents a line type in a table, either a header or a regular row. - /// - /// `LineType` is used to distinguish between different types of lines - /// in a table structure, aiding in formatting and processing. - /// - #[ derive( Debug, Default, PartialEq, Eq, Copy, Clone ) ] - pub enum LineType - { - /// Represents a regular row of data in the table. - #[ default ] - Regular, - /// Represents a header line in the table. - Header, - } - // = filters /// Filter passing all elements. @@ -45,11 +30,6 @@ mod private { /// Filter columns of a table to print it only partially. fn filter_col( &self, key : &str ) -> bool; - /// Determine is arguments needed for the filter or it can give answer even without arguments. Useful for optimization. - fn need_args( &self ) -> bool - { - true - } } impl Default for &'static dyn FilterCol @@ -78,11 +58,6 @@ mod private { true } - #[ inline( always ) ] - fn need_args( &self ) -> bool - { - false - } } impl None @@ -102,11 +77,6 @@ mod private { false } - #[ inline( always ) ] - fn need_args( &self ) -> bool - { - false - } } impl< F : Fn( &str ) -> bool > FilterCol for F @@ -124,12 +94,7 @@ mod private pub trait FilterRow { /// Filter rows of a table to print it only partially. - fn filter_row( &self, typ : LineType, irow : usize, row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] ) -> bool; - /// Determine is arguments needed for the filter or it can give answer even without arguments. Useful for optimization. - fn need_args( &self ) -> bool - { - true - } + fn filter_row( &self, row : &[ Cow< '_, str > ] ) -> bool; } impl Default for &'static dyn FilterRow @@ -144,15 +109,10 @@ mod private impl FilterRow for All { #[ inline( always ) ] - fn filter_row( &self, _typ : LineType, _irow : usize, _row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] ) -> bool + fn filter_row( &self, _row : &[ Cow< '_, str > ] ) -> bool { true } - #[ inline( always ) ] - fn need_args( &self ) -> bool - { - false - } } impl All @@ -168,12 +128,7 @@ mod private impl FilterRow for None { #[ inline( always ) ] - fn filter_row( &self, _typ : LineType, _irow : usize, _row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] ) -> bool - { - false - } - #[ inline( always ) ] - fn need_args( &self ) -> bool + fn filter_row( &self, _row : &[ Cow< '_, str > ] ) -> bool { false } @@ -189,12 +144,12 @@ mod private } } - impl< F : Fn( LineType, usize, &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] ) -> bool > FilterRow for F + impl< F : Fn( &[ Cow< '_, str > ] ) -> bool > FilterRow for F { #[ inline( always ) ] - fn filter_row( &self, typ : LineType, irow : usize, row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] ) -> bool + fn filter_row( &self, row : &[ Cow< '_, str > ] ) -> bool { - self( typ, irow, row ) + self( row ) } } @@ -231,7 +186,6 @@ pub mod orphan #[ doc( inline ) ] pub use private:: { - LineType, FilterCol, FilterRow, }; diff --git a/module/core/format_tools/src/format/output_format/keys.rs b/module/core/format_tools/src/format/output_format/keys.rs index 55ee27b023..5e2397dcb8 100644 --- a/module/core/format_tools/src/format/output_format/keys.rs +++ b/module/core/format_tools/src/format/output_format/keys.rs @@ -92,14 +92,18 @@ impl TableOutputFormat for Keys ) -> fmt::Result { - // dbg!( &x ); - - for col in &x.col_descriptors + if x.has_header && x.data.len() != 0 { - write!( c.buf, " - {}\n", col.label )?; + for col in &x.data[0].1 + { + write!( c.buf, " - {}\n", col )?; + } } - write!( c.buf, " {} fields\n", x.col_descriptors.len() )?; + if x.data.len() != 0 + { + write!( c.buf, " {} fields\n", x.data[0].1.len() )?; + } Ok(()) } diff --git a/module/core/format_tools/src/format/output_format/records.rs b/module/core/format_tools/src/format/output_format/records.rs index 45a1206e41..c6f8ab4d68 100644 --- a/module/core/format_tools/src/format/output_format/records.rs +++ b/module/core/format_tools/src/format/output_format/records.rs @@ -22,12 +22,12 @@ //! use crate::*; -use md_math::MdOffset; use print:: { InputExtract, Context, }; +use std::borrow::{ Cow, Borrow }; use core:: { fmt, @@ -156,69 +156,77 @@ impl TableOutputFormat for Records ) -> fmt::Result { - let label_width = x.header().fold( 0, | acc, cell | acc.max( cell.1[ 0 ] ) ); + let field_names : Vec< Cow< 'data, str > > = x.header().collect(); + let key_width = x.header().fold( 0, | acc, cell | acc.max( cell.len() ) ); write!( c.buf, "{}", self.table_prefix )?; - let mut first = true; - // Write each record - for ( irow, row ) in x.rows() - { + let mut actual_entries = 0; - if !row.vis - { - continue; - } - - if first - { - first = false; - } - else + for ( ientry, entry ) in x.rows() + { + if actual_entries > 0 { write!( c.buf, "{}", self.table_separator )?; } - let slice_width = x.data[ irow ].iter().fold( 0, | acc, cell | acc.max( cell.1[ 0 ] ) ); + actual_entries += 1; - writeln!( c.buf, " = {}", irow )?; + writeln!( c.buf, " = {}", ientry )?; - for ( icol, _col ) in x.col_descriptors.iter().enumerate() - { - let cell = &x.data[ irow ][ icol ]; - let height = cell.1[ 1 ]; + let row = wrap_text( entry, 0 ); - for islice in 0..height - { - let label = x.header_slice( islice, icol ); - let md_index = [ islice, icol, irow ]; - let slice = x.slices[ x.slices_dim.md_offset( md_index ) ]; + let value_width = row.iter().map( |sr| sr.iter().map( |c| c.chars().count() ).max().unwrap_or(0) ).max().unwrap_or(0); + + let mut row_count = 0; - if icol > 0 || islice > 0 + for ( ifield, field ) in row.iter().enumerate() + { + for ( irow, row ) in field.iter().enumerate() + { + if row_count > 0 { write!( c.buf, "{}", self.row_separator )?; } + row_count += 1; + let key = if irow > 0 + { + "" + } + else + { + field_names.get( ifield ).map( Cow::borrow ).unwrap_or( "" ) + }; + write!( c.buf, "{}", self.row_prefix )?; write!( c.buf, "{}", self.cell_prefix )?; - write!( c.buf, "{: +( + data: &'data Vec< Cow< 'data, str > >, + _limit: usize +) +-> Vec< Vec< &'data str > > +{ + data.iter().map( |c| string::lines( c ).collect() ).collect() +} \ No newline at end of file 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..749c529dec 100644 --- a/module/core/format_tools/src/format/output_format/table.rs +++ b/module/core/format_tools/src/format/output_format/table.rs @@ -16,6 +16,7 @@ use print:: InputExtract, Context, }; +use std::borrow::Cow; use core:: { fmt, @@ -75,6 +76,8 @@ pub struct Table pub corner_lb : char, /// Bottom-right corner character. pub corner_rb : char, + /// Limit table size (0 - no limit). + pub max_width : usize, } impl Default for Table @@ -103,6 +106,8 @@ impl Default for Table let corner_lb = '└'; let corner_rb = '┘'; + let max_width = 50; + Self { delimitting_header, @@ -123,6 +128,7 @@ impl Default for Table corner_rt, corner_lb, corner_rb, + max_width, } } } @@ -163,8 +169,6 @@ impl TableOutputFormat for Table { fn extract_write< 'buf, 'data >( &self, x : &InputExtract< 'data >, c : &mut Context< 'buf > ) -> fmt::Result { - use md_math::MdOffset; - let cell_prefix = &self.cell_prefix; let cell_postfix = &self.cell_postfix; let cell_separator = &self.cell_separator; @@ -173,114 +177,137 @@ impl TableOutputFormat for Table let row_separator = &self.row_separator; let h = self.h.to_string(); - let mut delimitting_header = self.delimitting_header; - let row_width = if delimitting_header + let data = wrap_text( &x.data, self.max_width ); + + let column_count = x.header().count(); + + let mut col_width : Vec< usize > = vec![ 0; column_count ]; + + for ( _, row ) in data.iter() { - let mut grid_width = x.mcells_vis[ 0 ] * ( cell_prefix.chars().count() + cell_postfix.chars().count() ); - grid_width += row_prefix.chars().count() + row_postfix.chars().count(); - if x.mcells_vis[ 0 ] > 0 + for ( icol, col ) in row.iter().enumerate() { - grid_width += ( x.mcells_vis[ 0 ] - 1 ) * ( cell_separator.chars().count() ); + col_width[ icol ] = col_width[ icol ].max( col.content.chars().count() ); } - x.mchars[ 0 ] + grid_width } - else - { - 0 - }; - let mut prev_typ : Option< LineType > = None; - // dbg!( x.row_descriptors.len() ); + let max_row_width = col_width.iter().sum::() + + self.row_prefix.chars().count() + + self.row_postfix.chars().count() + + column_count * ( self.cell_postfix.chars().count() + self.cell_prefix.chars().count() ) + + if column_count == 0 { 0 } else { ( column_count - 1 ) * self.cell_separator.chars().count() }; - for ( irow, row ) in x.row_descriptors.iter().enumerate() - { - let height = row.height; + let mut actual_rows = 0; - if delimitting_header + for ( _, row ) in data.iter() + { + if actual_rows == 1 && x.has_header && self.delimitting_header { - if let Some( prev_typ ) = prev_typ - { - if prev_typ == LineType::Header && row.typ == LineType::Regular - { - write!( c.buf, "{}", row_separator )?; - write!( c.buf, "{}", h.repeat( row_width ) )?; - delimitting_header = false - } - } - if row.vis - { - prev_typ = Some( row.typ ); - } + write!( c.buf, "{}", row_separator )?; + write!( c.buf, "{}", h.repeat( max_row_width ) )?; } - - if !row.vis + + if actual_rows > 0 { - continue; + write!( c.buf, "{}", row_separator )?; } - // dbg!( row.height ); + actual_rows += 1; + + write!( c.buf, "{}", row_prefix )?; - for islice in 0..height + for ( icol, col ) in row.iter().enumerate() { + let cell_width = col.wrap_width; + let col_width = col_width[ icol ]; + let slice_width = col.content.chars().count(); - if irow > 0 + if icol > 0 { - write!( c.buf, "{}", row_separator )?; + write!( c.buf, "{}", cell_separator )?; } - write!( c.buf, "{}", row_prefix )?; + write!( c.buf, "{}", cell_prefix )?; + + let lspaces = ( col_width - cell_width ) / 2; + let rspaces = ( ( col_width - cell_width ) as f32 / 2 as f32 ).round() as usize + cell_width - slice_width; + + if lspaces > 0 + { + write!( c.buf, "{: 0 { - let col = &x.col_descriptors[ icol ]; - let cell_width = x.data[ irow ][ icol ].1[0]; - let width = col.width; - let md_index = [ islice, icol, irow as usize ]; - let slice = x.slices[ x.slices_dim.md_offset( md_index ) ]; - - // println!( "md_index : {md_index:?} | md_offset : {} | slice : {slice}", x.slices_dim.md_offset( md_index ) ); - - if icol > 0 - { - write!( c.buf, "{}", cell_separator )?; - } - - write!( c.buf, "{}", cell_prefix )?; - - println!( "icol : {icol} | irow : {irow} | width : {width} | cell_width : {cell_width} | slice.len() : {}", slice.len() ); - - let lspaces = if cell_width > width { - 0 - } else { - ( width - cell_width ) / 2 - }; - - let rspaces = if (cell_width > width) || (slice.len() > cell_width) { - 0 - } else { - ( width - cell_width + 1 ) / 2 + cell_width - slice.len() - }; - - // println!( "icol : {icol} | irow : {irow} | width : {width} | cell_width : {cell_width} | lspaces : {lspaces} | rspaces : {rspaces}" ); - - if lspaces > 0 - { - write!( c.buf, "{: 0 - { - write!( c.buf, "{:>width$}", " ", width = rspaces )?; - } - - write!( c.buf, "{}", cell_postfix )?; + write!( c.buf, "{:>width$}", " ", width = rspaces )?; } - write!( c.buf, "{}", row_postfix )?; + write!( c.buf, "{}", cell_postfix )?; } + write!( c.buf, "{}", row_postfix )?; } Ok(()) } } + +#[ derive( Debug ) ] +struct WrappedCell< 'data > +{ + wrap_width : usize, + content : Cow< 'data, str > +} + +fn wrap_text< 'data > +( + data: &'data Vec< ( usize, Vec< Cow< 'data, str > > ) >, + limit: usize +) +-> Vec< ( usize, Vec< WrappedCell< 'data > > ) > +{ + let mut new_data = Vec::new(); + + for ( id, row ) in data + { + let unwrapped_text : Vec< Vec< Cow< 'data, str > > > = row.iter().map( |c| string::lines_with_limit( c.as_ref(), limit ).map( Cow::from ).collect() ).collect(); + + let max_rows = unwrapped_text.iter().map( Vec::len ).max().unwrap_or(0); + + let mut transposed : Vec< Vec< WrappedCell< 'data > > > = Vec::new(); + + if max_rows == 0 + { + transposed.push( vec![] ); + } + + for i in 0..max_rows + { + let mut row_vec : Vec< WrappedCell< 'data > > = Vec::new(); + + for col_lines in &unwrapped_text + { + if col_lines.len() > i + { + let wrap_width = col_lines.iter().map( |c| c.len() ).max().unwrap_or(0); + row_vec.push( WrappedCell { wrap_width , content : col_lines[ i ].clone() } ); + } + else + { + row_vec.push( WrappedCell { wrap_width : 0, content : Cow::from( "" ) } ); + } + } + + transposed.push( row_vec ); + } + + for row in transposed + { + new_data.push( ( *id, row ) ); + } + } + + new_data +} \ No newline at end of file diff --git a/module/core/format_tools/src/format/print.rs b/module/core/format_tools/src/format/print.rs index 78ac91b294..c26d920f15 100644 --- a/module/core/format_tools/src/format/print.rs +++ b/module/core/format_tools/src/format/print.rs @@ -7,12 +7,7 @@ mod private { use crate::*; - use md_math::MdOffset; - use std:: - { - borrow::Cow, - collections::HashMap, - }; + use std::borrow::Cow; use core:: { fmt, @@ -225,27 +220,6 @@ mod private } - /// A struct for extracting and organizing row of table data for formatting. - - #[ derive( Debug, Default ) ] - pub struct RowDescriptor - { - pub irow : usize, - pub height : usize, - pub typ : LineType, - pub vis : bool, - } - - /// A struct for extracting and organizing row of table data for formatting. - - #[ derive( Debug, Default ) ] - pub struct ColDescriptor< 'label > - { - pub icol : usize, - pub width : usize, - pub label : &'label str, - } - /// A struct for extracting and organizing table data for formatting. /// /// `InputExtract` holds metadata and content necessary for formatting tables, @@ -259,33 +233,13 @@ mod private pub struct InputExtract< 'data > { - /// Multidimensional size in number of columns per table and number of rows per table. - pub mcells : [ usize ; 2 ], - - /// Multidimensional size in number of visible columns per table and number of visible rows per table. - pub mcells_vis : [ usize ; 2 ], - - /// Multidimensional size in number of character without taking into account grids. - pub mchars : [ usize ; 2 ], - /// Indicates if the table has a header. pub has_header : bool, - /// Descriptors for each column, including optional title, width, and index. - // width, index - pub col_descriptors : Vec< ColDescriptor< 'data > >, - - /// Descriptors for each row, including height. - pub row_descriptors : Vec< RowDescriptor >, - - /// Extracted data for each cell, including string content and size. - // string, size, - pub data : Vec< Vec< ( Cow< 'data, str >, [ usize ; 2 ] ) > >, // xxx : use maybe flat vector - - /// Dimensions of slices for retrieving data from multi-matrix. - pub slices_dim : [ usize ; 3 ], - /// Extracted slices or strings for further processing. - pub slices : Vec< &'data str >, + /// Extracted data for each cell. + /// If the table has a header, then the first row is treated as a header row with column names. + /// Each row is a tuple where the first element is original (unfiltered) row index, and the second are columns. + pub data : Vec< ( usize, Vec< Cow< 'data, str > > ) >, } @@ -299,71 +253,30 @@ mod private /// This function provides an iterator that yields each row descriptor along with its index. /// If the table has a header, the first row is skipped, ensuring that iteration starts from /// the first data row. - /// - /// # Returns - /// - /// An iterator over tuples containing: - /// - `usize`: The index of the row. - /// - `&RowDescriptor`: A reference to the row descriptor. - /// - pub fn rows( & self ) -> impl _IteratorTrait< Item = ( usize, &RowDescriptor ) > + pub fn rows( & self ) -> impl _IteratorTrait< Item = &( usize, Vec< Cow< 'data, str > > ) > { - self.row_descriptors + self.data .iter() - .enumerate() .skip( if self.has_header { 1 } else { 0 } ) } /// Returns an iterator over the header cells, or a default value if no header is present. /// /// This function provides an iterator that yields each cell in the header row. If the table - /// does not have a header, it returns an iterator over default values, which are empty strings - /// with a size of `[0, 1]`. - /// - /// # Returns - /// - /// A boxed iterator yielding tuples containing: - /// - `Cow<'data, str>`: A clone-on-write string representing the cell content. - /// - `[usize; 2]`: An array representing the size of the cell. - /// - pub fn header( & self ) -> Box< dyn Iterator< Item = ( Cow< 'data, str >, [ usize ; 2 ] ) > + '_ > + /// does not have a header, it returns an iterator over default values, which are empty strings. + pub fn header( & self ) -> Box< dyn Iterator< Item = Cow< 'data, str > > + '_ > { - if self.has_header + if self.has_header && self.data.len() != 0 { - Box::new( self.data[ 0 ].iter().cloned() ) + Box::new( self.data[ 0 ].1.iter().cloned() ) } else { - Box::new( std::iter::repeat( ( Cow::Borrowed( "" ), [ 0, 1 ] ) ).take( self.mcells[ 0 ] ) ) + let col_count = if self.data.len() == 0 { 0 } else { self.data[0].1.len() }; + Box::new( std::iter::repeat( Cow::Borrowed( "" ) ).take( col_count ) ) } } - /// Returns a slice from the header, or an empty string if no header is present. - /// - /// This function retrieves a specific slice from the header row based on the provided indices. - /// If the table does not have a header, it returns an empty string. - /// - /// # Arguments - /// - /// - `islice`: The slice index within the header cell. - /// - `icol`: The column index within the header row. - /// - /// # Returns - /// - /// A string slice representing the header content at the specified indices. - /// - pub fn header_slice( & self, islice : usize, icol : usize ) -> & str - { - if self.has_header - { - let md_index = [ islice, icol, 0 ]; - self.slices[ self.slices_dim.md_offset( md_index ) ] - } - else - { - "" - } - } /// Extract input data from and collect it in a format consumable by output formatter. pub fn extract< 't, 'context, Table, RowKey, Row, CellKey> ( @@ -379,128 +292,56 @@ mod private Table : TableRows< RowKey = RowKey, Row = Row, CellKey = CellKey >, Table : TableHeader< CellKey = CellKey >, RowKey : table::RowKey, - Row : Cells< CellKey> + 'data, + Row : Cells< CellKey > + 'data, CellKey : table::CellKey + ?Sized + 'data, // CellRepr : table::CellRepr, { - use md_math::MdOffset; - - // let mcells = table.mcells(); - let mut mcells_vis = [ 0 ; 2 ]; - let mut mcells = [ 0 ; 2 ]; - let mut mchars = [ 0 ; 2 ]; - - // key width, index - let mut key_to_ikey : HashMap< &'t CellKey, usize > = HashMap::new(); - - let mut col_descriptors : Vec< ColDescriptor< '_ > > = Vec::with_capacity( mcells[ 0 ] ); - let mut row_descriptors : Vec< RowDescriptor > = Vec::with_capacity( mcells[ 1 ] ); let mut has_header = false; - let mut data : Vec< Vec< ( Cow< 't, str >, [ usize ; 2 ] ) > > = Vec::new(); + let mut data : Vec< ( usize, Vec< Cow< 't, str > > ) > = Vec::new(); let rows = table.rows(); - let mut irow : usize = 0; - let filter_col_need_args = filter_col.need_args(); - // let filter_row_need_args = filter_row.need_args(); - let mut row_add = | row_iter : &'_ mut dyn _IteratorTrait< Item = ( &'t CellKey, Cow< 't, str > ) >, typ : LineType | + let mut row_add = | id: usize, row_iter : &'_ mut dyn _IteratorTrait< Item = ( &'t CellKey, Cow< 't, str > ) > | { - - irow = row_descriptors.len(); - let vis = true; - let height = 1; - let mut row = RowDescriptor { height, typ, vis, irow }; - let mut ncol = 0; - let mut ncol_vis = 0; - - let fields : Vec< ( Cow< 't, str >, [ usize ; 2 ] ) > = row_iter + let fields : Vec< Cow< 't, str > > = row_iter .filter_map ( | ( key, val ) | { - let l = col_descriptors.len(); - - ncol += 1; - - if filter_col_need_args - { - if !filter_col.filter_col( key.borrow() ) - { - return None; - } - } - else + if !filter_col.filter_col( key.borrow() ) { - if !filter_col.filter_col( "" ) - { - return None; - } + return None; } - ncol_vis += 1; - - let sz = string::size( &val ); - - key_to_ikey - .entry( key ) - .and_modify( | icol | - { - let col = &mut col_descriptors[ *icol ]; - col.width = col.width.max( sz[ 0 ] ); - col.label = ""; - }) - .or_insert_with( || - { - let icol = l; - let width = sz[ 0 ]; - let col = ColDescriptor { width, icol, label : "" }; - col_descriptors.push( col ); - icol - }); - - row.height = row.height.max( sz[ 1 ] ); - return Some( ( val, sz ) ); + return Some( val ); } ) .collect(); - mcells[ 0 ] = mcells[ 0 ].max( ncol ); - mcells_vis[ 0 ] = mcells_vis[ 0 ].max( ncol_vis ); - - row.vis = filter_row.filter_row( typ, irow, &fields ); - if row.vis + if filter_row.filter_row( &fields ) { - mcells_vis[ 1 ] += 1; + data.push( ( id, fields ) ); } - mcells[ 1 ] += 1; - - row_descriptors.push( row ); - data.push( fields ); - }; - // process header first + let mut row_id = 0; if let Some( header ) = table.header() { - rows.len().checked_add( 1 ).expect( "Table has too many rows" ); - // assert!( header.len() <= usize::MAX, "Header of a table has too many cells" ); has_header = true; - let mut row2 = header.map( | ( key, title ) | + let mut row2 = header.map( | ( key, title ) | { ( key, Cow::Borrowed( title ) ) }); - row_add( &mut row2, LineType::Header ); + row_add( row_id, &mut row2 ); + + row_id += 1; } - // Collect rows - // key, string, size, for row in rows { - // assert!( row.cells().len() <= usize::MAX, "Row of a table has too many cells" ); - let mut row2 = row .cells() .map @@ -524,75 +365,17 @@ mod private } ); - row_add( &mut row2, LineType::Regular ); - } - - // calculate size in chars - - mchars[ 0 ] = col_descriptors.iter().fold( 0, | acc, col | acc + col.width ); - mchars[ 1 ] = row_descriptors.iter().fold( 0, | acc, row | acc + if row.vis { row.height } else { 0 } ); - - // cook slices multi-matrix - - let mut slices_dim = [ 1, mcells[ 0 ], mcells[ 1 ] ]; - slices_dim[ 0 ] = row_descriptors - .iter() - .fold( 0, | acc : usize, row | acc.max( row.height ) ) - ; - - let slices_len = slices_dim[ 0 ] * slices_dim[ 1 ] * slices_dim[ 2 ]; - let slices : Vec< &str > = vec![ "" ; slices_len ]; + row_add( row_id, &mut row2 ); - // assert_eq!( mcells, mcells, r#"Incorrect multidimensional size of table - // mcells <> mcells - // {mcells:?} <> {mcells:?}"# ); - // println!( "mcells : {mcells:?} | mcells : {mcells:?} | mcells_vis : {mcells_vis:?}" ); + row_id += 1; + } - let mut x = InputExtract::< '_ > + let x = InputExtract::< '_ > { - mcells, - mcells_vis, - mchars, - col_descriptors, - row_descriptors, data, has_header, - slices_dim, - slices, }; - // extract slices - - let mut slices : Vec< &str > = vec![]; - std::mem::swap( &mut x.slices, &mut slices ); - - let mut irow : isize = -1; - for row_data in x.data.iter() - { - - irow += 1; - - for icol in 0 .. x.col_descriptors.len() - { - let cell = &row_data[ icol ]; - string::lines( cell.0.as_ref() ) - .enumerate() - .for_each( | ( layer, s ) | - { - let md_index = [ layer, icol, irow as usize ]; - slices[ x.slices_dim.md_offset( md_index ) ] = s; - }) - ; - if irow == 0 - { - x.col_descriptors[ icol ].label = cell.0.as_ref(); - } - } - - } - - std::mem::swap( &mut x.slices, &mut slices ); - return callback( &x ); } 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, }; } diff --git a/module/core/format_tools/tests/inc/format_records_test.rs b/module/core/format_tools/tests/inc/format_records_test.rs index 72f23a5ff5..d6e2b16e70 100644 --- a/module/core/format_tools/tests/inc/format_records_test.rs +++ b/module/core/format_tools/tests/inc/format_records_test.rs @@ -281,9 +281,9 @@ fn filter_row_callback() format.row_separator = "\n".into(); let mut printer = print::Printer::with_format( &format ); - printer.filter_row = &| _typ, irow, _row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] | + printer.filter_row = &| row : &[ Cow< '_, str > ] | { - irow != 1 + row[0] != "1" }; let as_table = AsTable::new( &test_objects ); diff --git a/module/core/format_tools/tests/inc/format_table_test.rs b/module/core/format_tools/tests/inc/format_table_test.rs index eb8a3b17dd..4cb82a3286 100644 --- a/module/core/format_tools/tests/inc/format_table_test.rs +++ b/module/core/format_tools/tests/inc/format_table_test.rs @@ -295,9 +295,9 @@ fn filter_row_callback() format.row_separator = "\n".into(); let mut printer = print::Printer::with_format( &format ); - printer.filter_row = &| _typ, irow, _row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] | + printer.filter_row = &| row : &[ Cow< '_, str > ] | { - irow != 1 + row[0] != "1" }; let as_table = AsTable::new( &test_objects ); diff --git a/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs b/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs index bd9947cd71..9491237b6d 100644 --- a/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs +++ b/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs @@ -14,7 +14,7 @@ use the_module:: use std:: { - // fmt, + fmt, // collections::HashMap, borrow::Cow, }; diff --git a/module/move/assistant/src/bin/main.rs b/module/move/assistant/src/bin/main.rs index adeeaf150f..419030d03b 100644 --- a/module/move/assistant/src/bin/main.rs +++ b/module/move/assistant/src/bin/main.rs @@ -26,7 +26,7 @@ async fn main() -> Result< (), Box< dyn Error > > let secret = Secret::load()?; - let client = client::client( &secret )?; + let client = client( &secret )?; let cli = Cli::parse();