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
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 nu_color_config::color_from_hex;
use nu_color_config::{StyleComputer, TextStyle};
use nu_engine::{env::get_config, env_to_string, CallExt};
use nu_protocol::record;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Config, DataSource, Example, IntoPipelineData, ListStream, PipelineData,
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::{
CollapsedTable, ExpandedTable, JustTable, NuTable, NuTableCell, StringResult, TableOpts,
@ -16,6 +20,7 @@ use nu_table::{
};
use nu_utils::get_ls_colors;
use std::io::IsTerminal;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Instant;
use std::{path::PathBuf, sync::atomic::AtomicBool};
@ -60,12 +65,17 @@ impl Command for Table {
.input_output_types(vec![(Type::Any, Type::Any)])
// TODO: make this more precise: what turns into string and what into raw stream
.named(
"start-number",
SyntaxShape::Int,
"row number to start viewing from",
Some('n'),
"theme",
SyntaxShape::String,
"set a table mode/theme",
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(
"width",
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",
Some('a'),
)
.switch("list", "list available table modes/themes", Some('l'))
.category(Category::Viewers)
}
@ -112,15 +123,15 @@ impl Command for Table {
input: PipelineData,
) -> Result<PipelineData, ShellError> {
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_themes {
let val = Value::list(supported_table_modes(), Span::test_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
#[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)]
struct TableConfig {
row_offset: usize,
index: Option<usize>,
table_view: TableView,
term_width: usize,
theme: TableMode,
abbreviation: Option<usize>,
}
impl TableConfig {
fn new(
row_offset: usize,
table_view: TableView,
term_width: usize,
theme: TableMode,
abbreviation: Option<usize>,
index: Option<usize>,
) -> Self {
Self {
row_offset,
index,
table_view,
term_width,
abbreviation,
theme,
}
}
}
@ -212,8 +246,6 @@ fn parse_table_config(
state: &EngineState,
stack: &mut Stack,
) -> 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 expand: bool = call.has_flag("expand");
let expand_limit: Option<usize> = call.get_flag(state, stack, "expand-deep")?;
@ -232,13 +264,73 @@ fn parse_table_config(
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 cfg = TableConfig::new(row_offset, table_view, term_width, abbrivation);
let cfg = TableConfig::new(table_view, term_width, theme, abbrivation, index);
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> {
engine_state: &'a EngineState,
stack: &'a mut Stack,
@ -366,7 +458,17 @@ fn handle_record(
}
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 = match result {
@ -581,6 +683,7 @@ struct PagingTableCreator {
elements_displayed: usize,
reached_end: bool,
cfg: TableConfig,
row_offset: usize,
}
impl PagingTableCreator {
@ -601,6 +704,7 @@ impl PagingTableCreator {
cfg,
elements_displayed: 0,
reached_end: false,
row_offset: 0,
}
}
@ -657,9 +761,11 @@ impl PagingTableCreator {
style_comp,
self.ctrlc.clone(),
self.head,
self.cfg.row_offset,
self.cfg.term_width,
(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);
self.cfg.row_offset += idx;
self.row_offset += idx;
let config = get_config(&self.engine_state, &self.stack);
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 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
.draw(config, termwidth)