mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
nu-table: Remove width estimation logic (#6037)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
parent
2b2117173c
commit
58ab5aa887
3 changed files with 4 additions and 246 deletions
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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', " ")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue