nu-table/ Add -t/theme argument && Replace -n/start-number with -i/index (#11058)

ref #11054

cc: @fdncred 

I've not figured out how to be able to have a flag option as `table -i`
:(

```nu
~/bin/nushell> [[a b, c]; [1 [2 3 3] 3] [4 5 [1 2 [1 2 3]]]] | table -e --width=80 --theme basic -i false

+---+-------+-----------+
| a |   b   |     c     |
+---+-------+-----------+
| 1 | +---+ |         3 |
|   | | 2 | |           |
|   | +---+ |           |
|   | | 3 | |           |
|   | +---+ |           |
|   | | 3 | |           |
|   | +---+ |           |
+---+-------+-----------+
| 4 |     5 | +-------+ |
|   |       | |     1 | |
|   |       | +-------+ |
|   |       | |     2 | |
|   |       | +-------+ |
|   |       | | +---+ | |
|   |       | | | 1 | | |
|   |       | | +---+ | |
|   |       | | | 2 | | |
|   |       | | +---+ | |
|   |       | | | 3 | | |
|   |       | | +---+ | |
|   |       | +-------+ |
+---+-------+-----------+
```

```nu
~/bin/nushell> [[a b, c]; [1 [2 3 3] 3] [4 5 [1 2 [1 2 3]]]] | table -e --width=80 --theme basic -i 100

+-----+---+-------------+-----------------------+
|   # | a |      b      |           c           |
+-----+---+-------------+-----------------------+
| 100 | 1 | +-----+---+ |                     3 |
|     |   | | 100 | 2 | |                       |
|     |   | +-----+---+ |                       |
|     |   | | 101 | 3 | |                       |
|     |   | +-----+---+ |                       |
|     |   | | 102 | 3 | |                       |
|     |   | +-----+---+ |                       |
+-----+---+-------------+-----------------------+
| 101 | 4 |           5 | +-----+-------------+ |
|     |   |             | | 100 |           1 | |
|     |   |             | +-----+-------------+ |
|     |   |             | | 101 |           2 | |
|     |   |             | +-----+-------------+ |
|     |   |             | | 102 | +-----+---+ | |
|     |   |             | |     | | 100 | 1 | | |
|     |   |             | |     | +-----+---+ | |
|     |   |             | |     | | 101 | 2 | | |
|     |   |             | |     | +-----+---+ | |
|     |   |             | |     | | 102 | 3 | | |
|     |   |             | |     | +-----+---+ | |
|     |   |             | +-----+-------------+ |
+-----+---+-------------+-----------------------+
```
This commit is contained in:
Maxim Zhiburt 2023-11-16 02:41:18 +03:00 committed by GitHub
parent c110ddff66
commit e9c298713e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 253 additions and 63 deletions

View File

@ -1,14 +1,18 @@
// todo: (refactoring) limit get_config() usage to 1 call
// overall reduce the redundant calls to StyleComputer etc.
// the goal is to configure it once...
use lscolors::{LsColors, Style}; use lscolors::{LsColors, Style};
use nu_color_config::color_from_hex; use nu_color_config::color_from_hex;
use nu_color_config::{StyleComputer, TextStyle}; use nu_color_config::{StyleComputer, TextStyle};
use nu_engine::{env::get_config, env_to_string, CallExt}; use nu_engine::{env::get_config, env_to_string, CallExt};
use nu_protocol::record;
use nu_protocol::{ use nu_protocol::{
ast::Call, ast::Call,
engine::{Command, EngineState, Stack}, engine::{Command, EngineState, Stack},
Category, Config, DataSource, Example, IntoPipelineData, ListStream, PipelineData, Category, Config, DataSource, Example, IntoPipelineData, ListStream, PipelineData,
PipelineMetadata, RawStream, Record, ShellError, Signature, Span, SyntaxShape, Type, Value, PipelineMetadata, RawStream, Record, ShellError, Signature, Span, SyntaxShape, Type, Value,
}; };
use nu_protocol::{record, TableMode};
use nu_table::common::create_nu_table_config; use nu_table::common::create_nu_table_config;
use nu_table::{ use nu_table::{
CollapsedTable, ExpandedTable, JustTable, NuTable, NuTableCell, StringResult, TableOpts, CollapsedTable, ExpandedTable, JustTable, NuTable, NuTableCell, StringResult, TableOpts,
@ -16,6 +20,7 @@ use nu_table::{
}; };
use nu_utils::get_ls_colors; use nu_utils::get_ls_colors;
use std::io::IsTerminal; use std::io::IsTerminal;
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use std::time::Instant; use std::time::Instant;
use std::{path::PathBuf, sync::atomic::AtomicBool}; use std::{path::PathBuf, sync::atomic::AtomicBool};
@ -60,12 +65,17 @@ impl Command for Table {
.input_output_types(vec![(Type::Any, Type::Any)]) .input_output_types(vec![(Type::Any, Type::Any)])
// TODO: make this more precise: what turns into string and what into raw stream // TODO: make this more precise: what turns into string and what into raw stream
.named( .named(
"start-number", "theme",
SyntaxShape::Int, SyntaxShape::String,
"row number to start viewing from", "set a table mode/theme",
Some('n'), Some('t'),
)
.named(
"index",
SyntaxShape::Any,
"set or set off a index mode/theme",
Some('i'),
) )
.switch("list", "list available table modes/themes", Some('l'))
.named( .named(
"width", "width",
SyntaxShape::Int, SyntaxShape::Int,
@ -101,6 +111,7 @@ impl Command for Table {
"abbreviate the data in the table by truncating the middle part and only showing amount provided on top and bottom", "abbreviate the data in the table by truncating the middle part and only showing amount provided on top and bottom",
Some('a'), Some('a'),
) )
.switch("list", "list available table modes/themes", Some('l'))
.category(Category::Viewers) .category(Category::Viewers)
} }
@ -112,15 +123,15 @@ impl Command for Table {
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let list_themes: bool = call.has_flag("list"); let list_themes: bool = call.has_flag("list");
let cfg = parse_table_config(call, engine_state, stack)?;
let input = CmdInput::new(engine_state, stack, call, input);
// if list argument is present we just need to return a list of supported table themes // if list argument is present we just need to return a list of supported table themes
if list_themes { if list_themes {
let val = Value::list(supported_table_modes(), Span::test_data()); let val = Value::list(supported_table_modes(), Span::test_data());
return Ok(val.into_pipeline_data()); return Ok(val.into_pipeline_data());
} }
let cfg = parse_table_config(call, engine_state, stack)?;
let input = CmdInput::new(engine_state, stack, call, input);
// reset vt processing, aka ansi because illbehaved externals can break it // reset vt processing, aka ansi because illbehaved externals can break it
#[cfg(windows)] #[cfg(windows)]
{ {
@ -179,30 +190,53 @@ impl Command for Table {
}), }),
])), ])),
}, },
Example {
description: "Change a theme",
example: r#"[[a b]; [1 2] [2 [4 4]]] | table --theme basic"#,
result: None,
},
Example {
description: "Force a show of an index",
example: r#"[[a b]; [1 2] [2 [4 4]]] | table -i"#,
result: None,
},
Example {
description: "Set an index to start from a value",
example: r#"[[a b]; [1 2] [2 [4 4]]] | table -i 100"#,
result: None,
},
Example {
description: "Remove an index",
example: r#"[[a b]; [1 2] [2 [4 4]]] | table -i false"#,
result: None,
},
] ]
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct TableConfig { struct TableConfig {
row_offset: usize, index: Option<usize>,
table_view: TableView, table_view: TableView,
term_width: usize, term_width: usize,
theme: TableMode,
abbreviation: Option<usize>, abbreviation: Option<usize>,
} }
impl TableConfig { impl TableConfig {
fn new( fn new(
row_offset: usize,
table_view: TableView, table_view: TableView,
term_width: usize, term_width: usize,
theme: TableMode,
abbreviation: Option<usize>, abbreviation: Option<usize>,
index: Option<usize>,
) -> Self { ) -> Self {
Self { Self {
row_offset, index,
table_view, table_view,
term_width, term_width,
abbreviation, abbreviation,
theme,
} }
} }
} }
@ -212,8 +246,6 @@ fn parse_table_config(
state: &EngineState, state: &EngineState,
stack: &mut Stack, stack: &mut Stack,
) -> Result<TableConfig, ShellError> { ) -> Result<TableConfig, ShellError> {
let start_num: Option<i64> = call.get_flag(state, stack, "start-number")?;
let row_offset = start_num.unwrap_or_default() as usize;
let width_param: Option<i64> = call.get_flag(state, stack, "width")?; let width_param: Option<i64> = call.get_flag(state, stack, "width")?;
let expand: bool = call.has_flag("expand"); let expand: bool = call.has_flag("expand");
let expand_limit: Option<usize> = call.get_flag(state, stack, "expand-deep")?; let expand_limit: Option<usize> = call.get_flag(state, stack, "expand-deep")?;
@ -232,13 +264,73 @@ fn parse_table_config(
flatten_separator, flatten_separator,
}, },
}; };
let theme =
get_theme_flag(call, state, stack)?.unwrap_or_else(|| get_config(state, stack).table_mode);
let index = get_index_flag(call, state, stack)?;
let term_width = get_width_param(width_param); let term_width = get_width_param(width_param);
let cfg = TableConfig::new(row_offset, table_view, term_width, abbrivation); let cfg = TableConfig::new(table_view, term_width, theme, abbrivation, index);
Ok(cfg) Ok(cfg)
} }
fn get_index_flag(
call: &Call,
state: &EngineState,
stack: &mut Stack,
) -> Result<Option<usize>, ShellError> {
let index: Option<Value> = call.get_flag(state, stack, "index")?;
let value = match index {
Some(value) => value,
None => return Ok(Some(0)),
};
match value {
Value::Bool { val, .. } => {
if val {
Ok(Some(0))
} else {
Ok(None)
}
}
Value::Int { val, internal_span } => {
if val < 0 {
Err(ShellError::UnsupportedInput {
msg: String::from("got a negative integer"),
input: val.to_string(),
msg_span: call.span(),
input_span: internal_span,
})
} else {
Ok(Some(val as usize))
}
}
Value::Nothing { .. } => Ok(Some(0)),
_ => Err(ShellError::CantConvert {
to_type: String::from("index"),
from_type: String::new(),
span: call.span(),
help: Some(String::from("supported values: [bool, int, nothing]")),
}),
}
}
fn get_theme_flag(
call: &Call,
state: &EngineState,
stack: &mut Stack,
) -> Result<Option<TableMode>, ShellError> {
call.get_flag(state, stack, "theme")?
.map(|theme: String| TableMode::from_str(&theme))
.transpose()
.map_err(|err| ShellError::CantConvert {
to_type: String::from("theme"),
from_type: String::from("string"),
span: call.span(),
help: Some(String::from(err)),
})
}
struct CmdInput<'a> { struct CmdInput<'a> {
engine_state: &'a EngineState, engine_state: &'a EngineState,
stack: &'a mut Stack, stack: &'a mut Stack,
@ -366,7 +458,17 @@ fn handle_record(
} }
let indent = (config.table_indent.left, config.table_indent.right); let indent = (config.table_indent.left, config.table_indent.right);
let opts = TableOpts::new(&config, styles, ctrlc, span, 0, cfg.term_width, indent); let opts = TableOpts::new(
&config,
styles,
ctrlc,
span,
cfg.term_width,
indent,
cfg.theme,
cfg.index.unwrap_or(0),
cfg.index.is_none(),
);
let result = build_table_kv(record, cfg.table_view, opts, span)?; let result = build_table_kv(record, cfg.table_view, opts, span)?;
let result = match result { let result = match result {
@ -581,6 +683,7 @@ struct PagingTableCreator {
elements_displayed: usize, elements_displayed: usize,
reached_end: bool, reached_end: bool,
cfg: TableConfig, cfg: TableConfig,
row_offset: usize,
} }
impl PagingTableCreator { impl PagingTableCreator {
@ -601,6 +704,7 @@ impl PagingTableCreator {
cfg, cfg,
elements_displayed: 0, elements_displayed: 0,
reached_end: false, reached_end: false,
row_offset: 0,
} }
} }
@ -657,9 +761,11 @@ impl PagingTableCreator {
style_comp, style_comp,
self.ctrlc.clone(), self.ctrlc.clone(),
self.head, self.head,
self.cfg.row_offset,
self.cfg.term_width, self.cfg.term_width,
(cfg.table_indent.left, cfg.table_indent.right), (cfg.table_indent.left, cfg.table_indent.right),
self.cfg.theme,
self.cfg.index.unwrap_or(0) + self.row_offset,
self.cfg.index.is_none(),
) )
} }
@ -770,7 +876,7 @@ impl Iterator for PagingTableCreator {
let table = self.build_table(batch); let table = self.build_table(batch);
self.cfg.row_offset += idx; self.row_offset += idx;
let config = get_config(&self.engine_state, &self.stack); let config = get_config(&self.engine_state, &self.stack);
convert_table_to_output(table, &config, &self.ctrlc, self.cfg.term_width) convert_table_to_output(table, &config, &self.ctrlc, self.cfg.term_width)
@ -858,7 +964,7 @@ fn create_empty_placeholder(
let out = TableOutput::new(table, false, false); let out = TableOutput::new(table, false, false);
let style_computer = &StyleComputer::from_config(engine_state, stack); let style_computer = &StyleComputer::from_config(engine_state, stack);
let config = create_nu_table_config(&config, style_computer, &out, false); let config = create_nu_table_config(&config, style_computer, &out, false, TableMode::default());
out.table out.table
.draw(config, termwidth) .draw(config, termwidth)

View File

@ -2812,3 +2812,52 @@ fn table_abbreviation_by_config_override() {
); );
assert_eq!(actual.out, "╭───┬─────┬─────┬────────────────╮│ # │ a │ b │ c │├───┼─────┼─────┼────────────────┤│ 0 │ 1 │ 2 │ 3 ││ 1 │ 4 │ 5 │ [list 3 items] ││ 2 │ ... │ ... │ ... ││ 3 │ 1 │ 2 │ 3 ││ 4 │ 1 │ 2 │ 3 │╰───┴─────┴─────┴────────────────╯"); assert_eq!(actual.out, "╭───┬─────┬─────┬────────────────╮│ # │ a │ b │ c │├───┼─────┼─────┼────────────────┤│ 0 │ 1 │ 2 │ 3 ││ 1 │ 4 │ 5 │ [list 3 items] ││ 2 │ ... │ ... │ ... ││ 3 │ 1 │ 2 │ 3 ││ 4 │ 1 │ 2 │ 3 │╰───┴─────┴─────┴────────────────╯");
} }
#[test]
fn table_theme_arg() {
let actual = nu!("[[a b, c]; [1 2 3] [4 5 [1 2 3]] [1 2 3]] | table --width=80 --theme light");
assert_eq!(actual.out, " # a b c ──────────────────────────── 0 1 2 3 1 4 5 [list 3 items] 2 1 2 3 ");
let actual = nu!(theme_cmd(
"basic",
false,
"[[a b, c]; [1 2 3] [4 5 [1 2 3]] [1 2 3]] | table --width=80 --theme light"
));
assert_eq!(actual.out, "─#───a───b─────────c──────── 0 1 2 3 1 4 5 [list 3 items] 2 1 2 3 ");
}
#[test]
fn table_index_arg() {
let actual = nu!("[[a b]; [1 2] [2 [4 4]]] | table --width=80 --theme basic -i false");
assert_eq!(actual.out, "+---+----------------+| a | b |+---+----------------+| 1 | 2 |+---+----------------+| 2 | [list 2 items] |+---+----------------+");
let actual = nu!("[[a b]; [1 2] [2 [4 4]]] | table --width=80 --theme basic -i true");
assert_eq!(actual.out, "+---+---+----------------+| # | a | b |+---+---+----------------+| 0 | 1 | 2 |+---+---+----------------+| 1 | 2 | [list 2 items] |+---+---+----------------+");
let actual = nu!("[[a b]; [1 2] [2 [4 4]]] | table --width=80 --theme basic -i 10");
assert_eq!(actual.out, "+----+---+----------------+| # | a | b |+----+---+----------------+| 10 | 1 | 2 |+----+---+----------------+| 11 | 2 | [list 2 items] |+----+---+----------------+");
}
#[test]
fn table_expand_index_arg() {
let actual = nu!("[[a b]; [1 2] [2 [4 4]]] | table --width=80 --theme basic --expand -i false");
assert_eq!(actual.out, "+---+-------+| a | b |+---+-------+| 1 | 2 |+---+-------+| 2 | +---+ || | | 4 | || | +---+ || | | 4 | || | +---+ |+---+-------+");
let actual = nu!("[[a b]; [1 2] [2 [4 4]]] | table --width=80 --theme basic --expand -i true");
assert_eq!(actual.out, "+---+---+-----------+| # | a | b |+---+---+-----------+| 0 | 1 | 2 |+---+---+-----------+| 1 | 2 | +---+---+ || | | | 0 | 4 | || | | +---+---+ || | | | 1 | 4 | || | | +---+---+ |+---+---+-----------+");
let actual = nu!("[[a b]; [1 2] [2 [4 4]]] | table --width=80 --theme basic --expand -i 10");
assert_eq!(actual.out, "+----+---+------------+| # | a | b |+----+---+------------+| 10 | 1 | 2 |+----+---+------------+| 11 | 2 | +----+---+ || | | | 10 | 4 | || | | +----+---+ || | | | 11 | 4 | || | | +----+---+ |+----+---+------------+");
}
#[test]
fn table_list() {
let actual = nu!("table --list");
assert_eq!(actual.out, "╭────┬────────────────╮│ 0 │ basic ││ 1 │ compact ││ 2 │ compact_double ││ 3 │ default ││ 4 │ heavy ││ 5 │ light ││ 6 │ none ││ 7 │ reinforced ││ 8 │ rounded ││ 9 │ thin ││ 10 │ with_love ││ 11 │ psql ││ 12 │ markdown ││ 13 │ dots ││ 14 │ restructured ││ 15 │ ascii_rounded ││ 16 │ basic_compact │╰────┴────────────────╯");
let actual = nu!("ls | table --list");
assert_eq!(actual.out, "╭────┬────────────────╮│ 0 │ basic ││ 1 │ compact ││ 2 │ compact_double ││ 3 │ default ││ 4 │ heavy ││ 5 │ light ││ 6 │ none ││ 7 │ reinforced ││ 8 │ rounded ││ 9 │ thin ││ 10 │ with_love ││ 11 │ psql ││ 12 │ markdown ││ 13 │ dots ││ 14 │ restructured ││ 15 │ ascii_rounded ││ 16 │ basic_compact │╰────┴────────────────╯");
let actual = nu!("table --list --theme basic");
assert_eq!(actual.out, "╭────┬────────────────╮│ 0 │ basic ││ 1 │ compact ││ 2 │ compact_double ││ 3 │ default ││ 4 │ heavy ││ 5 │ light ││ 6 │ none ││ 7 │ reinforced ││ 8 │ rounded ││ 9 │ thin ││ 10 │ with_love ││ 11 │ psql ││ 12 │ markdown ││ 13 │ dots ││ 14 │ restructured ││ 15 │ ascii_rounded ││ 16 │ basic_compact │╰────┴────────────────╯");
}

