mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Introduce footer_inheritance option (#14070)
```nu $env.config.table.footer_inheritance = true ``` close #14060
This commit is contained in:
parent
619211c1bf
commit
3ec1c40320
8 changed files with 222 additions and 67 deletions
|
@ -1088,7 +1088,7 @@ fn create_empty_placeholder(
|
|||
let data = vec![vec![cell]];
|
||||
let mut table = NuTable::from(data);
|
||||
table.set_data_style(TextStyle::default().dimmed());
|
||||
let out = TableOutput::new(table, false, false);
|
||||
let out = TableOutput::new(table, false, false, false);
|
||||
|
||||
let style_computer = &StyleComputer::from_config(engine_state, stack);
|
||||
let config = create_nu_table_config(&config, style_computer, &out, false, TableMode::default());
|
||||
|
|
|
@ -2905,3 +2905,39 @@ fn table_general_header_on_separator_issue1() {
|
|||
let actual = nu!("$env.config.table.header_on_separator = true; [['Llll oo Bbbbbbbb' 'Bbbbbbbb Aaaa' Nnnnnn Ggggg 'Xxxxx Llllllll #' Bbb 'Pppp Ccccc' 'Rrrrrrrr Dddd' Rrrrrr 'Rrrrrr Ccccc II' 'Rrrrrr Ccccc Ppppppp II' 'Pppppp Dddddddd Tttt' 'Pppppp Dddddddd Dddd' 'Rrrrrrrrr Trrrrrr' 'Pppppp Ppppp Dddd' 'Ppppp Dddd' Hhhh]; [RRRRRRR FFFFFFFF UUUU VV 202407160001 BBB 1 '7/16/2024' '' AAA-1111 AAA-1111-11 '7 YEARS' 2555 'RRRRRRRR DDDD' '7/16/2031' '7/16/2031' NN]] | table --width=87 --theme basic");
|
||||
assert_eq!(actual.out, "+-#-+-Llll oo Bbbbbbbb-+-Bbbbbbbb Aaaa-+-Nnnnnn-+-Ggggg-+-Xxxxx Llllllll #-+-...-+| 0 | RRRRRRR | FFFFFFFF | UUUU | VV | 202407160001 | ... |+---+------------------+---------------+--------+-------+------------------+-----+");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_footer_inheritance() {
|
||||
let table1 = format!(
|
||||
"[ [ head1, head2, head3 ]; {} ]",
|
||||
(0..212)
|
||||
.map(|_| "[ 79 79 79 ]")
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
);
|
||||
|
||||
let structure = format!(
|
||||
"{{\
|
||||
field0: [ [ y1, y2, y3 ]; [ 1 2 3 ] [ 79 79 79 ] [ {{ f1: 'a string', f2: 1000 }}, 1, 2 ] ],\
|
||||
field1: [ a, b, c ],\
|
||||
field2: [ 123, 234, 345 ],\
|
||||
field3: {},\
|
||||
field4: {{ f1: 1, f2: 3, f3: {{ f1: f1, f2: f2, f3: f3 }} }},\
|
||||
field5: [ [ x1, x2, x3 ]; [ 1 2 3 ] [ 79 79 79 ] [ {{ f1: 'a string', f2: 1000 }}, 1, 2 ] ],\
|
||||
}}",
|
||||
table1
|
||||
);
|
||||
let actual = nu!(format!(
|
||||
"$env.config.table.footer_inheritance = true; {structure} | table --width=80 --expand"
|
||||
));
|
||||
|
||||
assert_eq!(actual.out.match_indices("head1").count(), 2);
|
||||
assert_eq!(actual.out.match_indices("head2").count(), 2);
|
||||
assert_eq!(actual.out.match_indices("head3").count(), 2);
|
||||
assert_eq!(actual.out.match_indices("y1").count(), 1);
|
||||
assert_eq!(actual.out.match_indices("y2").count(), 1);
|
||||
assert_eq!(actual.out.match_indices("y3").count(), 1);
|
||||
assert_eq!(actual.out.match_indices("x1").count(), 1);
|
||||
assert_eq!(actual.out.match_indices("x2").count(), 1);
|
||||
assert_eq!(actual.out.match_indices("x3").count(), 1);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,7 @@ pub struct TableConfig {
|
|||
pub trim: TrimStrategy,
|
||||
pub header_on_separator: bool,
|
||||
pub abbreviated_row_count: Option<usize>,
|
||||
pub footer_inheritance: bool,
|
||||
}
|
||||
|
||||
impl IntoValue for TableConfig {
|
||||
|
@ -350,6 +351,7 @@ impl IntoValue for TableConfig {
|
|||
"trim" => self.trim.into_value(span),
|
||||
"header_on_separator" => self.header_on_separator.into_value(span),
|
||||
"abbreviated_row_count" => abbv_count,
|
||||
"footer_inheritance" => self.footer_inheritance.into_value(span),
|
||||
}
|
||||
.into_value(span)
|
||||
}
|
||||
|
@ -365,6 +367,7 @@ impl Default for TableConfig {
|
|||
header_on_separator: false,
|
||||
padding: TableIndent::default(),
|
||||
abbreviated_row_count: None,
|
||||
footer_inheritance: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -401,6 +404,7 @@ impl UpdateFromValue for TableConfig {
|
|||
}
|
||||
_ => errors.type_mismatch(path, Type::custom("int or nothing"), val),
|
||||
},
|
||||
"footer_inheritance" => self.footer_inheritance.update(val, path, errors),
|
||||
_ => errors.unknown_option(path, val),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,12 @@ pub fn create_nu_table_config(
|
|||
expand: bool,
|
||||
mode: TableMode,
|
||||
) -> NuTableConfig {
|
||||
let with_footer = (config.table.footer_inheritance && out.with_footer)
|
||||
|| with_footer(config, out.with_header, out.table.count_rows());
|
||||
|
||||
NuTableConfig {
|
||||
theme: load_theme(mode),
|
||||
with_footer: with_footer(config, out.with_header, out.table.count_rows()),
|
||||
with_footer,
|
||||
with_index: out.with_index,
|
||||
with_header: out.with_header,
|
||||
split_color: Some(lookup_separator_color(comp)),
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
NuText, StringResult, TableResult, INDEX_COLUMN_NAME,
|
||||
},
|
||||
string_width,
|
||||
types::has_index,
|
||||
types::{has_footer, has_index},
|
||||
NuTable, NuTableCell, TableOpts, TableOutput,
|
||||
};
|
||||
use nu_color_config::{Alignment, StyleComputer, TextStyle};
|
||||
|
@ -31,11 +31,12 @@ impl ExpandedTable {
|
|||
}
|
||||
|
||||
pub fn build_value(self, item: &Value, opts: TableOpts<'_>) -> NuText {
|
||||
expanded_table_entry2(item, Cfg { opts, format: self })
|
||||
let cell = expanded_table_entry2(item, Cfg { opts, format: self });
|
||||
(cell.text, cell.style)
|
||||
}
|
||||
|
||||
pub fn build_map(self, record: &Record, opts: TableOpts<'_>) -> StringResult {
|
||||
expanded_table_kv(record, Cfg { opts, format: self })
|
||||
expanded_table_kv(record, Cfg { opts, format: self }).map(|cell| cell.map(|cell| cell.text))
|
||||
}
|
||||
|
||||
pub fn build_list(self, vals: &[Value], opts: TableOpts<'_>) -> StringResult {
|
||||
|
@ -58,6 +59,39 @@ struct Cfg<'a> {
|
|||
format: ExpandedTable,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CellOutput {
|
||||
text: String,
|
||||
style: TextStyle,
|
||||
is_big: bool,
|
||||
is_expanded: bool,
|
||||
}
|
||||
|
||||
impl CellOutput {
|
||||
fn new(text: String, style: TextStyle, is_big: bool, is_expanded: bool) -> Self {
|
||||
Self {
|
||||
text,
|
||||
style,
|
||||
is_big,
|
||||
is_expanded,
|
||||
}
|
||||
}
|
||||
|
||||
fn clean(text: String, is_big: bool, is_expanded: bool) -> Self {
|
||||
Self::new(text, Default::default(), is_big, is_expanded)
|
||||
}
|
||||
|
||||
fn text(text: String) -> Self {
|
||||
Self::styled((text, Default::default()))
|
||||
}
|
||||
|
||||
fn styled(text: NuText) -> Self {
|
||||
Self::new(text.0, text.1, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
type CellResult = Result<Option<CellOutput>, ShellError>;
|
||||
|
||||
fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
||||
const PADDING_SPACE: usize = 2;
|
||||
const SPLIT_LINE_SPACE: usize = 1;
|
||||
|
@ -83,6 +117,7 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
|
||||
let with_index = has_index(&cfg.opts, &headers);
|
||||
let row_offset = cfg.opts.index_offset;
|
||||
let mut is_footer_used = false;
|
||||
|
||||
// The header with the INDEX is removed from the table headers since
|
||||
// it is added to the natural table index
|
||||
|
@ -148,21 +183,25 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
}
|
||||
|
||||
let inner_cfg = update_config(cfg.clone(), available_width);
|
||||
let (mut text, style) = expanded_table_entry2(item, inner_cfg);
|
||||
let mut cell = expanded_table_entry2(item, inner_cfg);
|
||||
|
||||
let value_width = string_width(&text);
|
||||
let value_width = string_width(&cell.text);
|
||||
if value_width > available_width {
|
||||
// it must only happen when a string is produced, so we can safely wrap it.
|
||||
// (it might be string table representation as well) (I guess I mean default { table ...} { list ...})
|
||||
//
|
||||
// todo: Maybe convert_to_table2_entry could do for strings to not mess caller code?
|
||||
|
||||
text = wrap_text(&text, available_width, cfg.opts.config);
|
||||
cell.text = wrap_text(&cell.text, available_width, cfg.opts.config);
|
||||
}
|
||||
|
||||
let value = NuTableCell::new(text);
|
||||
let value = NuTableCell::new(cell.text);
|
||||
data[row].push(value);
|
||||
data_styles.insert((row, with_index as usize), style);
|
||||
data_styles.insert((row, with_index as usize), cell.style);
|
||||
|
||||
if cell.is_big {
|
||||
is_footer_used = cell.is_big;
|
||||
}
|
||||
}
|
||||
|
||||
let mut table = NuTable::from(data);
|
||||
|
@ -170,7 +209,12 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
table.set_index_style(get_index_style(cfg.opts.style_computer));
|
||||
set_data_styles(&mut table, data_styles);
|
||||
|
||||
return Ok(Some(TableOutput::new(table, false, with_index)));
|
||||
return Ok(Some(TableOutput::new(
|
||||
table,
|
||||
false,
|
||||
with_index,
|
||||
is_footer_used,
|
||||
)));
|
||||
}
|
||||
|
||||
if !headers.is_empty() {
|
||||
|
@ -233,22 +277,26 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
}
|
||||
|
||||
let inner_cfg = update_config(cfg.clone(), available);
|
||||
let (mut text, style) = expanded_table_entry(item, header.as_str(), inner_cfg);
|
||||
let mut cell = expanded_table_entry(item, header.as_str(), inner_cfg);
|
||||
|
||||
let mut value_width = string_width(&text);
|
||||
let mut value_width = string_width(&cell.text);
|
||||
if value_width > available {
|
||||
// it must only happen when a string is produced, so we can safely wrap it.
|
||||
// (it might be string table representation as well)
|
||||
|
||||
text = wrap_text(&text, available, cfg.opts.config);
|
||||
cell.text = wrap_text(&cell.text, available, cfg.opts.config);
|
||||
value_width = available;
|
||||
}
|
||||
|
||||
column_width = max(column_width, value_width);
|
||||
|
||||
let value = NuTableCell::new(text);
|
||||
let value = NuTableCell::new(cell.text);
|
||||
data[row + 1].push(value);
|
||||
data_styles.insert((row + 1, col + with_index as usize), style);
|
||||
data_styles.insert((row + 1, col + with_index as usize), cell.style);
|
||||
|
||||
if cell.is_big {
|
||||
is_footer_used = cell.is_big;
|
||||
}
|
||||
}
|
||||
|
||||
let head_cell = NuTableCell::new(header);
|
||||
|
@ -326,10 +374,12 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
table.set_indent(cfg.opts.indent.0, cfg.opts.indent.1);
|
||||
set_data_styles(&mut table, data_styles);
|
||||
|
||||
Ok(Some(TableOutput::new(table, true, with_index)))
|
||||
let has_footer = is_footer_used || has_footer(&cfg.opts, table.count_rows() as u64);
|
||||
|
||||
Ok(Some(TableOutput::new(table, true, with_index, has_footer)))
|
||||
}
|
||||
|
||||
fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult {
|
||||
fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> CellResult {
|
||||
let theme = load_theme(cfg.opts.mode);
|
||||
let key_width = record
|
||||
.columns()
|
||||
|
@ -345,11 +395,13 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult {
|
|||
|
||||
let value_width = cfg.opts.width - key_width - count_borders - padding - padding;
|
||||
|
||||
let mut with_footer = false;
|
||||
|
||||
let mut data = Vec::with_capacity(record.len());
|
||||
for (key, value) in record {
|
||||
cfg.opts.signals.check(cfg.opts.span)?;
|
||||
|
||||
let (value, is_expanded) = match expand_table_value(value, value_width, &cfg)? {
|
||||
let cell = match expand_table_value(value, value_width, &cfg)? {
|
||||
Some(val) => val,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
@ -358,35 +410,40 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult {
|
|||
// we could use Padding for it but,
|
||||
// the easiest way to do so is just push a new_line char before
|
||||
let mut key = key.to_owned();
|
||||
if !key.is_empty() && is_expanded && theme.has_top() {
|
||||
if !key.is_empty() && cell.is_expanded && theme.has_top() {
|
||||
key.insert(0, '\n');
|
||||
}
|
||||
|
||||
let key = NuTableCell::new(key);
|
||||
let val = NuTableCell::new(value);
|
||||
let val = NuTableCell::new(cell.text);
|
||||
let row = vec![key, val];
|
||||
|
||||
data.push(row);
|
||||
|
||||
if cell.is_big {
|
||||
with_footer = cell.is_big;
|
||||
}
|
||||
}
|
||||
|
||||
let mut table = NuTable::from(data);
|
||||
table.set_index_style(get_key_style(&cfg));
|
||||
table.set_indent(cfg.opts.indent.0, cfg.opts.indent.1);
|
||||
|
||||
let out = TableOutput::new(table, false, true);
|
||||
let out = TableOutput::new(table, false, true, with_footer);
|
||||
|
||||
maybe_expand_table(out, cfg.opts.width, &cfg.opts)
|
||||
.map(|value| value.map(|value| CellOutput::clean(value, with_footer, false)))
|
||||
}
|
||||
|
||||
// the flag is used as an optimization to not do `value.lines().count()` search.
|
||||
fn expand_table_value(
|
||||
value: &Value,
|
||||
value_width: usize,
|
||||
cfg: &Cfg<'_>,
|
||||
) -> Result<Option<(String, bool)>, ShellError> {
|
||||
fn expand_table_value(value: &Value, value_width: usize, cfg: &Cfg<'_>) -> CellResult {
|
||||
let is_limited = matches!(cfg.format.expand_limit, Some(0));
|
||||
if is_limited {
|
||||
return Ok(Some((value_to_string_clean(value, cfg), false)));
|
||||
return Ok(Some(CellOutput::clean(
|
||||
value_to_string_clean(value, cfg),
|
||||
false,
|
||||
false,
|
||||
)));
|
||||
}
|
||||
|
||||
let span = value.span();
|
||||
|
@ -400,42 +457,46 @@ fn expand_table_value(
|
|||
let cfg = create_table_cfg(cfg, &out);
|
||||
let value = out.table.draw(cfg, value_width);
|
||||
match value {
|
||||
Some(result) => Ok(Some((result, true))),
|
||||
Some(value) => Ok(Some(CellOutput::clean(value, out.with_footer, true))),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// it means that the list is empty
|
||||
Ok(Some((
|
||||
value_to_wrapped_string(value, cfg, value_width),
|
||||
false,
|
||||
)))
|
||||
Ok(Some(CellOutput::text(value_to_wrapped_string(
|
||||
value,
|
||||
cfg,
|
||||
value_width,
|
||||
))))
|
||||
}
|
||||
}
|
||||
}
|
||||
Value::Record { val: record, .. } => {
|
||||
if record.is_empty() {
|
||||
// Like list case return styled string instead of empty value
|
||||
return Ok(Some((
|
||||
value_to_wrapped_string(value, cfg, value_width),
|
||||
false,
|
||||
)));
|
||||
return Ok(Some(CellOutput::text(value_to_wrapped_string(
|
||||
value,
|
||||
cfg,
|
||||
value_width,
|
||||
))));
|
||||
}
|
||||
|
||||
let inner_cfg = update_config(dive_options(cfg, span), value_width);
|
||||
let result = expanded_table_kv(record, inner_cfg)?;
|
||||
match result {
|
||||
Some(result) => Ok(Some((result, true))),
|
||||
None => Ok(Some((
|
||||
value_to_wrapped_string(value, cfg, value_width),
|
||||
false,
|
||||
))),
|
||||
Some(result) => Ok(Some(CellOutput::clean(result.text, result.is_big, true))),
|
||||
None => Ok(Some(CellOutput::text(value_to_wrapped_string(
|
||||
value,
|
||||
cfg,
|
||||
value_width,
|
||||
)))),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let text = value_to_wrapped_string_clean(value, cfg, value_width);
|
||||
Ok(Some((text, false)))
|
||||
}
|
||||
_ => Ok(Some(CellOutput::text(value_to_wrapped_string_clean(
|
||||
value,
|
||||
cfg,
|
||||
value_width,
|
||||
)))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,27 +504,35 @@ fn get_key_style(cfg: &Cfg<'_>) -> TextStyle {
|
|||
get_header_style(cfg.opts.style_computer).alignment(Alignment::Left)
|
||||
}
|
||||
|
||||
fn expanded_table_entry(item: &Value, header: &str, cfg: Cfg<'_>) -> NuText {
|
||||
fn expanded_table_entry(item: &Value, header: &str, cfg: Cfg<'_>) -> CellOutput {
|
||||
match item {
|
||||
Value::Record { val, .. } => match val.get(header) {
|
||||
Some(val) => expanded_table_entry2(val, cfg),
|
||||
None => error_sign(cfg.opts.style_computer),
|
||||
None => CellOutput::styled(error_sign(cfg.opts.style_computer)),
|
||||
},
|
||||
_ => expanded_table_entry2(item, cfg),
|
||||
}
|
||||
}
|
||||
|
||||
fn expanded_table_entry2(item: &Value, cfg: Cfg<'_>) -> NuText {
|
||||
fn expanded_table_entry2(item: &Value, cfg: Cfg<'_>) -> CellOutput {
|
||||
let is_limit_reached = matches!(cfg.format.expand_limit, Some(0));
|
||||
if is_limit_reached {
|
||||
return nu_value_to_string_clean(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
return CellOutput::styled(nu_value_to_string_clean(
|
||||
item,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
));
|
||||
}
|
||||
|
||||
let span = item.span();
|
||||
match &item {
|
||||
Value::Record { val: record, .. } => {
|
||||
if record.is_empty() {
|
||||
return nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
return CellOutput::styled(nu_value_to_string(
|
||||
item,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
));
|
||||
}
|
||||
|
||||
// we verify what is the structure of a Record cause it might represent
|
||||
|
@ -471,18 +540,22 @@ fn expanded_table_entry2(item: &Value, cfg: Cfg<'_>) -> NuText {
|
|||
let table = expanded_table_kv(record, inner_cfg);
|
||||
|
||||
match table {
|
||||
Ok(Some(table)) => (table, TextStyle::default()),
|
||||
_ => nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer),
|
||||
Ok(Some(table)) => table,
|
||||
_ => CellOutput::styled(nu_value_to_string(
|
||||
item,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
)),
|
||||
}
|
||||
}
|
||||
Value::List { vals, .. } => {
|
||||
if cfg.format.flatten && is_simple_list(vals) {
|
||||
return value_list_to_string(
|
||||
return CellOutput::styled(value_list_to_string(
|
||||
vals,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
&cfg.format.flatten_sep,
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
let inner_cfg = dive_options(&cfg, span);
|
||||
|
@ -490,17 +563,31 @@ fn expanded_table_entry2(item: &Value, cfg: Cfg<'_>) -> NuText {
|
|||
|
||||
let out = match table {
|
||||
Ok(Some(out)) => out,
|
||||
_ => return nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer),
|
||||
_ => {
|
||||
return CellOutput::styled(nu_value_to_string(
|
||||
item,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let table_config = create_table_cfg(&cfg, &out);
|
||||
let table = out.table.draw(table_config, usize::MAX);
|
||||
match table {
|
||||
Some(table) => (table, TextStyle::default()),
|
||||
None => nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer),
|
||||
Some(table) => CellOutput::clean(table, out.with_footer, false),
|
||||
None => CellOutput::styled(nu_value_to_string(
|
||||
item,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => nu_value_to_string_clean(item, cfg.opts.config, cfg.opts.style_computer),
|
||||
_ => CellOutput::styled(nu_value_to_string_clean(
|
||||
item,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult {
|
|||
let mut table = NuTable::from(data);
|
||||
table.set_index_style(TextStyle::default_field());
|
||||
|
||||
let mut out = TableOutput::new(table, false, true);
|
||||
let mut out = TableOutput::new(table, false, true, false);
|
||||
|
||||
let left = opts.config.table.padding.left;
|
||||
let right = opts.config.table.padding.right;
|
||||
|
@ -82,7 +82,7 @@ fn table(input: &[Value], opts: &TableOpts<'_>) -> TableResult {
|
|||
let with_header = !headers.is_empty();
|
||||
if !with_header {
|
||||
let table = to_table_with_no_header(input, with_index, row_offset, opts)?;
|
||||
let table = table.map(|table| TableOutput::new(table, false, with_index));
|
||||
let table = table.map(|table| TableOutput::new(table, false, with_index, false));
|
||||
return Ok(table);
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ fn table(input: &[Value], opts: &TableOpts<'_>) -> TableResult {
|
|||
.collect();
|
||||
|
||||
let table = to_table_with_header(input, &headers, with_index, row_offset, opts)?;
|
||||
let table = table.map(|table| TableOutput::new(table, true, with_index));
|
||||
let table = table.map(|table| TableOutput::new(table, true, with_index, false));
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use terminal_size::{terminal_size, Height, Width};
|
||||
|
||||
use crate::{common::INDEX_COLUMN_NAME, NuTable};
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{Config, FooterMode, Signals, Span, TableIndexMode, TableMode};
|
||||
|
||||
mod collapse;
|
||||
mod expanded;
|
||||
mod general;
|
||||
|
@ -6,22 +12,20 @@ pub use collapse::CollapsedTable;
|
|||
pub use expanded::ExpandedTable;
|
||||
pub use general::JustTable;
|
||||
|
||||
use crate::{common::INDEX_COLUMN_NAME, NuTable};
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{Config, Signals, Span, TableIndexMode, TableMode};
|
||||
|
||||
pub struct TableOutput {
|
||||
pub table: NuTable,
|
||||
pub with_header: bool,
|
||||
pub with_index: bool,
|
||||
pub with_footer: bool,
|
||||
}
|
||||
|
||||
impl TableOutput {
|
||||
pub fn new(table: NuTable, with_header: bool, with_index: bool) -> Self {
|
||||
pub fn new(table: NuTable, with_header: bool, with_index: bool, with_footer: bool) -> Self {
|
||||
Self {
|
||||
table,
|
||||
with_header,
|
||||
with_index,
|
||||
with_footer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,3 +79,23 @@ fn has_index(opts: &TableOpts<'_>, headers: &[String]) -> bool {
|
|||
|
||||
with_index && !opts.index_remove
|
||||
}
|
||||
|
||||
fn has_footer(opts: &TableOpts<'_>, count_records: u64) -> bool {
|
||||
match opts.config.footer_mode {
|
||||
// Only show the footer if there are more than RowCount rows
|
||||
FooterMode::RowCount(limit) => count_records > limit,
|
||||
// Always show the footer
|
||||
FooterMode::Always => true,
|
||||
// Never show the footer
|
||||
FooterMode::Never => false,
|
||||
// Calculate the screen height and row count, if screen height is larger than row count, don't show footer
|
||||
FooterMode::Auto => {
|
||||
let (_width, height) = match terminal_size() {
|
||||
Some((w, h)) => (Width(w.0).0 as u64, Height(h.0).0 as u64),
|
||||
None => (Width(0).0 as u64, Height(0).0 as u64),
|
||||
};
|
||||
|
||||
height <= count_records
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -169,6 +169,7 @@ $env.config = {
|
|||
truncating_suffix: "..." # A suffix used by the 'truncating' methodology
|
||||
}
|
||||
header_on_separator: false # show header text on separator/border line
|
||||
footer_inheritance: false # render footer in parent table if child is big enough (extended table option)
|
||||
# abbreviated_row_count: 10 # limit data rows from top and bottom after reaching a set point
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue