From 58ab5aa88741f7215dec8ee55fe0d8d27d6a0de0 Mon Sep 17 00:00:00 2001 From: Maxim Zhiburt Date: Wed, 13 Jul 2022 14:54:03 +0300 Subject: [PATCH] nu-table: Remove width estimation logic (#6037) Signed-off-by: Maxim Zhiburt --- crates/nu-table/src/table.rs | 37 +----- crates/nu-table/src/table_theme.rs | 22 --- crates/nu-table/src/width_control.rs | 191 +-------------------------- 3 files changed, 4 insertions(+), 246 deletions(-) diff --git a/crates/nu-table/src/table.rs b/crates/nu-table/src/table.rs index d2753ad700..cf249b2cbe 100644 --- a/crates/nu-table/src/table.rs +++ b/crates/nu-table/src/table.rs @@ -11,11 +11,7 @@ use tabled::{ Alignment, Modify, TableOption, Width, }; -use crate::{ - table_theme::TableTheme, - width_control::{estimate_max_column_width, fix_termwidth, maybe_truncate_columns}, - StyledString, -}; +use crate::{table_theme::TableTheme, width_control::maybe_truncate_columns, StyledString}; #[derive(Debug)] pub struct Table { @@ -49,16 +45,11 @@ pub fn draw_table( color_hm: &HashMap, config: &Config, ) -> Option { - let termwidth = fix_termwidth(termwidth, &table.theme)?; - let (mut headers, mut data, count_columns) = table_fix_lengths(table.headers.as_ref(), &table.data); maybe_truncate_columns(&mut headers, &mut data, count_columns, termwidth); - let max_column_width = - estimate_max_column_width(headers.as_ref(), &data, count_columns, termwidth)?; - let alignments = build_alignment_map(&table.data); let headers = table_header_to_strings(headers); @@ -71,15 +62,7 @@ pub fn draw_table( let table = build_table(data, headers, Some(alignments), config, with_footer); let table = load_theme(table, color_hm, theme, with_footer, with_header); - let (count_columns, table) = count_columns_on_table(table); - - let table = table_trim_columns( - table, - count_columns, - termwidth, - max_column_width, - &config.trim_strategy, - ); + let table = table_trim_columns(table, termwidth, &config.trim_strategy); Some(print_table(table, config)) } @@ -100,13 +83,6 @@ fn print_table(table: tabled::Table, config: &Config) -> String { } } -fn count_columns_on_table(mut table: tabled::Table) -> (usize, tabled::Table) { - let mut c = CountColumns(0); - table = table.with(&mut c); - - (c.0, table) -} - fn table_data_to_strings( table_data: Vec>, count_headers: usize, @@ -292,18 +268,11 @@ impl TableOption for &mut CountColumns { fn table_trim_columns( table: tabled::Table, - count_columns: usize, termwidth: usize, - max_column_width: usize, trim_strategy: &TrimStrategy, ) -> tabled::Table { - let mut table_width = max_column_width * count_columns; - if table_width > termwidth { - table_width = termwidth; - } - table.with(&TrimStrategyModifier { - termwidth: table_width, + termwidth, trim_strategy, }) } diff --git a/crates/nu-table/src/table_theme.rs b/crates/nu-table/src/table_theme.rs index 2c0fa9a6db..05e9d5d6f0 100644 --- a/crates/nu-table/src/table_theme.rs +++ b/crates/nu-table/src/table_theme.rs @@ -3,32 +3,24 @@ use tabled::{style::StyleConfig, Style}; #[derive(Debug, Clone)] pub struct TableTheme { pub(crate) theme: StyleConfig, - pub(crate) is_left_set: bool, - pub(crate) is_right_set: bool, } impl TableTheme { pub fn basic() -> TableTheme { Self { theme: Style::ascii().into(), - is_left_set: true, - is_right_set: true, } } pub fn thin() -> TableTheme { Self { theme: Style::modern().into(), - is_left_set: true, - is_right_set: true, } } pub fn light() -> TableTheme { Self { theme: Style::blank().header('─').into(), - is_left_set: false, - is_right_set: false, } } @@ -39,8 +31,6 @@ impl TableTheme { .right_off() .horizontal_off() .into(), - is_left_set: false, - is_right_set: false, } } @@ -52,8 +42,6 @@ impl TableTheme { .bottom('❤') .vertical('❤') .into(), - is_left_set: false, - is_right_set: false, } } @@ -68,16 +56,12 @@ impl TableTheme { .bottom_intersection('╩') .header_intersection('╬') .into(), - is_left_set: false, - is_right_set: false, } } pub fn rounded() -> TableTheme { Self { theme: Style::rounded().into(), - is_left_set: true, - is_right_set: true, } } @@ -90,8 +74,6 @@ impl TableTheme { .bottom_right_corner('┛') .horizontal_off() .into(), - is_left_set: true, - is_right_set: true, } } @@ -115,16 +97,12 @@ impl TableTheme { .header_intersection('╋') .horizontal_off() .into(), - is_left_set: true, - is_right_set: true, } } pub fn none() -> TableTheme { Self { theme: Style::blank().into(), - is_left_set: false, - is_right_set: false, } } } diff --git a/crates/nu-table/src/width_control.rs b/crates/nu-table/src/width_control.rs index a42741852a..af5a2b6384 100644 --- a/crates/nu-table/src/width_control.rs +++ b/crates/nu-table/src/width_control.rs @@ -1,6 +1,5 @@ use crate::textstyle::TextStyle; -use crate::{StyledString, TableTheme}; -use std::iter::Iterator; +use crate::StyledString; pub(crate) fn maybe_truncate_columns( headers: &mut Option>, @@ -32,191 +31,3 @@ pub(crate) fn maybe_truncate_columns( } } } - -pub(crate) fn estimate_max_column_width( - headers: Option<&Vec>, - data: &[Vec], - count_columns: usize, - termwidth: usize, -) -> Option { - let max_per_column = get_max_column_widths(headers, data, count_columns); - - // Measure how big our columns need to be (accounting for separators also) - let max_naive_column_width = (termwidth - 3 * (count_columns - 1)) / count_columns; - - let column_space = ColumnSpace::measure(&max_per_column, max_naive_column_width, count_columns); - - // This gives us the max column width - let max_column_width = column_space.max_width(termwidth)?; - - // This width isn't quite right, as we're rounding off some of our space - let column_space = column_space.fix_almost_column_width( - &max_per_column, - max_naive_column_width, - max_column_width, - count_columns, - ); - - // This should give us the final max column width - let max_column_width = column_space.max_width(termwidth)?; - - Some(max_column_width) -} - -pub(crate) fn fix_termwidth(termwidth: usize, theme: &TableTheme) -> Option { - let edges_width = if theme.is_left_set && theme.is_right_set { - 3 - } else if theme.is_left_set || theme.is_right_set { - 1 - } else { - 0 - }; - - if termwidth < edges_width { - return None; - } - - Some(termwidth - edges_width - 1) -} - -fn get_max_column_widths( - headers: Option<&Vec>, - data: &[Vec], - count_columns: usize, -) -> Vec { - use std::cmp::max; - - let mut output = vec![0; count_columns]; - - if let Some(headers) = headers { - for (col, content) in headers.iter().enumerate() { - let content = clean(&content.contents); - let content_width = tabled::papergrid::string_width_multiline(&content); - output[col] = max(output[col], content_width); - } - } - - for row in data { - for (col, content) in row.iter().enumerate() { - let content = clean(&content.contents); - let content_width = tabled::papergrid::string_width_multiline(&content); - output[col] = max(output[col], content_width); - } - } - - output -} - -struct ColumnSpace { - num_overages: usize, - underage_sum: usize, - overage_separator_sum: usize, -} - -impl ColumnSpace { - /// Measure how much space we have once we subtract off the columns who are small enough - fn measure( - max_per_column: &[usize], - max_naive_column_width: usize, - headers_len: usize, - ) -> ColumnSpace { - let mut num_overages = 0; - let mut underage_sum = 0; - let mut overage_separator_sum = 0; - let iter = max_per_column.iter().enumerate().take(headers_len); - - for (i, &column_max) in iter { - if column_max > max_naive_column_width { - num_overages += 1; - if i != (headers_len - 1) { - overage_separator_sum += 3; - } - if i == 0 { - overage_separator_sum += 1; - } - } else { - underage_sum += column_max; - // if column isn't last, add 3 for its separator - if i != (headers_len - 1) { - underage_sum += 3; - } - if i == 0 { - underage_sum += 1; - } - } - } - - ColumnSpace { - num_overages, - underage_sum, - overage_separator_sum, - } - } - - fn fix_almost_column_width( - self, - max_per_column: &[usize], - max_naive_column_width: usize, - max_column_width: usize, - headers_len: usize, - ) -> ColumnSpace { - let mut num_overages = 0; - let mut overage_separator_sum = 0; - let mut underage_sum = self.underage_sum; - let iter = max_per_column.iter().enumerate().take(headers_len); - - for (i, &column_max) in iter { - if column_max > max_naive_column_width { - if column_max <= max_column_width { - underage_sum += column_max; - // if column isn't last, add 3 for its separator - if i != (headers_len - 1) { - underage_sum += 3; - } - if i == 0 { - underage_sum += 1; - } - } else { - // Column is still too large, so let's count it - num_overages += 1; - if i != (headers_len - 1) { - overage_separator_sum += 3; - } - if i == 0 { - overage_separator_sum += 1; - } - } - } - } - - ColumnSpace { - num_overages, - underage_sum, - overage_separator_sum, - } - } - - fn max_width(&self, termwidth: usize) -> Option { - let ColumnSpace { - num_overages, - underage_sum, - overage_separator_sum, - } = self; - - if *num_overages > 0 { - termwidth - .checked_sub(1)? - .checked_sub(*underage_sum)? - .checked_sub(*overage_separator_sum)? - .checked_div(*num_overages) - } else { - Some(99999) - } - } -} - -fn clean(input: &str) -> String { - let input = input.replace('\r', ""); - - input.replace('\t', " ") -}