View File

@ -38,9 +38,11 @@ fn try_build_map(
style_computer, style_computer,
ctrlc, ctrlc,
Span::unknown(), Span::unknown(),
0,
usize::MAX, usize::MAX,
(config.table_indent.left, config.table_indent.right), (config.table_indent.left, config.table_indent.right),
config.table_mode,
0,
false,
); );
let result = ExpandedTable::new(None, false, String::new()).build_map(&record, opts); let result = ExpandedTable::new(None, false, String::new()).build_map(&record, opts);
match result { match result {
@ -63,10 +65,13 @@ fn try_build_list(
style_computer, style_computer,
ctrlc, ctrlc,
Span::unknown(), Span::unknown(),
0,
usize::MAX, usize::MAX,
(config.table_indent.left, config.table_indent.right), (config.table_indent.left, config.table_indent.right),
config.table_mode,
0,
false,
); );
let result = ExpandedTable::new(None, false, String::new()).build_list(&vals, opts); let result = ExpandedTable::new(None, false, String::new()).build_list(&vals, opts);
match result { match result {
Ok(Some(out)) => out, Ok(Some(out)) => out,

View File

@ -3,7 +3,7 @@ use crate::{record, Config, ShellError, Span, Value};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
#[derive(Serialize, Deserialize, Clone, Debug, Default)] #[derive(Serialize, Deserialize, Clone, Copy, Debug, Default)]
pub enum TableMode { pub enum TableMode {
Basic, Basic,
Thin, Thin,

View File

@ -17,9 +17,10 @@ pub fn create_nu_table_config(
comp: &StyleComputer, comp: &StyleComputer,
out: &TableOutput, out: &TableOutput,
expand: bool, expand: bool,
mode: TableMode,
) -> NuTableConfig { ) -> NuTableConfig {
NuTableConfig { NuTableConfig {
theme: load_theme_from_config(config), theme: load_theme(mode),
with_footer: with_footer(config, out.with_header, out.table.count_rows()), with_footer: with_footer(config, out.with_header, out.table.count_rows()),
with_index: out.with_index, with_index: out.with_index,
with_header: out.with_header, with_header: out.with_header,
@ -173,8 +174,8 @@ fn is_cfg_trim_keep_words(config: &Config) -> bool {
) )
} }
pub fn load_theme_from_config(config: &Config) -> TableTheme { pub fn load_theme(mode: TableMode) -> TableTheme {
match config.table_mode { match mode {
TableMode::Basic => TableTheme::basic(), TableMode::Basic => TableTheme::basic(),
TableMode::Thin => TableTheme::thin(), TableMode::Thin => TableTheme::thin(),
TableMode::Light => TableTheme::light(), TableMode::Light => TableTheme::light(),

View File

@ -1,11 +1,11 @@
use nu_color_config::StyleComputer; use nu_color_config::StyleComputer;
use nu_protocol::{Config, Record, Value}; use nu_protocol::{Config, Record, TableMode, Value};
use crate::UnstructuredTable; use crate::UnstructuredTable;
use crate::common::nu_value_to_string_clean; use crate::common::nu_value_to_string_clean;
use crate::{ use crate::{
common::{get_index_style, load_theme_from_config}, common::{get_index_style, load_theme},
StringResult, TableOpts, StringResult, TableOpts,
}; };
@ -13,7 +13,13 @@ pub struct CollapsedTable;
impl CollapsedTable { impl CollapsedTable {
pub fn build(value: Value, opts: TableOpts<'_>) -> StringResult { pub fn build(value: Value, opts: TableOpts<'_>) -> StringResult {
collapsed_table(value, opts.config, opts.width, opts.style_computer) collapsed_table(
value,
opts.config,
opts.width,
opts.style_computer,
opts.mode,
)
} }
} }
@ -22,10 +28,11 @@ fn collapsed_table(
config: &Config, config: &Config,
term_width: usize, term_width: usize,
style_computer: &StyleComputer, style_computer: &StyleComputer,
mode: TableMode,
) -> StringResult { ) -> StringResult {
colorize_value(&mut value, config, style_computer); colorize_value(&mut value, config, style_computer);
let theme = load_theme_from_config(config); let theme = load_theme(mode);
let mut table = UnstructuredTable::new(value, config); let mut table = UnstructuredTable::new(value, config);
let is_empty = table.truncate(&theme, term_width); let is_empty = table.truncate(&theme, term_width);
if is_empty { if is_empty {

View File

@ -3,17 +3,18 @@ use std::collections::HashMap;
use nu_color_config::{Alignment, StyleComputer, TextStyle}; use nu_color_config::{Alignment, StyleComputer, TextStyle};
use nu_engine::column::get_columns; use nu_engine::column::get_columns;
use nu_protocol::{Config, Record, ShellError, Span, TableIndexMode, Value}; use nu_protocol::{Config, Record, ShellError, Span, Value};
use tabled::grid::config::Position; use tabled::grid::config::Position;
use crate::{ use crate::{
common::{ common::{
create_nu_table_config, error_sign, get_header_style, get_index_style, create_nu_table_config, error_sign, get_header_style, get_index_style, load_theme,
load_theme_from_config, nu_value_to_string, nu_value_to_string_clean, nu_value_to_string, nu_value_to_string_clean, nu_value_to_string_colored, wrap_text,
nu_value_to_string_colored, wrap_text, NuText, StringResult, TableResult, NuText, StringResult, TableResult, INDEX_COLUMN_NAME,
INDEX_COLUMN_NAME,
}, },
string_width, NuTable, NuTableCell, TableOpts, TableOutput, string_width,
types::has_index,
NuTable, NuTableCell, TableOpts, TableOutput,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -83,11 +84,8 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
let headers = get_columns(input); let headers = get_columns(input);
let with_index = match cfg.opts.config.table_index_mode { let with_index = has_index(&cfg.opts, &headers);
TableIndexMode::Always => true, let row_offset = cfg.opts.index_offset;
TableIndexMode::Never => false,
TableIndexMode::Auto => headers.iter().any(|header| header == INDEX_COLUMN_NAME),
};
// The header with the INDEX is removed from the table headers since // The header with the INDEX is removed from the table headers since
// it is added to the natural table index // it is added to the natural table index
@ -115,7 +113,7 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
return Err(*error.clone()); return Err(*error.clone());
} }
let index = row + cfg.opts.row_offset; let index = row + row_offset;
let text = item let text = item
.as_record() .as_record()
.ok() .ok()
@ -343,7 +341,7 @@ fn expanded_table_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
} }
fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult { fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> StringResult {
let theme = load_theme_from_config(cfg.opts.config); let theme = load_theme(cfg.opts.mode);
let key_width = record let key_width = record
.columns() .columns()
.map(|col| string_width(col)) .map(|col| string_width(col))
@ -556,7 +554,8 @@ fn dive_options<'b>(cfg: &Cfg<'b>, span: Span) -> Cfg<'b> {
} }
fn maybe_expand_table(out: TableOutput, term_width: usize, opts: &TableOpts<'_>) -> StringResult { fn maybe_expand_table(out: TableOutput, term_width: usize, opts: &TableOpts<'_>) -> StringResult {
let mut table_config = create_nu_table_config(opts.config, opts.style_computer, &out, false); let mut table_config =
create_nu_table_config(opts.config, opts.style_computer, &out, false, opts.mode);
let total_width = out.table.total_width(&table_config); let total_width = out.table.total_width(&table_config);
if total_width < term_width { if total_width < term_width {
const EXPAND_THRESHOLD: f32 = 0.80; const EXPAND_THRESHOLD: f32 = 0.80;
@ -577,7 +576,13 @@ fn set_data_styles(table: &mut NuTable, styles: HashMap<Position, TextStyle>) {
} }
fn create_table_cfg(cfg: &Cfg<'_>, out: &TableOutput) -> crate::NuTableConfig { fn create_table_cfg(cfg: &Cfg<'_>, out: &TableOutput) -> crate::NuTableConfig {
create_nu_table_config(cfg.opts.config, cfg.opts.style_computer, out, false) create_nu_table_config(
cfg.opts.config,
cfg.opts.style_computer,
out,
false,
cfg.opts.mode,
)
} }
fn value_to_string(value: &Value, cfg: &Cfg<'_>) -> String { fn value_to_string(value: &Value, cfg: &Cfg<'_>) -> String {

View File

@ -1,6 +1,6 @@
use nu_color_config::TextStyle; use nu_color_config::TextStyle;
use nu_engine::column::get_columns; use nu_engine::column::get_columns;
use nu_protocol::{Config, Record, ShellError, TableIndexMode, Value}; use nu_protocol::{Config, Record, ShellError, Value};
use crate::{ use crate::{
clean_charset, colorize_space, clean_charset, colorize_space,
@ -11,6 +11,8 @@ use crate::{
NuTable, NuTableCell, StringResult, TableOpts, TableOutput, TableResult, NuTable, NuTableCell, StringResult, TableOpts, TableOutput, TableResult,
}; };
use super::has_index;
pub struct JustTable; pub struct JustTable;
impl JustTable { impl JustTable {
@ -24,7 +26,7 @@ impl JustTable {
} }
fn create_table(input: &[Value], opts: TableOpts<'_>) -> Result<Option<String>, ShellError> { fn create_table(input: &[Value], opts: TableOpts<'_>) -> Result<Option<String>, ShellError> {
match table(input, opts.row_offset, opts.clone())? { match table(input, &opts)? {
Some(mut out) => { Some(mut out) => {
let left = opts.config.table_indent.left; let left = opts.config.table_indent.left;
let right = opts.config.table_indent.right; let right = opts.config.table_indent.right;
@ -33,7 +35,7 @@ fn create_table(input: &[Value], opts: TableOpts<'_>) -> Result<Option<String>,
colorize_space(out.table.get_records_mut(), opts.style_computer); colorize_space(out.table.get_records_mut(), opts.style_computer);
let table_config = let table_config =
create_nu_table_config(opts.config, opts.style_computer, &out, false); create_nu_table_config(opts.config, opts.style_computer, &out, false, opts.mode);
Ok(out.table.draw(table_config, opts.width)) Ok(out.table.draw(table_config, opts.width))
} }
None => Ok(None), None => Ok(None),
@ -65,23 +67,21 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult {
let right = opts.config.table_indent.right; let right = opts.config.table_indent.right;
out.table.set_indent(left, right); out.table.set_indent(left, right);
let table_config = create_nu_table_config(opts.config, opts.style_computer, &out, false); let table_config =
create_nu_table_config(opts.config, opts.style_computer, &out, false, opts.mode);
let table = out.table.draw(table_config, opts.width); let table = out.table.draw(table_config, opts.width);
Ok(table) Ok(table)
} }
fn table(input: &[Value], row_offset: usize, opts: TableOpts<'_>) -> TableResult { fn table(input: &[Value], opts: &TableOpts<'_>) -> TableResult {
if input.is_empty() { if input.is_empty() {
return Ok(None); return Ok(None);
} }
let mut headers = get_columns(input); let mut headers = get_columns(input);
let with_index = match opts.config.table_index_mode { let with_index = has_index(opts, &headers);
TableIndexMode::Always => true, let row_offset = opts.index_offset;
TableIndexMode::Never => false,
TableIndexMode::Auto => headers.iter().any(|header| header == INDEX_COLUMN_NAME),
};
let with_header = !headers.is_empty(); let with_header = !headers.is_empty();
if !with_header { if !with_header {
@ -112,7 +112,7 @@ fn to_table_with_header(
headers: Vec<String>, headers: Vec<String>,
with_index: bool, with_index: bool,
row_offset: usize, row_offset: usize,
opts: TableOpts<'_>, opts: &TableOpts<'_>,
) -> Result<Option<NuTable>, ShellError> { ) -> Result<Option<NuTable>, ShellError> {
let count_rows = input.len() + 1; let count_rows = input.len() + 1;
let count_columns = headers.len(); let count_columns = headers.len();
@ -140,7 +140,7 @@ fn to_table_with_header(
let skip_index = usize::from(with_index); let skip_index = usize::from(with_index);
for (col, header) in headers.iter().enumerate().skip(skip_index) { for (col, header) in headers.iter().enumerate().skip(skip_index) {
let (text, style) = get_string_value_with_header(item, header, &opts); let (text, style) = get_string_value_with_header(item, header, opts);
table.insert((row + 1, col), text); table.insert((row + 1, col), text);
table.insert_style((row + 1, col), style); table.insert_style((row + 1, col), style);
@ -154,7 +154,7 @@ fn to_table_with_no_header(
input: &[Value], input: &[Value],
with_index: bool, with_index: bool,
row_offset: usize, row_offset: usize,
opts: TableOpts<'_>, opts: &TableOpts<'_>,
) -> Result<Option<NuTable>, ShellError> { ) -> Result<Option<NuTable>, ShellError> {
let mut table = NuTable::new(input.len(), with_index as usize + 1); let mut table = NuTable::new(input.len(), with_index as usize + 1);
table.set_index_style(get_index_style(opts.style_computer)); table.set_index_style(get_index_style(opts.style_computer));
@ -173,7 +173,7 @@ fn to_table_with_no_header(
table.insert((row, 0), text); table.insert((row, 0), text);
} }
let (text, style) = get_string_value(item, &opts); let (text, style) = get_string_value(item, opts);
let pos = (row, with_index as usize); let pos = (row, with_index as usize);
table.insert(pos, text); table.insert(pos, text);

View File

@ -8,9 +8,9 @@ pub use collapse::CollapsedTable;
pub use expanded::ExpandedTable; pub use expanded::ExpandedTable;
pub use general::JustTable; pub use general::JustTable;
use nu_color_config::StyleComputer; use nu_color_config::StyleComputer;
use nu_protocol::{Config, Span}; use nu_protocol::{Config, Span, TableIndexMode, TableMode};
use crate::NuTable; use crate::{common::INDEX_COLUMN_NAME, NuTable};
pub struct TableOutput { pub struct TableOutput {
pub table: NuTable, pub table: NuTable,
@ -34,29 +34,46 @@ pub struct TableOpts<'a> {
config: &'a Config, config: &'a Config,
style_computer: &'a StyleComputer<'a>, style_computer: &'a StyleComputer<'a>,
span: Span, span: Span,
row_offset: usize,
width: usize, width: usize,
indent: (usize, usize), indent: (usize, usize),
mode: TableMode,
index_offset: usize,
index_remove: bool,
} }
impl<'a> TableOpts<'a> { impl<'a> TableOpts<'a> {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
config: &'a Config, config: &'a Config,
style_computer: &'a StyleComputer<'a>, style_computer: &'a StyleComputer<'a>,
ctrlc: Option<Arc<AtomicBool>>, ctrlc: Option<Arc<AtomicBool>>,
span: Span, span: Span,
row_offset: usize,
width: usize, width: usize,
indent: (usize, usize), indent: (usize, usize),
mode: TableMode,
index_offset: usize,
index_remove: bool,
) -> Self { ) -> Self {
Self { Self {
ctrlc, ctrlc,
config, config,
style_computer, style_computer,
span, span,
row_offset,
indent, indent,
width, width,
mode,
index_offset,
index_remove,
} }
} }
} }
fn has_index(opts: &TableOpts<'_>, headers: &[String]) -> bool {
let with_index = match opts.config.table_index_mode {
TableIndexMode::Always => true,
TableIndexMode::Never => false,
TableIndexMode::Auto => headers.iter().any(|header| header == INDEX_COLUMN_NAME),
};
with_index && !opts.index_remove
}