@@ -493,6 +493,115 @@ pub fn render_table(
493493 lines
494494}
495495
496+ /// Renders a table as a simple ASCII code block without outer borders.
497+ ///
498+ /// This produces a cleaner, minimal table format suitable for code blocks:
499+ /// ```text
500+ /// Header 1 | Header 2 | Header 3
501+ /// ---------+-----------+---------
502+ /// Cell 1 | Cell 2 | Cell 3
503+ /// Cell 4 | Cell 5 | Cell 6
504+ /// ```
505+ ///
506+ /// # Arguments
507+ /// * `table` - The table to render
508+ /// * `style` - Style for all text (headers and cells use the same style)
509+ /// * `max_width` - Maximum total width for the table
510+ ///
511+ /// # Returns
512+ /// A vector of `Line`s ready for display in ratatui.
513+ pub fn render_table_simple ( table : & Table , style : Style , max_width : u16 ) -> Vec < Line < ' static > > {
514+ // Handle empty table
515+ if table. is_empty ( ) {
516+ return Vec :: new ( ) ;
517+ }
518+
519+ // Clone and calculate widths if not already done
520+ let mut table = table. clone ( ) ;
521+ if table. column_widths . iter ( ) . all ( |& w| w == 0 ) {
522+ table. calculate_column_widths ( max_width) ;
523+ }
524+
525+ // Handle case where we still have no columns
526+ if table. num_columns ( ) == 0 {
527+ return Vec :: new ( ) ;
528+ }
529+
530+ let widths = & table. column_widths ;
531+ let alignments = & table. alignments ;
532+
533+ let mut lines = Vec :: new ( ) ;
534+
535+ // Header row (if present)
536+ if !table. headers . is_empty ( ) {
537+ lines. push ( render_simple_row ( & table. headers , widths, alignments, style) ) ;
538+
539+ // Header separator line: ---+---+---
540+ lines. push ( render_simple_separator ( widths, style) ) ;
541+ }
542+
543+ // Data rows
544+ for row in & table. rows {
545+ lines. push ( render_simple_row ( row, widths, alignments, style) ) ;
546+ }
547+
548+ lines
549+ }
550+
551+ /// Renders a simple row without outer borders.
552+ ///
553+ /// Format: `content | content | content`
554+ fn render_simple_row (
555+ cells : & [ TableCell ] ,
556+ widths : & [ usize ] ,
557+ alignments : & [ Alignment ] ,
558+ style : Style ,
559+ ) -> Line < ' static > {
560+ let mut spans = Vec :: new ( ) ;
561+
562+ for ( i, width) in widths. iter ( ) . enumerate ( ) {
563+ // Get cell content or empty string if missing
564+ let cell = cells. get ( i) ;
565+ let content = cell. map ( |c| c. content . as_str ( ) ) . unwrap_or ( "" ) ;
566+ let alignment = alignments. get ( i) . copied ( ) . unwrap_or_default ( ) ;
567+
568+ // Truncate and align
569+ let truncated = truncate_with_ellipsis ( content, * width) ;
570+ let aligned = align_text ( & truncated, * width, alignment) ;
571+
572+ // Add cell content with padding
573+ spans. push ( Span :: styled ( format ! ( " {} " , aligned) , style) ) ;
574+
575+ // Add separator between columns (not after last)
576+ if i < widths. len ( ) - 1 {
577+ spans. push ( Span :: styled ( "|" , style) ) ;
578+ }
579+ }
580+
581+ Line :: from ( spans)
582+ }
583+
584+ /// Renders a simple separator line for the header.
585+ ///
586+ /// Format: `---+---+---`
587+ fn render_simple_separator ( widths : & [ usize ] , style : Style ) -> Line < ' static > {
588+ let mut spans = Vec :: new ( ) ;
589+
590+ for ( i, & width) in widths. iter ( ) . enumerate ( ) {
591+ // Each column segment: padding + content + padding (same as cell)
592+ let segment_width = width + 2 ; // +2 for the spaces on each side
593+ let segment: String = std:: iter:: repeat ( '-' ) . take ( segment_width) . collect ( ) ;
594+ spans. push ( Span :: styled ( segment, style) ) ;
595+
596+ // Add separator between columns (not after last)
597+ if i < widths. len ( ) - 1 {
598+ spans. push ( Span :: styled ( "+" , style) ) ;
599+ }
600+ }
601+
602+ Line :: from ( spans)
603+ }
604+
496605/// Renders a horizontal border line.
497606///
498607/// # Arguments
@@ -996,4 +1105,115 @@ mod tests {
9961105 assert_eq ! ( cell. content, "" ) ;
9971106 assert_eq ! ( cell. width( ) , 0 ) ;
9981107 }
1108+
1109+ // ============================================================
1110+ // Simple Table Tests
1111+ // ============================================================
1112+
1113+ #[ test]
1114+ fn test_simple_table_empty ( ) {
1115+ let table = Table :: default ( ) ;
1116+ let lines = render_table_simple ( & table, Style :: default ( ) , 80 ) ;
1117+ assert ! ( lines. is_empty( ) ) ;
1118+ }
1119+
1120+ #[ test]
1121+ fn test_simple_table_basic ( ) {
1122+ let mut builder = TableBuilder :: new ( ) ;
1123+ builder. start_header ( ) ;
1124+ builder. add_cell ( "Header" . to_string ( ) ) ;
1125+ builder. end_header ( ) ;
1126+
1127+ builder. start_row ( ) ;
1128+ builder. add_cell ( "Value" . to_string ( ) ) ;
1129+ builder. end_row ( ) ;
1130+
1131+ let table = builder. build ( ) ;
1132+ let lines = render_table_simple ( & table, Style :: default ( ) , 80 ) ;
1133+
1134+ // Should have: header, separator, data row = 3 lines (no outer borders)
1135+ assert_eq ! ( lines. len( ) , 3 ) ;
1136+ }
1137+
1138+ #[ test]
1139+ fn test_simple_table_multiple_columns ( ) {
1140+ let mut builder = TableBuilder :: new ( ) ;
1141+ builder. start_header ( ) ;
1142+ builder. add_cell ( "A" . to_string ( ) ) ;
1143+ builder. add_cell ( "B" . to_string ( ) ) ;
1144+ builder. add_cell ( "C" . to_string ( ) ) ;
1145+ builder. end_header ( ) ;
1146+
1147+ builder. start_row ( ) ;
1148+ builder. add_cell ( "1" . to_string ( ) ) ;
1149+ builder. add_cell ( "2" . to_string ( ) ) ;
1150+ builder. add_cell ( "3" . to_string ( ) ) ;
1151+ builder. end_row ( ) ;
1152+
1153+ let table = builder. build ( ) ;
1154+ let lines = render_table_simple ( & table, Style :: default ( ) , 80 ) ;
1155+
1156+ // Check that separator line contains + characters
1157+ let separator_content: String = lines[ 1 ] . spans . iter ( ) . map ( |s| & * s. content ) . collect ( ) ;
1158+ assert ! (
1159+ separator_content. contains( '+' ) ,
1160+ "Separator should contain + for column separation"
1161+ ) ;
1162+ assert ! (
1163+ separator_content. contains( '-' ) ,
1164+ "Separator should contain - for dashes"
1165+ ) ;
1166+ }
1167+
1168+ #[ test]
1169+ fn test_simple_table_without_headers ( ) {
1170+ let mut builder = TableBuilder :: new ( ) ;
1171+
1172+ builder. start_row ( ) ;
1173+ builder. add_cell ( "A" . to_string ( ) ) ;
1174+ builder. add_cell ( "B" . to_string ( ) ) ;
1175+ builder. end_row ( ) ;
1176+
1177+ builder. start_row ( ) ;
1178+ builder. add_cell ( "C" . to_string ( ) ) ;
1179+ builder. add_cell ( "D" . to_string ( ) ) ;
1180+ builder. end_row ( ) ;
1181+
1182+ let table = builder. build ( ) ;
1183+ let lines = render_table_simple ( & table, Style :: default ( ) , 80 ) ;
1184+
1185+ // Should have: 2 data rows only (no header, no separator)
1186+ assert_eq ! ( lines. len( ) , 2 ) ;
1187+ }
1188+
1189+ #[ test]
1190+ fn test_simple_table_format ( ) {
1191+ let mut builder = TableBuilder :: new ( ) ;
1192+ builder. start_header ( ) ;
1193+ builder. add_cell ( "Name" . to_string ( ) ) ;
1194+ builder. add_cell ( "Value" . to_string ( ) ) ;
1195+ builder. end_header ( ) ;
1196+
1197+ builder. start_row ( ) ;
1198+ builder. add_cell ( "foo" . to_string ( ) ) ;
1199+ builder. add_cell ( "bar" . to_string ( ) ) ;
1200+ builder. end_row ( ) ;
1201+
1202+ let table = builder. build ( ) ;
1203+ let lines = render_table_simple ( & table, Style :: default ( ) , 80 ) ;
1204+
1205+ // First line should be header with | separator
1206+ let header_content: String = lines[ 0 ] . spans . iter ( ) . map ( |s| & * s. content ) . collect ( ) ;
1207+ assert ! (
1208+ header_content. contains( '|' ) ,
1209+ "Header should have | separator between columns"
1210+ ) ;
1211+
1212+ // Second line should be separator with -+-
1213+ let separator_content: String = lines[ 1 ] . spans . iter ( ) . map ( |s| & * s. content ) . collect ( ) ;
1214+ assert ! (
1215+ separator_content. contains( '+' ) ,
1216+ "Separator should have + at column intersections"
1217+ ) ;
1218+ }
9991219}
0 commit comments