From 1ba01691b880d8eb8cafc53315d0b78d15dcfdda Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Wed, 3 Jul 2024 16:43:20 +0300 Subject: [PATCH] Fix issue with head on separation lines --- crates/nu-table/src/table.rs | 213 +++++++++++++++++++++++++++-------- 1 file changed, 166 insertions(+), 47 deletions(-) diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index bdaf7fb6c3..11e7b2fb1b 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -17,8 +17,8 @@ use tabled::{ }, }, settings::{ - formatting::AlignmentStrategy, object::Segment, peaker::Peaker, themes::ColumnNames, Color, - Modify, Padding, Settings, TableOption, Width, + formatting::AlignmentStrategy, object::Segment, peaker::Peaker, themes::ColumnNames, + width::Truncate, Color, Modify, Padding, Settings, TableOption, Width, }, Table, }; @@ -269,20 +269,51 @@ fn set_indent(table: &mut Table, left: usize, right: usize) { fn set_border_head(table: &mut Table, with_footer: bool, wctrl: TableWidthCtrl) { if with_footer { let count_rows = table.count_rows(); + let last_row_index = count_rows - 1; + + // note: funnily last and row must be equal at this point but we do not rely on it just in case. + + let mut first_row = GetRow(0, Vec::new()); + let mut head_settings = GetRowSettings(0, AlignmentHorizontal::Left, None); + let mut last_row = GetRow(last_row_index, Vec::new()); + + table.with(&mut first_row); + table.with(&mut head_settings); + table.with(&mut last_row); + table.with( Settings::default() .with(wctrl) .with(StripColorFromRow(0)) .with(StripColorFromRow(count_rows - 1)) - .with(HeaderMove((0, 0), true)) - .with(HeaderMove((count_rows - 1 - 1, count_rows - 1), false)), + .with(MoveRowNext::new(0, 0)) + .with(MoveRowPrev::new(last_row_index - 1, last_row_index)) + .with(SetLineHeaders::new( + 0, + first_row.1, + head_settings.1, + head_settings.2.clone(), + )) + .with(SetLineHeaders::new( + last_row_index, + last_row.1, + head_settings.1, + head_settings.2, + )), ); } else { + let mut row = GetRow(0, Vec::new()); + let mut row_opts = GetRowSettings(0, AlignmentHorizontal::Left, None); + + table.with(&mut row); + table.with(&mut row_opts); + table.with( Settings::default() .with(wctrl) .with(StripColorFromRow(0)) - .with(HeaderMove((0, 0), true)), + .with(MoveRowNext::new(0, 0)) + .with(SetLineHeaders::new(0, row.1, row_opts.1, row_opts.2)), ); } } @@ -729,50 +760,154 @@ fn build_width(records: &NuRecords, pad: usize) -> Vec { widths } -struct HeaderMove((usize, usize), bool); +struct GetRow(usize, Vec); -impl TableOption, ColoredConfig> for HeaderMove { +impl TableOption, ColoredConfig> for &mut GetRow { + fn change( + self, + recs: &mut NuRecords, + _: &mut ColoredConfig, + _: &mut CompleteDimensionVecRecords<'_>, + ) { + let row = self.0; + self.1 = recs[row].iter().map(|c| c.as_ref().to_owned()).collect(); + } +} + +struct GetRowSettings(usize, AlignmentHorizontal, Option); + +impl TableOption, ColoredConfig> + for &mut GetRowSettings +{ + fn change( + self, + _: &mut NuRecords, + cfg: &mut ColoredConfig, + _: &mut CompleteDimensionVecRecords<'_>, + ) { + let row = self.0; + self.1 = *cfg.get_alignment_horizontal(Entity::Row(row)); + self.2 = cfg + .get_colors() + .get_color((row, 0)) + .cloned() + .map(Color::from); + } +} + +struct SetLineHeaders { + line: usize, + columns: Vec, + alignment: AlignmentHorizontal, + color: Option, +} + +impl SetLineHeaders { + fn new( + line: usize, + columns: Vec, + alignment: AlignmentHorizontal, + color: Option, + ) -> Self { + Self { + line, + columns, + alignment, + color, + } + } +} + +impl TableOption, ColoredConfig> for SetLineHeaders { fn change( self, recs: &mut NuRecords, cfg: &mut ColoredConfig, dims: &mut CompleteDimensionVecRecords<'_>, ) { - let (row, line) = self.0; - if self.1 { - move_header_on_next(recs, cfg, dims, row, line); - } else { - move_header_on_prev(recs, cfg, dims, row, line); - } + let mut columns = self.columns; + match dims.get_widths() { + Some(widths) => { + columns = columns + .into_iter() + .zip(widths) + .map(|(s, width)| Truncate::truncate_text(&s, *width).into_owned()) + .collect(); + } + None => { + // we don't have widths cached; which means that NO widtds adjustmens were done + // which means we are OK to leave columns as they are. + } + }; + + set_column_names( + recs, + cfg, + dims, + columns, + self.line, + self.alignment, + self.color, + ) } } -fn move_header_on_next( - recs: &mut NuRecords, - cfg: &mut ColoredConfig, - dims: &mut CompleteDimensionVecRecords<'_>, +struct MoveRowNext { row: usize, line: usize, -) { +} + +impl MoveRowNext { + fn new(row: usize, line: usize) -> Self { + Self { row, line } + } +} + +struct MoveRowPrev { + row: usize, + line: usize, +} + +impl MoveRowPrev { + fn new(row: usize, line: usize) -> Self { + Self { row, line } + } +} + +impl TableOption, ColoredConfig> for MoveRowNext { + fn change( + self, + recs: &mut NuRecords, + cfg: &mut ColoredConfig, + _: &mut CompleteDimensionVecRecords<'_>, + ) { + row_shift_next(recs, cfg, self.row, self.line); + } +} + +impl TableOption, ColoredConfig> for MoveRowPrev { + fn change( + self, + recs: &mut NuRecords, + cfg: &mut ColoredConfig, + _: &mut CompleteDimensionVecRecords<'_>, + ) { + row_shift_prev(recs, cfg, self.row, self.line); + } +} + +fn row_shift_next(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, line: usize) { let count_rows = recs.count_rows(); let count_columns = recs.count_columns(); let has_line = cfg.has_horizontal(line, count_rows); let has_next_line = cfg.has_horizontal(line + 1, count_rows); - let align = *cfg.get_alignment_horizontal(Entity::Row(row)); - let color = cfg - .get_colors() - .get_color((row, 0)) - .cloned() - .map(Color::from); - if !has_line && !has_next_line { return; } if !has_line { - let head = remove_row(recs, row); + let _ = remove_row(recs, row); let count_rows = recs.count_rows(); - set_column_names(recs, cfg, dims, head, line, align, color); shift_alignments_down(cfg, row, count_rows, count_columns); shift_colors_down(cfg, row, count_rows, count_columns); shift_lines_up(cfg, count_rows, &[line + 1]); @@ -780,47 +915,31 @@ fn move_header_on_next( return; } - let head = remove_row(recs, row); + let _ = remove_row(recs, row); let count_rows = recs.count_rows(); - set_column_names(recs, cfg, dims, head, line, align, color); shift_alignments_down(cfg, row, count_rows, count_columns); shift_colors_down(cfg, row, count_rows, count_columns); remove_lines(cfg, count_rows, &[line + 1]); shift_lines_up(cfg, count_rows, &[count_rows]); } -fn move_header_on_prev( - recs: &mut NuRecords, - cfg: &mut ColoredConfig, - dims: &mut CompleteDimensionVecRecords<'_>, - row: usize, - line: usize, -) { +fn row_shift_prev(recs: &mut NuRecords, cfg: &mut ColoredConfig, row: usize, line: usize) { let count_rows = recs.count_rows(); let count_columns = recs.count_columns(); let has_line = cfg.has_horizontal(line, count_rows); let has_prev_line = cfg.has_horizontal(line - 1, count_rows); - let align = *cfg.get_alignment_horizontal(Entity::Row(row)); - let color = cfg - .get_colors() - .get_color((row, 0)) - .cloned() - .map(Color::from); - if !has_line && !has_prev_line { return; } if !has_line { - let head = remove_row(recs, row); + let _ = remove_row(recs, row); // shift_lines_down(table, &[line - 1]); - set_column_names(recs, cfg, dims, head, line - 1, align, color); return; } - let head = remove_row(recs, row); + let _ = remove_row(recs, row); let count_rows = count_rows - 1; - set_column_names(recs, cfg, dims, head, line - 1, align, color); shift_alignments_down(cfg, row, count_rows, count_columns); shift_colors_down(cfg, row, count_rows, count_columns); remove_lines(cfg, count_rows, &[line - 1]);