nu-table: Fix padding 0 width issues (#10011)

close #10001

cc: @fdncred @amtoine 

note: make sure you rebase/squash

---------

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
Maxim Zhiburt 2023-08-15 03:07:34 +03:00 committed by GitHub
parent 435348aa61
commit 696b2cda4a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 45 deletions

View file

@ -2596,16 +2596,16 @@ fn table_expand_padding_not_default() {
let actual = nu!("$env.config.table.padding = 5; [[a b, c]; [1 2 3] [4 5 [1 2 3]]] | table -e"); let actual = nu!("$env.config.table.padding = 5; [[a b, c]; [1 2 3] [4 5 [1 2 3]]] | table -e");
assert_eq!( assert_eq!(
actual.out, actual.out,
"╭───────────┬───────────┬───────────┬───────────────────────────────────╮\ "╭──────────────────────────┬────────────────────────────────────────────────╮\
# a b c \ # a b c \
\ \
0 1 2 3 \ 0 1 2 3 \
1 4 5 \ 1 4 5 \
0 1 \ 0 1 \
1 2 \ 1 2 \
2 3 \ 2 3 \
\ \
" "
); );
} }

View file

@ -26,13 +26,13 @@ use tabled::{
/// NuTable is a table rendering implementation. /// NuTable is a table rendering implementation.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct NuTable { pub struct NuTable {
data: NuTableData, data: NuRecords,
styles: Styles, styles: Styles,
alignments: Alignments, alignments: Alignments,
indent: (usize, usize), indent: (usize, usize),
} }
type NuTableData = VecRecords<NuTableCell>; pub type NuRecords = VecRecords<NuTableCell>;
pub type NuTableCell = CellInfo<String>; pub type NuTableCell = CellInfo<String>;
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@ -158,7 +158,7 @@ impl NuTable {
/// Return a total table width. /// Return a total table width.
pub fn total_width(&self, config: &NuTableConfig) -> usize { pub fn total_width(&self, config: &NuTableConfig) -> usize {
let config = get_config(&config.theme, false, None); let config = get_config(&config.theme, false, None);
let widths = build_width(&self.data); let widths = build_width(&self.data, self.indent.0 + self.indent.1);
get_total_width2(&widths, &config) get_total_width2(&widths, &config)
} }
} }
@ -200,7 +200,7 @@ impl Default for NuTableConfig {
} }
fn build_table( fn build_table(
mut data: NuTableData, mut data: NuRecords,
cfg: NuTableConfig, cfg: NuTableConfig,
alignments: Alignments, alignments: Alignments,
styles: Styles, styles: Styles,
@ -211,7 +211,8 @@ fn build_table(
return Some(String::new()); return Some(String::new());
} }
let widths = maybe_truncate_columns(&mut data, &cfg.theme, termwidth); let pad = indent.0 + indent.1;
let widths = maybe_truncate_columns(&mut data, &cfg.theme, termwidth, pad);
if widths.is_empty() { if widths.is_empty() {
return None; return None;
} }
@ -224,7 +225,7 @@ fn build_table(
} }
fn draw_table( fn draw_table(
data: NuTableData, data: NuRecords,
alignments: Alignments, alignments: Alignments,
styles: Styles, styles: Styles,
widths: Vec<usize>, widths: Vec<usize>,
@ -437,9 +438,10 @@ fn table_trim_columns(
} }
fn maybe_truncate_columns( fn maybe_truncate_columns(
data: &mut NuTableData, data: &mut NuRecords,
theme: &TableTheme, theme: &TableTheme,
termwidth: usize, termwidth: usize,
pad: usize,
) -> Vec<usize> { ) -> Vec<usize> {
const TERMWIDTH_THRESHOLD: usize = 120; const TERMWIDTH_THRESHOLD: usize = 120;
@ -449,20 +451,21 @@ fn maybe_truncate_columns(
truncate_columns_by_content truncate_columns_by_content
}; };
truncate(data, theme, termwidth) truncate(data, theme, pad, termwidth)
} }
// VERSION where we are showing AS LITTLE COLUMNS AS POSSIBLE but WITH AS MUCH CONTENT AS POSSIBLE. // VERSION where we are showing AS LITTLE COLUMNS AS POSSIBLE but WITH AS MUCH CONTENT AS POSSIBLE.
fn truncate_columns_by_content( fn truncate_columns_by_content(
data: &mut NuTableData, data: &mut NuRecords,
theme: &TableTheme, theme: &TableTheme,
pad: usize,
termwidth: usize, termwidth: usize,
) -> Vec<usize> { ) -> Vec<usize> {
const MIN_ACCEPTABLE_WIDTH: usize = 3; const MIN_ACCEPTABLE_WIDTH: usize = 3;
const TRAILING_COLUMN_WIDTH: usize = 5; const TRAILING_COLUMN_WIDTH: usize = 5;
let config = get_config(theme, false, None); let config = get_config(theme, false, None);
let mut widths = build_width(&*data); let mut widths = build_width(&*data, pad);
let total_width = get_total_width2(&widths, &config); let total_width = get_total_width2(&widths, &config);
if total_width <= termwidth { if total_width <= termwidth {
return widths; return widths;
@ -516,7 +519,7 @@ fn truncate_columns_by_content(
if can_be_squeezed { if can_be_squeezed {
push_empty_column(data); push_empty_column(data);
widths.push(3 + 2); widths.push(3 + pad);
} else { } else {
if data.count_columns() == 1 { if data.count_columns() == 1 {
return vec![]; return vec![];
@ -525,7 +528,7 @@ fn truncate_columns_by_content(
truncate_columns(data, data.count_columns() - 1); truncate_columns(data, data.count_columns() - 1);
push_empty_column(data); push_empty_column(data);
widths.pop(); widths.pop();
widths.push(3 + 2); widths.push(3 + pad);
} }
widths widths
@ -533,15 +536,16 @@ fn truncate_columns_by_content(
// VERSION where we are showing AS MANY COLUMNS AS POSSIBLE but as a side affect they MIGHT CONTAIN AS LITTLE CONTENT AS POSSIBLE // VERSION where we are showing AS MANY COLUMNS AS POSSIBLE but as a side affect they MIGHT CONTAIN AS LITTLE CONTENT AS POSSIBLE
fn truncate_columns_by_columns( fn truncate_columns_by_columns(
data: &mut NuTableData, data: &mut NuRecords,
theme: &TableTheme, theme: &TableTheme,
pad: usize,
termwidth: usize, termwidth: usize,
) -> Vec<usize> { ) -> Vec<usize> {
const ACCEPTABLE_WIDTH: usize = 10 + 2; let acceptable_width = 10 + pad;
const TRAILING_COLUMN_WIDTH: usize = 3 + 2; let trailing_column_width = 3 + pad;
let config = get_config(theme, false, None); let config = get_config(theme, false, None);
let mut widths = build_width(&*data); let mut widths = build_width(&*data, pad);
let total_width = get_total_width2(&widths, &config); let total_width = get_total_width2(&widths, &config);
if total_width <= termwidth { if total_width <= termwidth {
return widths; return widths;
@ -550,7 +554,7 @@ fn truncate_columns_by_columns(
let widths_total = widths.iter().sum::<usize>(); let widths_total = widths.iter().sum::<usize>();
let min_widths = widths let min_widths = widths
.iter() .iter()
.map(|w| min(*w, ACCEPTABLE_WIDTH)) .map(|w| min(*w, acceptable_width))
.sum::<usize>(); .sum::<usize>();
let mut min_total = total_width - widths_total + min_widths; let mut min_total = total_width - widths_total + min_widths;
@ -564,7 +568,7 @@ fn truncate_columns_by_columns(
i += 1; i += 1;
let column = data.count_columns() - 1 - i; let column = data.count_columns() - 1 - i;
let width = min(widths[column], ACCEPTABLE_WIDTH); let width = min(widths[column], acceptable_width);
min_total -= width; min_total -= width;
if config.get_borders().has_vertical() { if config.get_borders().has_vertical() {
@ -585,9 +589,9 @@ fn truncate_columns_by_columns(
// Append columns with a trailing column // Append columns with a trailing column
let diff = termwidth - min_total; let diff = termwidth - min_total;
if diff > TRAILING_COLUMN_WIDTH { if diff > trailing_column_width {
push_empty_column(data); push_empty_column(data);
widths.push(3 + 2); widths.push(3 + pad);
} else { } else {
if data.count_columns() == 1 { if data.count_columns() == 1 {
return vec![]; return vec![];
@ -596,7 +600,7 @@ fn truncate_columns_by_columns(
truncate_columns(data, data.count_columns() - 1); truncate_columns(data, data.count_columns() - 1);
push_empty_column(data); push_empty_column(data);
widths.pop(); widths.pop();
widths.push(3 + 2); widths.push(3 + pad);
} }
widths widths
@ -631,7 +635,7 @@ fn get_config(theme: &TableTheme, with_header: bool, color: Option<Style>) -> Co
table.get_config().clone() table.get_config().clone()
} }
fn push_empty_column(data: &mut NuTableData) { fn push_empty_column(data: &mut NuRecords) {
let records = std::mem::take(data); let records = std::mem::take(data);
let mut inner: Vec<Vec<_>> = records.into(); let mut inner: Vec<Vec<_>> = records.into();
@ -643,7 +647,7 @@ fn push_empty_column(data: &mut NuTableData) {
*data = VecRecords::new(inner); *data = VecRecords::new(inner);
} }
fn duplicate_row(data: &mut NuTableData, row: usize) { fn duplicate_row(data: &mut NuRecords, row: usize) {
let records = std::mem::take(data); let records = std::mem::take(data);
let mut inner: Vec<Vec<_>> = records.into(); let mut inner: Vec<Vec<_>> = records.into();
@ -653,7 +657,7 @@ fn duplicate_row(data: &mut NuTableData, row: usize) {
*data = VecRecords::new(inner); *data = VecRecords::new(inner);
} }
fn truncate_columns(data: &mut NuTableData, count: usize) { fn truncate_columns(data: &mut NuRecords, count: usize) {
let records = std::mem::take(data); let records = std::mem::take(data);
let mut inner: Vec<Vec<_>> = records.into(); let mut inner: Vec<Vec<_>> = records.into();
@ -693,15 +697,14 @@ impl<R> TableOption<R, CompleteDimensionVecRecords<'_>, ColoredConfig> for SetDi
} }
// it assumes no spans is used. // it assumes no spans is used.
fn build_width(records: &VecRecords<CellInfo<String>>) -> Vec<usize> { fn build_width(records: &NuRecords, pad: usize) -> Vec<usize> {
use tabled::grid::records::vec_records::Cell; use tabled::grid::records::vec_records::Cell;
const PAD: usize = 2;
let count_columns = records.count_columns(); let count_columns = records.count_columns();
let mut widths = vec![0; count_columns]; let mut widths = vec![0; count_columns];
for columns in records.iter_rows() { for columns in records.iter_rows() {
for (col, cell) in columns.iter().enumerate() { for (col, cell) in columns.iter().enumerate() {
let width = Cell::width(cell) + PAD; let width = Cell::width(cell) + pad;
widths[col] = std::cmp::max(widths[col], width); widths[col] = std::cmp::max(widths[col], width);
} }
} }
@ -711,12 +714,10 @@ fn build_width(records: &VecRecords<CellInfo<String>>) -> Vec<usize> {
struct HeaderMove((usize, usize), bool); struct HeaderMove((usize, usize), bool);
impl TableOption<VecRecords<CellInfo<String>>, CompleteDimensionVecRecords<'_>, ColoredConfig> impl TableOption<NuRecords, CompleteDimensionVecRecords<'_>, ColoredConfig> for HeaderMove {
for HeaderMove
{
fn change( fn change(
self, self,
recs: &mut VecRecords<CellInfo<String>>, recs: &mut NuRecords,
cfg: &mut ColoredConfig, cfg: &mut ColoredConfig,
dims: &mut CompleteDimensionVecRecords<'_>, dims: &mut CompleteDimensionVecRecords<'_>,
) { ) {
@ -730,7 +731,7 @@ impl TableOption<VecRecords<CellInfo<String>>, CompleteDimensionVecRecords<'_>,
} }
fn move_header_on_next( fn move_header_on_next(
recs: &mut VecRecords<CellInfo<String>>, recs: &mut NuRecords,
cfg: &mut ColoredConfig, cfg: &mut ColoredConfig,
dims: &mut CompleteDimensionVecRecords<'_>, dims: &mut CompleteDimensionVecRecords<'_>,
row: usize, row: usize,
@ -772,7 +773,7 @@ fn move_header_on_next(
} }
fn move_header_on_prev( fn move_header_on_prev(
recs: &mut VecRecords<CellInfo<String>>, recs: &mut NuRecords,
cfg: &mut ColoredConfig, cfg: &mut ColoredConfig,
dims: &mut CompleteDimensionVecRecords<'_>, dims: &mut CompleteDimensionVecRecords<'_>,
row: usize, row: usize,
@ -857,7 +858,7 @@ fn shift_lines_up(cfg: &mut ColoredConfig, count_rows: usize, lines: &[usize]) {
} }
fn set_column_names( fn set_column_names(
records: &mut VecRecords<CellInfo<String>>, records: &mut NuRecords,
cfg: &mut ColoredConfig, cfg: &mut ColoredConfig,
dims: &mut CompleteDimensionVecRecords<'_>, dims: &mut CompleteDimensionVecRecords<'_>,
head: Vec<String>, head: Vec<String>,
@ -873,7 +874,7 @@ fn set_column_names(
ColumnNames::change(names, records, cfg, dims) ColumnNames::change(names, records, cfg, dims)
} }
fn remove_row(recs: &mut VecRecords<CellInfo<String>>, row: usize) -> Vec<String> { fn remove_row(recs: &mut NuRecords, row: usize) -> Vec<String> {
let count_columns = recs.count_columns(); let count_columns = recs.count_columns();
let columns = (0..count_columns) let columns = (0..count_columns)
.map(|column| recs.get_text((row, column)).to_owned()) .map(|column| recs.get_text((row, column)).to_owned())