nu-table: Remove width estimation logic (#6037)

Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
Maxim Zhiburt 2022-07-13 14:54:03 +03:00 committed by GitHub
parent 2b2117173c
commit 58ab5aa887
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 4 additions and 246 deletions

View file

@ -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<String, Style>,
config: &Config,
) -> Option<String> {
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<Vec<StyledString>>,
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,
})
}

View file

@ -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,
}
}
}

View file

@ -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<Vec<StyledString>>,
@ -32,191 +31,3 @@ pub(crate) fn maybe_truncate_columns(
}
}
}
pub(crate) fn estimate_max_column_width(
headers: Option<&Vec<StyledString>>,
data: &[Vec<StyledString>],
count_columns: usize,
termwidth: usize,
) -> Option<usize> {
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<usize> {
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<StyledString>>,
data: &[Vec<StyledString>],
count_columns: usize,
) -> Vec<usize> {
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<usize> {
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', " ")
}