mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
nu_table: Fix style of tables with no header (#6025)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
parent
217c2bae99
commit
93a965e3e2
@ -168,7 +168,7 @@ impl Command for Table {
|
||||
}
|
||||
|
||||
let table = nu_table::Table {
|
||||
headers: vec![],
|
||||
headers: None,
|
||||
data: output,
|
||||
theme: load_theme_from_config(config),
|
||||
};
|
||||
@ -430,16 +430,18 @@ fn convert_to_table(
|
||||
}
|
||||
|
||||
Ok(Some(nu_table::Table {
|
||||
headers: headers
|
||||
.into_iter()
|
||||
.map(|x| StyledString {
|
||||
contents: x,
|
||||
style: TextStyle {
|
||||
alignment: nu_table::Alignment::Center,
|
||||
color_style: Some(color_hm["header"]),
|
||||
},
|
||||
})
|
||||
.collect(),
|
||||
headers: Some(
|
||||
headers
|
||||
.into_iter()
|
||||
.map(|x| StyledString {
|
||||
contents: x,
|
||||
style: TextStyle {
|
||||
alignment: nu_table::Alignment::Center,
|
||||
color_style: Some(color_hm["header"]),
|
||||
},
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
data: data
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
|
@ -23,7 +23,7 @@ fn main() {
|
||||
// The table rows
|
||||
let rows = vec_of_str_to_vec_of_styledstr(&row_data, false);
|
||||
// The table itself
|
||||
let table = Table::new(headers, vec![rows; 3], TableTheme::rounded());
|
||||
let table = Table::new(Some(headers), vec![rows; 3], TableTheme::rounded());
|
||||
// FIXME: Config isn't available from here so just put these here to compile
|
||||
let color_hm: HashMap<String, nu_ansi_term::Style> = HashMap::new();
|
||||
// get the default config
|
||||
|
@ -19,14 +19,14 @@ use crate::{
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Table {
|
||||
pub headers: Vec<StyledString>,
|
||||
pub headers: Option<Vec<StyledString>>,
|
||||
pub data: Vec<Vec<StyledString>>,
|
||||
pub theme: TableTheme,
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn new(
|
||||
headers: Vec<StyledString>,
|
||||
headers: Option<Vec<StyledString>>,
|
||||
data: Vec<Vec<StyledString>>,
|
||||
theme: TableTheme,
|
||||
) -> Table {
|
||||
@ -46,22 +46,18 @@ pub fn draw_table(
|
||||
) -> Option<String> {
|
||||
let termwidth = fix_termwidth(termwidth, &table.theme)?;
|
||||
|
||||
let (mut headers, mut data) = table_fix_lengths(&table.headers, &table.data);
|
||||
let (mut headers, mut data, count_columns) =
|
||||
table_fix_lengths(table.headers.as_ref(), &table.data);
|
||||
|
||||
maybe_truncate_columns(&mut headers, &mut data, termwidth);
|
||||
maybe_truncate_columns(&mut headers, &mut data, count_columns, termwidth);
|
||||
|
||||
let max_column_width = estimate_max_column_width(&headers, &data, 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);
|
||||
let data = table_data_to_strings(data, headers.len());
|
||||
|
||||
let headers = if headers.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(headers)
|
||||
};
|
||||
let data = table_data_to_strings(data, count_columns);
|
||||
|
||||
let theme = &table.theme;
|
||||
let with_header = headers.is_some();
|
||||
@ -111,20 +107,22 @@ fn table_data_to_strings(
|
||||
data
|
||||
}
|
||||
|
||||
fn table_header_to_strings(table_headers: Vec<StyledString>) -> Vec<String> {
|
||||
let mut headers = Vec::with_capacity(table_headers.len());
|
||||
for cell in table_headers {
|
||||
let colored_text = cell
|
||||
.style
|
||||
.color_style
|
||||
.as_ref()
|
||||
.map(|color| color.paint(&cell.contents).to_string())
|
||||
.unwrap_or(cell.contents);
|
||||
fn table_header_to_strings(table_headers: Option<Vec<StyledString>>) -> Option<Vec<String>> {
|
||||
table_headers.map(|table_headers| {
|
||||
let mut headers = Vec::with_capacity(table_headers.len());
|
||||
for cell in table_headers {
|
||||
let colored_text = cell
|
||||
.style
|
||||
.color_style
|
||||
.as_ref()
|
||||
.map(|color| color.paint(&cell.contents).to_string())
|
||||
.unwrap_or(cell.contents);
|
||||
|
||||
headers.push(colored_text)
|
||||
}
|
||||
headers.push(colored_text)
|
||||
}
|
||||
|
||||
headers
|
||||
headers
|
||||
})
|
||||
}
|
||||
|
||||
fn build_alignment_map(data: &[Vec<StyledString>]) -> Vec<Vec<Alignment>> {
|
||||
@ -320,14 +318,17 @@ impl tabled::TableOption for &TrimStrategyModifier<'_> {
|
||||
}
|
||||
|
||||
fn table_fix_lengths(
|
||||
headers: &[StyledString],
|
||||
headers: Option<&Vec<StyledString>>,
|
||||
data: &[Vec<StyledString>],
|
||||
) -> (Vec<StyledString>, Vec<Vec<StyledString>>) {
|
||||
) -> (Option<Vec<StyledString>>, Vec<Vec<StyledString>>, usize) {
|
||||
let length = table_find_max_length(headers, data);
|
||||
|
||||
let mut headers_fixed = Vec::with_capacity(length);
|
||||
headers_fixed.extend(headers.iter().cloned());
|
||||
headers_fixed.extend(std::iter::repeat(StyledString::default()).take(length - headers.len()));
|
||||
let headers_fixed = headers.map(|h| {
|
||||
let mut headers_fixed = Vec::with_capacity(length);
|
||||
headers_fixed.extend(h.iter().cloned());
|
||||
headers_fixed.extend(std::iter::repeat(StyledString::default()).take(length - h.len()));
|
||||
headers_fixed
|
||||
});
|
||||
|
||||
let mut data_fixed = Vec::with_capacity(data.len());
|
||||
for row in data {
|
||||
@ -337,11 +338,11 @@ fn table_fix_lengths(
|
||||
data_fixed.push(row_fixed);
|
||||
}
|
||||
|
||||
(headers_fixed, data_fixed)
|
||||
(headers_fixed, data_fixed, length)
|
||||
}
|
||||
|
||||
fn table_find_max_length(headers: &[StyledString], data: &[Vec<StyledString>]) -> usize {
|
||||
let mut length = headers.len();
|
||||
fn table_find_max_length(headers: Option<&Vec<StyledString>>, data: &[Vec<StyledString>]) -> usize {
|
||||
let mut length = headers.map_or(0, |h| h.len());
|
||||
for row in data {
|
||||
length = std::cmp::max(length, row.len());
|
||||
}
|
||||
|
@ -3,23 +3,26 @@ use crate::{StyledString, TableTheme};
|
||||
use std::iter::Iterator;
|
||||
|
||||
pub(crate) fn maybe_truncate_columns(
|
||||
headers: &mut Vec<StyledString>,
|
||||
headers: &mut Option<Vec<StyledString>>,
|
||||
data: &mut [Vec<StyledString>],
|
||||
length: usize,
|
||||
termwidth: usize,
|
||||
) {
|
||||
// Make sure we have enough space for the columns we have
|
||||
let max_num_of_columns = termwidth / 10;
|
||||
|
||||
// If we have too many columns, truncate the table
|
||||
if max_num_of_columns < headers.len() {
|
||||
headers.truncate(max_num_of_columns);
|
||||
headers.push(StyledString::new(
|
||||
String::from("..."),
|
||||
TextStyle::basic_center(),
|
||||
));
|
||||
if let Some(headers) = headers {
|
||||
if max_num_of_columns < length {
|
||||
headers.truncate(max_num_of_columns);
|
||||
headers.push(StyledString::new(
|
||||
String::from("..."),
|
||||
TextStyle::basic_center(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if max_num_of_columns < headers.len() {
|
||||
if max_num_of_columns < length {
|
||||
for entry in data.iter_mut() {
|
||||
entry.truncate(max_num_of_columns);
|
||||
entry.push(StyledString::new(
|
||||
@ -31,17 +34,17 @@ pub(crate) fn maybe_truncate_columns(
|
||||
}
|
||||
|
||||
pub(crate) fn estimate_max_column_width(
|
||||
headers: &[StyledString],
|
||||
headers: Option<&Vec<StyledString>>,
|
||||
data: &[Vec<StyledString>],
|
||||
count_columns: usize,
|
||||
termwidth: usize,
|
||||
) -> Option<usize> {
|
||||
let max_per_column = get_max_column_widths(headers, data);
|
||||
let max_per_column = get_max_column_widths(headers, data, count_columns);
|
||||
|
||||
let headers_len = headers.len();
|
||||
// Measure how big our columns need to be (accounting for separators also)
|
||||
let max_naive_column_width = (termwidth - 3 * (headers_len - 1)) / headers_len;
|
||||
let max_naive_column_width = (termwidth - 3 * (count_columns - 1)) / count_columns;
|
||||
|
||||
let column_space = ColumnSpace::measure(&max_per_column, max_naive_column_width, headers_len);
|
||||
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)?;
|
||||
@ -51,7 +54,7 @@ pub(crate) fn estimate_max_column_width(
|
||||
&max_per_column,
|
||||
max_naive_column_width,
|
||||
max_column_width,
|
||||
headers_len,
|
||||
count_columns,
|
||||
);
|
||||
|
||||
// This should give us the final max column width
|
||||
@ -76,15 +79,21 @@ pub(crate) fn fix_termwidth(termwidth: usize, theme: &TableTheme) -> Option<usiz
|
||||
Some(termwidth - edges_width - 1)
|
||||
}
|
||||
|
||||
fn get_max_column_widths(headers: &[StyledString], data: &[Vec<StyledString>]) -> Vec<usize> {
|
||||
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; headers.len()];
|
||||
let mut output = vec![0; count_columns];
|
||||
|
||||
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);
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user