mirror of
https://github.com/nushell/nushell
synced 2025-01-13 05:38:57 +00:00
More refactorings
This commit is contained in:
parent
49318b91f3
commit
25629b41b6
8 changed files with 337 additions and 356 deletions
|
@ -25,17 +25,10 @@ use std::{
|
|||
use terminal_size::{Height, Width};
|
||||
use url::Url;
|
||||
|
||||
const STREAM_PAGE_SIZE: usize = 1000;
|
||||
type ShellResult<T> = Result<T, ShellError>;
|
||||
|
||||
fn get_width_param(width_param: Option<i64>) -> usize {
|
||||
if let Some(col) = width_param {
|
||||
col as usize
|
||||
} else if let Some((Width(w), Height(_))) = terminal_size::terminal_size() {
|
||||
w as usize
|
||||
} else {
|
||||
80
|
||||
}
|
||||
}
|
||||
const STREAM_PAGE_SIZE: usize = 1000;
|
||||
const DEFAULT_TABLE_WIDTH: usize = 80;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Table;
|
||||
|
@ -119,16 +112,14 @@ impl Command for Table {
|
|||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
) -> ShellResult<PipelineData> {
|
||||
let list_themes: bool = call.has_flag(engine_state, stack, "list")?;
|
||||
// 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 cwd = engine_state.cwd(Some(stack))?;
|
||||
let cfg = parse_table_config(call, engine_state, stack)?;
|
||||
let input = CmdInput::new(engine_state, stack, call, input);
|
||||
let input = CmdInput::parse(engine_state, stack, call, input)?;
|
||||
|
||||
// reset vt processing, aka ansi because illbehaved externals can break it
|
||||
#[cfg(windows)]
|
||||
|
@ -136,7 +127,7 @@ impl Command for Table {
|
|||
let _ = nu_utils::enable_vt_processing();
|
||||
}
|
||||
|
||||
handle_table_command(input, cfg, cwd)
|
||||
handle_table_command(input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -221,74 +212,119 @@ impl Command for Table {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
struct TableConfig {
|
||||
index: Option<usize>,
|
||||
table_view: TableView,
|
||||
term_width: usize,
|
||||
view: TableView,
|
||||
width: usize,
|
||||
theme: TableMode,
|
||||
abbreviation: Option<usize>,
|
||||
index: Option<usize>,
|
||||
}
|
||||
|
||||
impl TableConfig {
|
||||
fn new(
|
||||
table_view: TableView,
|
||||
term_width: usize,
|
||||
view: TableView,
|
||||
width: usize,
|
||||
theme: TableMode,
|
||||
abbreviation: Option<usize>,
|
||||
index: Option<usize>,
|
||||
) -> Self {
|
||||
Self {
|
||||
index,
|
||||
table_view,
|
||||
term_width,
|
||||
abbreviation,
|
||||
view,
|
||||
width,
|
||||
theme,
|
||||
abbreviation,
|
||||
index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum TableView {
|
||||
General,
|
||||
Collapsed,
|
||||
Expanded {
|
||||
limit: Option<usize>,
|
||||
flatten: bool,
|
||||
flatten_separator: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
struct CLIArgs {
|
||||
width: Option<i64>,
|
||||
abbrivation: Option<usize>,
|
||||
theme: TableMode,
|
||||
expand: bool,
|
||||
expand_limit: Option<usize>,
|
||||
expand_flatten: bool,
|
||||
expand_flatten_separator: Option<String>,
|
||||
collapse: bool,
|
||||
index: Option<usize>,
|
||||
}
|
||||
|
||||
fn parse_table_config(
|
||||
call: &Call,
|
||||
state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
) -> Result<TableConfig, ShellError> {
|
||||
let width_param: Option<i64> = call.get_flag(state, stack, "width")?;
|
||||
let expand: bool = call.has_flag(state, stack, "expand")?;
|
||||
let expand_limit: Option<usize> = call.get_flag(state, stack, "expand-deep")?;
|
||||
let collapse: bool = call.has_flag(state, stack, "collapse")?;
|
||||
let flatten: bool = call.has_flag(state, stack, "flatten")?;
|
||||
let flatten_separator: Option<String> = call.get_flag(state, stack, "flatten-separator")?;
|
||||
let abbrivation: Option<usize> = call
|
||||
.get_flag(state, stack, "abbreviated")?
|
||||
.or_else(|| stack.get_config(state).table.abbreviated_row_count);
|
||||
let table_view = match (expand, collapse) {
|
||||
) -> ShellResult<TableConfig> {
|
||||
let args = get_cli_args(call, state, stack)?;
|
||||
let table_view = get_table_view(&args);
|
||||
let term_width = get_table_width(args.width);
|
||||
|
||||
let cfg = TableConfig::new(
|
||||
table_view,
|
||||
term_width,
|
||||
args.theme,
|
||||
args.abbrivation,
|
||||
args.index,
|
||||
);
|
||||
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
fn get_table_view(args: &CLIArgs) -> TableView {
|
||||
match (args.expand, args.collapse) {
|
||||
(false, false) => TableView::General,
|
||||
(_, true) => TableView::Collapsed,
|
||||
(true, _) => TableView::Expanded {
|
||||
limit: expand_limit,
|
||||
flatten,
|
||||
flatten_separator,
|
||||
limit: args.expand_limit,
|
||||
flatten: args.expand_flatten,
|
||||
flatten_separator: args.expand_flatten_separator.clone(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cli_args(call: &Call<'_>, state: &EngineState, stack: &mut Stack) -> ShellResult<CLIArgs> {
|
||||
let width: Option<i64> = call.get_flag(state, stack, "width")?;
|
||||
let expand: bool = call.has_flag(state, stack, "expand")?;
|
||||
let expand_limit: Option<usize> = call.get_flag(state, stack, "expand-deep")?;
|
||||
let expand_flatten: bool = call.has_flag(state, stack, "flatten")?;
|
||||
let expand_flatten_separator: Option<String> =
|
||||
call.get_flag(state, stack, "flatten-separator")?;
|
||||
let collapse: bool = call.has_flag(state, stack, "collapse")?;
|
||||
let abbrivation: Option<usize> = call
|
||||
.get_flag(state, stack, "abbreviated")?
|
||||
.or_else(|| stack.get_config(state).table.abbreviated_row_count);
|
||||
let theme =
|
||||
get_theme_flag(call, state, stack)?.unwrap_or_else(|| stack.get_config(state).table.mode);
|
||||
let index = get_index_flag(call, state, stack)?;
|
||||
|
||||
let term_width = get_width_param(width_param);
|
||||
|
||||
Ok(TableConfig::new(
|
||||
table_view,
|
||||
term_width,
|
||||
theme,
|
||||
Ok(CLIArgs {
|
||||
abbrivation,
|
||||
collapse,
|
||||
expand,
|
||||
expand_limit,
|
||||
expand_flatten,
|
||||
expand_flatten_separator,
|
||||
width,
|
||||
theme,
|
||||
index,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn get_index_flag(
|
||||
call: &Call,
|
||||
state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
) -> Result<Option<usize>, ShellError> {
|
||||
) -> ShellResult<Option<usize>> {
|
||||
let index: Option<Value> = call.get_flag(state, stack, "index")?;
|
||||
let value = match index {
|
||||
Some(value) => value,
|
||||
|
@ -329,7 +365,7 @@ fn get_theme_flag(
|
|||
call: &Call,
|
||||
state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
) -> Result<Option<TableMode>, ShellError> {
|
||||
) -> ShellResult<Option<TableMode>> {
|
||||
call.get_flag(state, stack, "theme")?
|
||||
.map(|theme: String| {
|
||||
TableMode::from_str(&theme).map_err(|err| ShellError::CantConvert {
|
||||
|
@ -347,29 +383,36 @@ struct CmdInput<'a> {
|
|||
stack: &'a mut Stack,
|
||||
call: &'a Call<'a>,
|
||||
data: PipelineData,
|
||||
cfg: TableConfig,
|
||||
cwd: nu_path::PathBuf<Absolute>,
|
||||
}
|
||||
|
||||
impl<'a> CmdInput<'a> {
|
||||
fn new(
|
||||
fn parse(
|
||||
engine_state: &'a EngineState,
|
||||
stack: &'a mut Stack,
|
||||
call: &'a Call<'a>,
|
||||
data: PipelineData,
|
||||
) -> Self {
|
||||
Self {
|
||||
) -> ShellResult<Self> {
|
||||
let cwd = engine_state.cwd(Some(stack))?;
|
||||
let cfg = parse_table_config(call, engine_state, stack)?;
|
||||
|
||||
Ok(Self {
|
||||
engine_state,
|
||||
stack,
|
||||
call,
|
||||
data,
|
||||
}
|
||||
cfg,
|
||||
cwd,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_config(&self) -> std::sync::Arc<Config> {
|
||||
self.stack.get_config(self.engine_state)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_table_command(
|
||||
mut input: CmdInput<'_>,
|
||||
cfg: TableConfig,
|
||||
cwd: nu_path::PathBuf<Absolute>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
fn handle_table_command(mut input: CmdInput<'_>) -> ShellResult<PipelineData> {
|
||||
let span = input.data.span().unwrap_or(input.call.head);
|
||||
match input.data {
|
||||
// Binary streams should behave as if they really are `binary` data, and printed as hex
|
||||
|
@ -391,15 +434,15 @@ fn handle_table_command(
|
|||
let stream = ListStream::new(vals.into_iter(), span, signals);
|
||||
input.data = PipelineData::Empty;
|
||||
|
||||
handle_row_stream(input, cfg, stream, metadata, cwd)
|
||||
handle_row_stream(input, stream, metadata)
|
||||
}
|
||||
PipelineData::ListStream(stream, metadata) => {
|
||||
input.data = PipelineData::Empty;
|
||||
handle_row_stream(input, cfg, stream, metadata, cwd)
|
||||
handle_row_stream(input, stream, metadata)
|
||||
}
|
||||
PipelineData::Value(Value::Record { val, .. }, ..) => {
|
||||
input.data = PipelineData::Empty;
|
||||
handle_record(input, cfg, val.into_owned())
|
||||
handle_record(input, val.into_owned())
|
||||
}
|
||||
PipelineData::Value(Value::Error { error, .. }, ..) => {
|
||||
// Propagate this error outward, so that it goes to stderr
|
||||
|
@ -415,7 +458,7 @@ fn handle_table_command(
|
|||
let stream =
|
||||
ListStream::new(val.into_range_iter(span, Signals::empty()), span, signals);
|
||||
input.data = PipelineData::Empty;
|
||||
handle_row_stream(input, cfg, stream, metadata, cwd)
|
||||
handle_row_stream(input, stream, metadata)
|
||||
}
|
||||
x => Ok(x),
|
||||
}
|
||||
|
@ -490,59 +533,55 @@ fn pretty_hex_stream(stream: ByteStream, span: Span) -> ByteStream {
|
|||
)
|
||||
}
|
||||
|
||||
fn handle_record(
|
||||
input: CmdInput,
|
||||
cfg: TableConfig,
|
||||
mut record: Record,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let config = {
|
||||
let state = input.engine_state;
|
||||
let stack: &Stack = input.stack;
|
||||
stack.get_config(state)
|
||||
};
|
||||
fn handle_record(input: CmdInput, mut record: Record) -> ShellResult<PipelineData> {
|
||||
let span = input.data.span().unwrap_or(input.call.head);
|
||||
let styles = &StyleComputer::from_config(input.engine_state, input.stack);
|
||||
|
||||
if record.is_empty() {
|
||||
let value =
|
||||
create_empty_placeholder("record", cfg.term_width, input.engine_state, input.stack);
|
||||
create_empty_placeholder("record", input.cfg.width, input.engine_state, input.stack);
|
||||
let value = Value::string(value, span);
|
||||
return Ok(value.into_pipeline_data());
|
||||
};
|
||||
|
||||
if let Some(limit) = cfg.abbreviation {
|
||||
let prev_len = record.len();
|
||||
if record.len() > limit * 2 + 1 {
|
||||
// TODO: see if the following table builders would be happy with a simple iterator
|
||||
let mut record_iter = record.into_iter();
|
||||
record = Record::with_capacity(limit * 2 + 1);
|
||||
record.extend(record_iter.by_ref().take(limit));
|
||||
record.push(String::from("..."), Value::string("...", Span::unknown()));
|
||||
record.extend(record_iter.skip(prev_len - 2 * limit));
|
||||
}
|
||||
if let Some(limit) = input.cfg.abbreviation {
|
||||
record = make_record_abbreviation(record, limit);
|
||||
}
|
||||
|
||||
let opts = TableOpts::new(
|
||||
let config = input.get_config();
|
||||
let opts = create_table_opts(
|
||||
input.engine_state,
|
||||
input.stack,
|
||||
&config,
|
||||
styles,
|
||||
input.engine_state.signals(),
|
||||
&input.cfg,
|
||||
span,
|
||||
cfg.term_width,
|
||||
config.table.padding,
|
||||
cfg.theme,
|
||||
cfg.index.unwrap_or(0),
|
||||
cfg.index.is_none(),
|
||||
0,
|
||||
);
|
||||
let result = build_table_kv(record, cfg.table_view, opts, span)?;
|
||||
let result = build_table_kv(record, input.cfg.view.clone(), opts, span)?;
|
||||
|
||||
let result = match result {
|
||||
Some(output) => maybe_strip_color(output, &config),
|
||||
None => report_unsuccessful_output(input.engine_state.signals(), cfg.term_width),
|
||||
None => report_unsuccessful_output(input.engine_state.signals(), input.cfg.width),
|
||||
};
|
||||
|
||||
let val = Value::string(result, span);
|
||||
let data = val.into_pipeline_data();
|
||||
|
||||
Ok(val.into_pipeline_data())
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
fn make_record_abbreviation(mut record: Record, limit: usize) -> Record {
|
||||
if record.len() <= limit * 2 + 1 {
|
||||
return record;
|
||||
}
|
||||
|
||||
// TODO: see if the following table builders would be happy with a simple iterator
|
||||
let prev_len = record.len();
|
||||
let mut record_iter = record.into_iter();
|
||||
record = Record::with_capacity(limit * 2 + 1);
|
||||
record.extend(record_iter.by_ref().take(limit));
|
||||
record.push(String::from("..."), Value::string("...", Span::unknown()));
|
||||
record.extend(record_iter.skip(prev_len - 2 * limit));
|
||||
record
|
||||
}
|
||||
|
||||
fn report_unsuccessful_output(signals: &Signals, term_width: usize) -> String {
|
||||
|
@ -580,11 +619,11 @@ fn build_table_kv(
|
|||
|
||||
fn build_table_batch(
|
||||
vals: Vec<Value>,
|
||||
table_view: TableView,
|
||||
view: TableView,
|
||||
opts: TableOpts<'_>,
|
||||
span: Span,
|
||||
) -> StringResult {
|
||||
match table_view {
|
||||
match view {
|
||||
TableView::General => JustTable::table(&vals, opts),
|
||||
TableView::Expanded {
|
||||
limit,
|
||||
|
@ -603,22 +642,17 @@ fn build_table_batch(
|
|||
|
||||
fn handle_row_stream(
|
||||
input: CmdInput<'_>,
|
||||
cfg: TableConfig,
|
||||
stream: ListStream,
|
||||
metadata: Option<PipelineMetadata>,
|
||||
cwd: nu_path::PathBuf<Absolute>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
) -> ShellResult<PipelineData> {
|
||||
let cfg = input.get_config();
|
||||
let stream = match metadata.as_ref() {
|
||||
// First, `ls` sources:
|
||||
Some(PipelineMetadata {
|
||||
data_source: DataSource::Ls,
|
||||
..
|
||||
}) => {
|
||||
let config = {
|
||||
let state = input.engine_state;
|
||||
let stack: &Stack = input.stack;
|
||||
stack.get_config(state)
|
||||
};
|
||||
let config = cfg.clone();
|
||||
let ls_colors_env_str = match input.stack.get_env_var(input.engine_state, "LS_COLORS") {
|
||||
Some(v) => Some(env_to_string(
|
||||
"LS_COLORS",
|
||||
|
@ -637,7 +671,7 @@ fn handle_row_stream(
|
|||
let span = value.span();
|
||||
if let Value::String { val, .. } = value {
|
||||
if let Some(val) =
|
||||
render_path_name(val, &config, &ls_colors, cwd.clone(), span)
|
||||
render_path_name(val, &config, &ls_colors, input.cwd.clone(), span)
|
||||
{
|
||||
*value = val;
|
||||
}
|
||||
|
@ -693,6 +727,7 @@ fn handle_row_stream(
|
|||
// for the values it outputs. Because engine_state is passed in, config doesn't need to.
|
||||
input.engine_state.clone(),
|
||||
input.stack.clone(),
|
||||
input.cfg,
|
||||
cfg,
|
||||
);
|
||||
let stream = ByteStream::from_result_iter(
|
||||
|
@ -735,8 +770,9 @@ struct PagingTableCreator {
|
|||
stack: Stack,
|
||||
elements_displayed: usize,
|
||||
reached_end: bool,
|
||||
cfg: TableConfig,
|
||||
table_config: TableConfig,
|
||||
row_offset: usize,
|
||||
config: std::sync::Arc<Config>,
|
||||
}
|
||||
|
||||
impl PagingTableCreator {
|
||||
|
@ -745,114 +781,51 @@ impl PagingTableCreator {
|
|||
stream: ListStream,
|
||||
engine_state: EngineState,
|
||||
stack: Stack,
|
||||
cfg: TableConfig,
|
||||
table_config: TableConfig,
|
||||
config: std::sync::Arc<Config>,
|
||||
) -> Self {
|
||||
PagingTableCreator {
|
||||
head,
|
||||
stream: stream.into_inner(),
|
||||
engine_state,
|
||||
stack,
|
||||
cfg,
|
||||
config,
|
||||
table_config,
|
||||
elements_displayed: 0,
|
||||
reached_end: false,
|
||||
row_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_extended(
|
||||
&mut self,
|
||||
batch: Vec<Value>,
|
||||
limit: Option<usize>,
|
||||
flatten: bool,
|
||||
flatten_separator: Option<String>,
|
||||
) -> StringResult {
|
||||
fn build_table(&mut self, batch: Vec<Value>) -> ShellResult<Option<String>> {
|
||||
if batch.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let cfg = {
|
||||
let state = &self.engine_state;
|
||||
let stack = &self.stack;
|
||||
stack.get_config(state)
|
||||
};
|
||||
let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack);
|
||||
let opts = self.create_table_opts(&cfg, &style_comp);
|
||||
let view = TableView::Expanded {
|
||||
limit,
|
||||
flatten,
|
||||
flatten_separator,
|
||||
};
|
||||
|
||||
build_table_batch(batch, view, opts, self.head)
|
||||
let opts = self.create_table_opts();
|
||||
build_table_batch(batch, self.table_config.view.clone(), opts, self.head)
|
||||
}
|
||||
|
||||
fn build_collapsed(&mut self, batch: Vec<Value>) -> StringResult {
|
||||
if batch.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let cfg = {
|
||||
let state = &self.engine_state;
|
||||
let stack = &self.stack;
|
||||
stack.get_config(state)
|
||||
};
|
||||
let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack);
|
||||
let opts = self.create_table_opts(&cfg, &style_comp);
|
||||
|
||||
build_table_batch(batch, TableView::Collapsed, opts, self.head)
|
||||
}
|
||||
|
||||
fn build_general(&mut self, batch: Vec<Value>) -> StringResult {
|
||||
let cfg = {
|
||||
let state = &self.engine_state;
|
||||
let stack = &self.stack;
|
||||
stack.get_config(state)
|
||||
};
|
||||
let style_comp = StyleComputer::from_config(&self.engine_state, &self.stack);
|
||||
let opts = self.create_table_opts(&cfg, &style_comp);
|
||||
|
||||
build_table_batch(batch, TableView::General, opts, self.head)
|
||||
}
|
||||
|
||||
fn create_table_opts<'a>(
|
||||
&'a self,
|
||||
cfg: &'a Config,
|
||||
style_comp: &'a StyleComputer<'a>,
|
||||
) -> TableOpts<'a> {
|
||||
TableOpts::new(
|
||||
cfg,
|
||||
style_comp,
|
||||
self.engine_state.signals(),
|
||||
fn create_table_opts(&self) -> TableOpts<'_> {
|
||||
create_table_opts(
|
||||
&self.engine_state,
|
||||
&self.stack,
|
||||
&self.config,
|
||||
&self.table_config,
|
||||
self.head,
|
||||
self.cfg.term_width,
|
||||
cfg.table.padding,
|
||||
self.cfg.theme,
|
||||
self.cfg.index.unwrap_or(0) + self.row_offset,
|
||||
self.cfg.index.is_none(),
|
||||
self.row_offset,
|
||||
)
|
||||
}
|
||||
|
||||
fn build_table(&mut self, batch: Vec<Value>) -> Result<Option<String>, ShellError> {
|
||||
match &self.cfg.table_view {
|
||||
TableView::General => self.build_general(batch),
|
||||
TableView::Collapsed => self.build_collapsed(batch),
|
||||
TableView::Expanded {
|
||||
limit,
|
||||
flatten,
|
||||
flatten_separator,
|
||||
} => self.build_extended(batch, *limit, *flatten, flatten_separator.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PagingTableCreator {
|
||||
type Item = Result<Vec<u8>, ShellError>;
|
||||
type Item = ShellResult<Vec<u8>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let batch;
|
||||
let end;
|
||||
|
||||
match self.cfg.abbreviation {
|
||||
match self.table_config.abbreviation {
|
||||
Some(abbr) => {
|
||||
(batch, _, end) =
|
||||
stream_collect_abbriviated(&mut self.stream, abbr, self.engine_state.signals());
|
||||
|
@ -882,7 +855,7 @@ impl Iterator for PagingTableCreator {
|
|||
self.elements_displayed = 1;
|
||||
let result = create_empty_placeholder(
|
||||
"list",
|
||||
self.cfg.term_width,
|
||||
self.table_config.width,
|
||||
&self.engine_state,
|
||||
&self.stack,
|
||||
);
|
||||
|
@ -896,16 +869,11 @@ impl Iterator for PagingTableCreator {
|
|||
|
||||
self.row_offset += batch_size;
|
||||
|
||||
let config = {
|
||||
let state = &self.engine_state;
|
||||
let stack = &self.stack;
|
||||
stack.get_config(state)
|
||||
};
|
||||
convert_table_to_output(
|
||||
table,
|
||||
&config,
|
||||
&self.config,
|
||||
self.engine_state.signals(),
|
||||
self.cfg.term_width,
|
||||
self.table_config.width,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1050,17 +1018,6 @@ fn render_path_name(
|
|||
Some(Value::string(val, span))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum TableView {
|
||||
General,
|
||||
Collapsed,
|
||||
Expanded {
|
||||
limit: Option<usize>,
|
||||
flatten: bool,
|
||||
flatten_separator: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
fn maybe_strip_color(output: String, config: &Config) -> String {
|
||||
// the terminal is for when people do ls from vim, there should be no coloring there
|
||||
if !config.use_ansi_coloring || !std::io::stdout().is_terminal() {
|
||||
|
@ -1098,11 +1055,11 @@ fn create_empty_placeholder(
|
|||
}
|
||||
|
||||
fn convert_table_to_output(
|
||||
table: Result<Option<String>, ShellError>,
|
||||
table: ShellResult<Option<String>>,
|
||||
config: &Config,
|
||||
signals: &Signals,
|
||||
term_width: usize,
|
||||
) -> Option<Result<Vec<u8>, ShellError>> {
|
||||
) -> Option<ShellResult<Vec<u8>>> {
|
||||
match table {
|
||||
Ok(Some(table)) => {
|
||||
let table = maybe_strip_color(table, config);
|
||||
|
@ -1148,3 +1105,31 @@ fn supported_table_modes() -> Vec<Value> {
|
|||
Value::test_string("basic_compact"),
|
||||
]
|
||||
}
|
||||
|
||||
fn create_table_opts<'a>(
|
||||
engine_state: &'a EngineState,
|
||||
stack: &'a Stack,
|
||||
cfg: &'a Config,
|
||||
table_cfg: &'a TableConfig,
|
||||
span: Span,
|
||||
offset: usize,
|
||||
) -> TableOpts<'a> {
|
||||
let comp = StyleComputer::from_config(engine_state, stack);
|
||||
let signals = engine_state.signals();
|
||||
let offset = table_cfg.index.unwrap_or(0) + offset;
|
||||
let index = table_cfg.index.is_none();
|
||||
let width = table_cfg.width;
|
||||
let theme = table_cfg.theme;
|
||||
|
||||
TableOpts::new(cfg, comp, signals, span, width, theme, offset, index)
|
||||
}
|
||||
|
||||
fn get_table_width(width: Option<i64>) -> usize {
|
||||
if let Some(col) = width {
|
||||
col as usize
|
||||
} else if let Some((Width(w), Height(_))) = terminal_size::terminal_size() {
|
||||
w as usize
|
||||
} else {
|
||||
DEFAULT_TABLE_WIDTH
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,12 +69,9 @@ fn convert_value_to_string(
|
|||
} else {
|
||||
let config = engine_state.get_config();
|
||||
let style_computer = StyleComputer::from_config(engine_state, stack);
|
||||
let table =
|
||||
nu_common::try_build_table(value, engine_state.signals(), config, style_computer);
|
||||
|
||||
Ok(nu_common::try_build_table(
|
||||
engine_state.signals(),
|
||||
config,
|
||||
&style_computer,
|
||||
value,
|
||||
))
|
||||
Ok(table)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,80 +1,57 @@
|
|||
use crate::nu_common::NuConfig;
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{Record, Signals, Span, Value};
|
||||
use nu_protocol::{Record, Signals, Value};
|
||||
use nu_table::{
|
||||
common::{nu_value_to_string, nu_value_to_string_clean},
|
||||
ExpandedTable, TableOpts,
|
||||
};
|
||||
|
||||
pub fn try_build_table(
|
||||
value: Value,
|
||||
signals: &Signals,
|
||||
config: &NuConfig,
|
||||
style_computer: &StyleComputer,
|
||||
value: Value,
|
||||
style_computer: StyleComputer,
|
||||
) -> String {
|
||||
let span = value.span();
|
||||
match value {
|
||||
Value::List { vals, .. } => try_build_list(vals, signals, config, span, style_computer),
|
||||
Value::Record { val, .. } => try_build_map(&val, span, style_computer, signals, config),
|
||||
val if matches!(val, Value::String { .. }) => {
|
||||
nu_value_to_string_clean(&val, config, style_computer).0
|
||||
}
|
||||
val => nu_value_to_string(&val, config, style_computer).0,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_build_map(
|
||||
record: &Record,
|
||||
span: Span,
|
||||
style_computer: &StyleComputer,
|
||||
signals: &Signals,
|
||||
config: &NuConfig,
|
||||
) -> String {
|
||||
let opts = TableOpts::new(
|
||||
config,
|
||||
style_computer,
|
||||
signals,
|
||||
Span::unknown(),
|
||||
span,
|
||||
usize::MAX,
|
||||
config.table.padding,
|
||||
config.table.mode,
|
||||
0,
|
||||
false,
|
||||
);
|
||||
let result = ExpandedTable::new(None, false, String::new()).build_map(record, opts);
|
||||
match value {
|
||||
Value::List { vals, .. } => try_build_list(vals, opts),
|
||||
Value::Record { val, .. } => try_build_map(&val, opts),
|
||||
val if matches!(val, Value::String { .. }) => {
|
||||
nu_value_to_string_clean(&val, config, &opts.style_computer).0
|
||||
}
|
||||
val => nu_value_to_string(&val, config, &opts.style_computer).0,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_build_map(record: &Record, opts: TableOpts<'_>) -> String {
|
||||
let result = ExpandedTable::new(None, false, String::new()).build_map(record, opts.clone());
|
||||
match result {
|
||||
Ok(Some(result)) => result,
|
||||
Ok(None) | Err(_) => {
|
||||
nu_value_to_string(&Value::record(record.clone(), span), config, style_computer).0
|
||||
_ => {
|
||||
let value = Value::record(record.clone(), opts.span);
|
||||
nu_value_to_string(&value, opts.config, &opts.style_computer).0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_build_list(
|
||||
vals: Vec<Value>,
|
||||
signals: &Signals,
|
||||
config: &NuConfig,
|
||||
span: Span,
|
||||
style_computer: &StyleComputer,
|
||||
) -> String {
|
||||
let opts = TableOpts::new(
|
||||
config,
|
||||
style_computer,
|
||||
signals,
|
||||
Span::unknown(),
|
||||
usize::MAX,
|
||||
config.table.padding,
|
||||
config.table.mode,
|
||||
0,
|
||||
false,
|
||||
);
|
||||
|
||||
let result = ExpandedTable::new(None, false, String::new()).build_list(&vals, opts);
|
||||
fn try_build_list(vals: Vec<Value>, opts: TableOpts<'_>) -> String {
|
||||
let result = ExpandedTable::new(None, false, String::new()).build_list(&vals, opts.clone());
|
||||
match result {
|
||||
Ok(Some(out)) => out,
|
||||
Ok(None) | Err(_) => {
|
||||
_ => {
|
||||
// it means that the list is empty
|
||||
nu_value_to_string(&Value::list(vals, span), config, style_computer).0
|
||||
let value = Value::list(vals, opts.span);
|
||||
nu_value_to_string(&value, opts.config, &opts.style_computer).0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,11 @@ impl NuTable {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_row(&mut self, index: usize, row: Vec<NuRecordsValue>) {
|
||||
assert_eq!(self.data[index].len(), row.len());
|
||||
self.data[index] = row;
|
||||
}
|
||||
|
||||
pub fn set_column_style(&mut self, column: usize, style: TextStyle) {
|
||||
if let Some(style) = style.color_style {
|
||||
let style = convert_style(style);
|
||||
|
|
|
@ -17,7 +17,7 @@ impl CollapsedTable {
|
|||
}
|
||||
|
||||
fn collapsed_table(mut value: Value, opts: TableOpts<'_>) -> StringResult {
|
||||
colorize_value(&mut value, opts.config, opts.style_computer);
|
||||
colorize_value(&mut value, opts.config, &opts.style_computer);
|
||||
|
||||
let mut table = UnstructuredTable::new(value, opts.config);
|
||||
|
||||
|
@ -27,7 +27,7 @@ fn collapsed_table(mut value: Value, opts: TableOpts<'_>) -> StringResult {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let table = table.draw(&theme, opts.config.table.padding, opts.style_computer);
|
||||
let table = table.draw(&theme, opts.config.table.padding, &opts.style_computer);
|
||||
|
||||
Ok(Some(table))
|
||||
}
|
||||
|
|
|
@ -45,16 +45,14 @@ impl ExpandedTable {
|
|||
}
|
||||
|
||||
pub fn build_list(self, vals: &[Value], opts: TableOpts<'_>) -> StringResult {
|
||||
let cfg = Cfg {
|
||||
opts: opts.clone(),
|
||||
format: self,
|
||||
};
|
||||
let out = match expand_list(vals, cfg)? {
|
||||
let cfg = Cfg { opts, format: self };
|
||||
let output = expand_list(vals, cfg.clone())?;
|
||||
let output = match output {
|
||||
Some(out) => out,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
maybe_expand_table(out, opts.width, &opts)
|
||||
maybe_expand_table(output, cfg.opts.width, &cfg.opts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +179,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
cfg.opts.signals.check(cfg.opts.span)?;
|
||||
check_value(item)?;
|
||||
|
||||
let inner_cfg = update_config(&cfg, available_width);
|
||||
let inner_cfg = cfg_expand_reset_table(cfg.clone(), available_width);
|
||||
let mut cell = expand_entry(item, inner_cfg);
|
||||
|
||||
let value_width = string_width(&cell.text);
|
||||
|
@ -202,8 +200,11 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
}
|
||||
|
||||
let mut table = NuTable::from(data);
|
||||
table.set_indent(cfg.opts.indent.left, cfg.opts.indent.right);
|
||||
table.set_index_style(get_index_style(cfg.opts.style_computer));
|
||||
table.set_indent(
|
||||
cfg.opts.config.table.padding.left,
|
||||
cfg.opts.config.table.padding.right,
|
||||
);
|
||||
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, rows_count)));
|
||||
|
@ -267,7 +268,7 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
cfg.opts.signals.check(cfg.opts.span)?;
|
||||
check_value(item)?;
|
||||
|
||||
let inner_cfg = update_config(&cfg, available);
|
||||
let inner_cfg = cfg_expand_reset_table(cfg.clone(), available);
|
||||
let mut cell = expand_entry_with_header(item, &header, inner_cfg);
|
||||
|
||||
let mut value_width = string_width(&cell.text);
|
||||
|
@ -360,9 +361,12 @@ fn expand_list(input: &[Value], cfg: Cfg<'_>) -> TableResult {
|
|||
}
|
||||
|
||||
let mut table = NuTable::from(data);
|
||||
table.set_index_style(get_index_style(cfg.opts.style_computer));
|
||||
table.set_header_style(get_header_style(cfg.opts.style_computer));
|
||||
table.set_indent(cfg.opts.indent.left, cfg.opts.indent.right);
|
||||
table.set_index_style(get_index_style(&cfg.opts.style_computer));
|
||||
table.set_header_style(get_header_style(&cfg.opts.style_computer));
|
||||
table.set_indent(
|
||||
cfg.opts.config.table.padding.left,
|
||||
cfg.opts.config.table.padding.right,
|
||||
);
|
||||
set_data_styles(&mut table, data_styles);
|
||||
|
||||
Ok(Some(TableOutput::new(table, true, with_index, rows_count)))
|
||||
|
@ -417,7 +421,10 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> CellResult {
|
|||
|
||||
let mut table = NuTable::from(data);
|
||||
table.set_index_style(get_key_style(&cfg));
|
||||
table.set_indent(cfg.opts.indent.left, cfg.opts.indent.right);
|
||||
table.set_indent(
|
||||
cfg.opts.config.table.padding.left,
|
||||
cfg.opts.config.table.padding.right,
|
||||
);
|
||||
|
||||
let out = TableOutput::new(table, false, true, count_rows);
|
||||
|
||||
|
@ -427,8 +434,7 @@ fn expanded_table_kv(record: &Record, cfg: Cfg<'_>) -> CellResult {
|
|||
|
||||
// the flag is used as an optimization to not do `value.lines().count()` search.
|
||||
fn expand_value(value: &Value, width: usize, cfg: &Cfg<'_>) -> CellResult {
|
||||
let is_limited = matches!(cfg.format.expand_limit, Some(0));
|
||||
if is_limited {
|
||||
if is_limit_reached(cfg) {
|
||||
let value = value_to_string_clean(value, cfg);
|
||||
return Ok(Some(CellOutput::clean(value, 1, false)));
|
||||
}
|
||||
|
@ -436,7 +442,7 @@ fn expand_value(value: &Value, width: usize, cfg: &Cfg<'_>) -> CellResult {
|
|||
let span = value.span();
|
||||
match value {
|
||||
Value::List { vals, .. } => {
|
||||
let inner_cfg = update_config(&dive_options(cfg, span), width);
|
||||
let inner_cfg = cfg_expand_reset_table(cfg_expand_next_level(cfg.clone(), span), width);
|
||||
let table = expand_list(vals, inner_cfg)?;
|
||||
|
||||
match table {
|
||||
|
@ -462,7 +468,7 @@ fn expand_value(value: &Value, width: usize, cfg: &Cfg<'_>) -> CellResult {
|
|||
return Ok(Some(CellOutput::text(value)));
|
||||
}
|
||||
|
||||
let inner_cfg = update_config(&dive_options(cfg, span), width);
|
||||
let inner_cfg = cfg_expand_reset_table(cfg_expand_next_level(cfg.clone(), span), width);
|
||||
let result = expanded_table_kv(record, inner_cfg)?;
|
||||
match result {
|
||||
Some(result) => Ok(Some(CellOutput::clean(result.text, result.size, true))),
|
||||
|
@ -480,23 +486,22 @@ fn expand_value(value: &Value, width: usize, cfg: &Cfg<'_>) -> CellResult {
|
|||
}
|
||||
|
||||
fn get_key_style(cfg: &Cfg<'_>) -> TextStyle {
|
||||
get_header_style(cfg.opts.style_computer).alignment(Alignment::Left)
|
||||
get_header_style(&cfg.opts.style_computer).alignment(Alignment::Left)
|
||||
}
|
||||
|
||||
fn expand_entry_with_header(item: &Value, header: &str, cfg: Cfg<'_>) -> CellOutput {
|
||||
match item {
|
||||
Value::Record { val, .. } => match val.get(header) {
|
||||
Some(val) => expand_entry(val, cfg),
|
||||
None => CellOutput::styled(error_sign(cfg.opts.style_computer)),
|
||||
None => CellOutput::styled(error_sign(&cfg.opts.style_computer)),
|
||||
},
|
||||
_ => expand_entry(item, cfg),
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_entry(item: &Value, cfg: Cfg<'_>) -> CellOutput {
|
||||
let is_limit_reached = matches!(cfg.format.expand_limit, Some(0));
|
||||
if is_limit_reached {
|
||||
let value = nu_value_to_string_clean(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
if is_limit_reached(&cfg) {
|
||||
let value = nu_value_to_string_clean(item, cfg.opts.config, &cfg.opts.style_computer);
|
||||
return CellOutput::styled(value);
|
||||
}
|
||||
|
||||
|
@ -504,18 +509,18 @@ fn expand_entry(item: &Value, cfg: Cfg<'_>) -> CellOutput {
|
|||
match &item {
|
||||
Value::Record { val: record, .. } => {
|
||||
if record.is_empty() {
|
||||
let value = nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
let value = nu_value_to_string(item, cfg.opts.config, &cfg.opts.style_computer);
|
||||
return CellOutput::styled(value);
|
||||
}
|
||||
|
||||
// we verify what is the structure of a Record cause it might represent
|
||||
let inner_cfg = dive_options(&cfg, span);
|
||||
let inner_cfg = cfg_expand_next_level(cfg.clone(), span);
|
||||
let table = expanded_table_kv(record, inner_cfg);
|
||||
|
||||
match table {
|
||||
Ok(Some(table)) => table,
|
||||
_ => {
|
||||
let value = nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
let value = nu_value_to_string(item, cfg.opts.config, &cfg.opts.style_computer);
|
||||
CellOutput::styled(value)
|
||||
}
|
||||
}
|
||||
|
@ -525,19 +530,19 @@ fn expand_entry(item: &Value, cfg: Cfg<'_>) -> CellOutput {
|
|||
let value = list_to_string(
|
||||
vals,
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
&cfg.opts.style_computer,
|
||||
&cfg.format.flatten_sep,
|
||||
);
|
||||
return CellOutput::text(value);
|
||||
}
|
||||
|
||||
let inner_cfg = dive_options(&cfg, span);
|
||||
let inner_cfg = cfg_expand_next_level(cfg.clone(), span);
|
||||
let table = expand_list(vals, inner_cfg);
|
||||
|
||||
let out = match table {
|
||||
Ok(Some(out)) => out,
|
||||
_ => {
|
||||
let value = nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
let value = nu_value_to_string(item, cfg.opts.config, &cfg.opts.style_computer);
|
||||
return CellOutput::styled(value);
|
||||
}
|
||||
};
|
||||
|
@ -547,18 +552,22 @@ fn expand_entry(item: &Value, cfg: Cfg<'_>) -> CellOutput {
|
|||
match table {
|
||||
Some(table) => CellOutput::clean(table, out.count_rows, false),
|
||||
None => {
|
||||
let value = nu_value_to_string(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
let value = nu_value_to_string(item, cfg.opts.config, &cfg.opts.style_computer);
|
||||
CellOutput::styled(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let value = nu_value_to_string_clean(item, cfg.opts.config, cfg.opts.style_computer);
|
||||
let value = nu_value_to_string_clean(item, cfg.opts.config, &cfg.opts.style_computer);
|
||||
CellOutput::styled(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_limit_reached(cfg: &Cfg<'_>) -> bool {
|
||||
matches!(cfg.format.expand_limit, Some(0))
|
||||
}
|
||||
|
||||
fn is_simple_list(vals: &[Value]) -> bool {
|
||||
vals.iter()
|
||||
.all(|v| !matches!(v, Value::Record { .. } | Value::List { .. }))
|
||||
|
@ -583,19 +592,9 @@ fn list_to_string(
|
|||
buf
|
||||
}
|
||||
|
||||
fn dive_options<'b>(cfg: &Cfg<'b>, span: Span) -> Cfg<'b> {
|
||||
let mut cfg = cfg.clone();
|
||||
cfg.opts.span = span;
|
||||
if let Some(deep) = cfg.format.expand_limit.as_mut() {
|
||||
*deep -= 1
|
||||
}
|
||||
|
||||
cfg
|
||||
}
|
||||
|
||||
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, opts.mode);
|
||||
create_nu_table_config(opts.config, &opts.style_computer, &out, false, opts.mode);
|
||||
let total_width = out.table.total_width(&table_config);
|
||||
if total_width < term_width {
|
||||
const EXPAND_THRESHOLD: f32 = 0.80;
|
||||
|
@ -606,7 +605,9 @@ fn maybe_expand_table(out: TableOutput, term_width: usize, opts: &TableOpts<'_>)
|
|||
}
|
||||
}
|
||||
|
||||
Ok(out.table.draw(table_config, term_width))
|
||||
let table = out.table.draw(table_config, term_width);
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
|
||||
fn set_data_styles(table: &mut NuTable, styles: HashMap<Position, TextStyle>) {
|
||||
|
@ -618,7 +619,7 @@ fn set_data_styles(table: &mut NuTable, styles: HashMap<Position, TextStyle>) {
|
|||
fn create_table_cfg(cfg: &Cfg<'_>, out: &TableOutput) -> crate::NuTableConfig {
|
||||
create_nu_table_config(
|
||||
cfg.opts.config,
|
||||
cfg.opts.style_computer,
|
||||
&cfg.opts.style_computer,
|
||||
out,
|
||||
false,
|
||||
cfg.opts.mode,
|
||||
|
@ -626,11 +627,11 @@ fn create_table_cfg(cfg: &Cfg<'_>, out: &TableOutput) -> crate::NuTableConfig {
|
|||
}
|
||||
|
||||
fn value_to_string(value: &Value, cfg: &Cfg<'_>) -> String {
|
||||
nu_value_to_string(value, cfg.opts.config, cfg.opts.style_computer).0
|
||||
nu_value_to_string(value, cfg.opts.config, &cfg.opts.style_computer).0
|
||||
}
|
||||
|
||||
fn value_to_string_clean(value: &Value, cfg: &Cfg<'_>) -> String {
|
||||
nu_value_to_string_clean(value, cfg.opts.config, cfg.opts.style_computer).0
|
||||
nu_value_to_string_clean(value, cfg.opts.config, &cfg.opts.style_computer).0
|
||||
}
|
||||
|
||||
fn value_to_wrapped_string(value: &Value, cfg: &Cfg<'_>, value_width: usize) -> String {
|
||||
|
@ -638,13 +639,21 @@ fn value_to_wrapped_string(value: &Value, cfg: &Cfg<'_>, value_width: usize) ->
|
|||
}
|
||||
|
||||
fn value_to_wrapped_string_clean(value: &Value, cfg: &Cfg<'_>, value_width: usize) -> String {
|
||||
let text = nu_value_to_string_colored(value, cfg.opts.config, cfg.opts.style_computer);
|
||||
let text = nu_value_to_string_colored(value, cfg.opts.config, &cfg.opts.style_computer);
|
||||
wrap_text(&text, value_width, cfg.opts.config)
|
||||
}
|
||||
|
||||
fn update_config<'a>(cfg: &Cfg<'a>, width: usize) -> Cfg<'a> {
|
||||
let mut new = cfg.clone();
|
||||
new.opts.width = width;
|
||||
new.opts.index_offset = 0;
|
||||
new
|
||||
fn cfg_expand_next_level(mut cfg: Cfg<'_>, span: Span) -> Cfg<'_> {
|
||||
cfg.opts.span = span;
|
||||
if let Some(deep) = cfg.format.expand_limit.as_mut() {
|
||||
*deep -= 1
|
||||
}
|
||||
|
||||
cfg
|
||||
}
|
||||
|
||||
fn cfg_expand_reset_table(mut cfg: Cfg<'_>, width: usize) -> Cfg<'_> {
|
||||
cfg.opts.width = width;
|
||||
cfg.opts.index_offset = 0;
|
||||
cfg
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@ fn list_table(input: &[Value], opts: TableOpts<'_>) -> Result<Option<String>, Sh
|
|||
opts.config.table.padding.right,
|
||||
);
|
||||
|
||||
colorize_space(out.table.get_records_mut(), opts.style_computer);
|
||||
colorize_space(out.table.get_records_mut(), &opts.style_computer);
|
||||
|
||||
let config = create_nu_table_config(opts.config, opts.style_computer, &out, false, opts.mode);
|
||||
let config = create_nu_table_config(opts.config, &opts.style_computer, &out, false, opts.mode);
|
||||
let table = out.table.draw(config, opts.width);
|
||||
|
||||
Ok(table)
|
||||
|
@ -51,7 +51,7 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult {
|
|||
|
||||
let key = NuRecordsValue::new(column.to_string());
|
||||
|
||||
let value = nu_value_to_string_colored(value, opts.config, opts.style_computer);
|
||||
let value = nu_value_to_string_colored(value, opts.config, &opts.style_computer);
|
||||
let value = NuRecordsValue::new(value);
|
||||
|
||||
row.push(key);
|
||||
|
@ -67,7 +67,7 @@ fn kv_table(record: &Record, opts: TableOpts<'_>) -> StringResult {
|
|||
|
||||
let out = TableOutput::from_table(table, false, true);
|
||||
let table_config =
|
||||
create_nu_table_config(opts.config, opts.style_computer, &out, false, opts.mode);
|
||||
create_nu_table_config(opts.config, &opts.style_computer, &out, false, opts.mode);
|
||||
let table = out.table.draw(table_config, opts.width);
|
||||
|
||||
Ok(table)
|
||||
|
@ -100,28 +100,23 @@ fn create_table_with_header(
|
|||
headers: Vec<String>,
|
||||
opts: &TableOpts<'_>,
|
||||
) -> Result<Option<NuTable>, ShellError> {
|
||||
// The header with the INDEX is removed from the table headers since
|
||||
// it is added to the natural table index
|
||||
let headers: Vec<_> = headers
|
||||
.into_iter()
|
||||
.filter(|header| header != INDEX_COLUMN_NAME)
|
||||
.collect();
|
||||
let headers = collect_headers(headers, false);
|
||||
|
||||
let count_rows = input.len() + 1;
|
||||
let count_columns = headers.len();
|
||||
let mut table = NuTable::new(count_rows, count_columns);
|
||||
|
||||
table.set_header_style(get_header_style(opts.style_computer));
|
||||
table.set_index_style(get_index_style(opts.style_computer));
|
||||
table.set_header_style(get_header_style(&opts.style_computer));
|
||||
table.set_index_style(get_index_style(&opts.style_computer));
|
||||
|
||||
table.insert_row(0, headers.clone());
|
||||
table.set_row(0, headers.clone());
|
||||
|
||||
for (row, item) in input.iter().enumerate() {
|
||||
opts.signals.check(opts.span)?;
|
||||
check_value(item)?;
|
||||
|
||||
for (col, header) in headers.iter().enumerate() {
|
||||
let (text, style) = get_string_value_with_header(item, header, opts);
|
||||
let (text, style) = get_string_value_with_header(item, header.as_ref(), opts);
|
||||
|
||||
let pos = (row + 1, col);
|
||||
table.insert(pos, text);
|
||||
|
@ -138,23 +133,16 @@ fn create_table_with_header_and_index(
|
|||
row_offset: usize,
|
||||
opts: &TableOpts<'_>,
|
||||
) -> Result<Option<NuTable>, ShellError> {
|
||||
// The header with the INDEX is removed from the table headers since
|
||||
// it is added to the natural table index
|
||||
let mut headers: Vec<_> = headers
|
||||
.into_iter()
|
||||
.filter(|header| header != INDEX_COLUMN_NAME)
|
||||
.collect();
|
||||
|
||||
headers.insert(0, "#".into());
|
||||
let headers = collect_headers(headers, true);
|
||||
|
||||
let count_rows = input.len() + 1;
|
||||
let count_columns = headers.len();
|
||||
let mut table = NuTable::new(count_rows, count_columns);
|
||||
|
||||
table.set_header_style(get_header_style(opts.style_computer));
|
||||
table.set_index_style(get_index_style(opts.style_computer));
|
||||
table.set_header_style(get_header_style(&opts.style_computer));
|
||||
table.set_index_style(get_index_style(&opts.style_computer));
|
||||
|
||||
table.insert_row(0, headers.clone());
|
||||
table.set_row(0, headers.clone());
|
||||
|
||||
for (row, item) in input.iter().enumerate() {
|
||||
opts.signals.check(opts.span)?;
|
||||
|
@ -164,7 +152,7 @@ fn create_table_with_header_and_index(
|
|||
table.insert((row + 1, 0), text);
|
||||
|
||||
for (col, header) in headers.iter().enumerate().skip(1) {
|
||||
let (text, style) = get_string_value_with_header(item, header, opts);
|
||||
let (text, style) = get_string_value_with_header(item, header.as_ref(), opts);
|
||||
|
||||
let pos = (row + 1, col);
|
||||
table.insert(pos, text);
|
||||
|
@ -180,7 +168,7 @@ fn create_table_with_no_header(
|
|||
opts: &TableOpts<'_>,
|
||||
) -> Result<Option<NuTable>, ShellError> {
|
||||
let mut table = NuTable::new(input.len(), 1);
|
||||
table.set_index_style(get_index_style(opts.style_computer));
|
||||
table.set_index_style(get_index_style(&opts.style_computer));
|
||||
|
||||
for (row, item) in input.iter().enumerate() {
|
||||
opts.signals.check(opts.span)?;
|
||||
|
@ -202,7 +190,7 @@ fn create_table_with_no_header_and_index(
|
|||
opts: &TableOpts<'_>,
|
||||
) -> Result<Option<NuTable>, ShellError> {
|
||||
let mut table = NuTable::new(input.len(), 1 + 1);
|
||||
table.set_index_style(get_index_style(opts.style_computer));
|
||||
table.set_index_style(get_index_style(&opts.style_computer));
|
||||
|
||||
for (row, item) in input.iter().enumerate() {
|
||||
opts.signals.check(opts.span)?;
|
||||
|
@ -225,14 +213,14 @@ fn get_string_value_with_header(item: &Value, header: &str, opts: &TableOpts) ->
|
|||
match item {
|
||||
Value::Record { val, .. } => match val.get(header) {
|
||||
Some(value) => get_string_value(value, opts),
|
||||
None => get_empty_style(opts.style_computer),
|
||||
None => get_empty_style(&opts.style_computer),
|
||||
},
|
||||
value => get_string_value(value, opts),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_string_value(item: &Value, opts: &TableOpts) -> NuText {
|
||||
let (mut text, style) = get_value_style(item, opts.config, opts.style_computer);
|
||||
let (mut text, style) = get_value_style(item, opts.config, &opts.style_computer);
|
||||
|
||||
let is_string = matches!(item, Value::String { .. });
|
||||
if is_string {
|
||||
|
@ -251,3 +239,24 @@ fn get_table_row_index(item: &Value, config: &Config, row: usize, offset: usize)
|
|||
_ => (row + offset).to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_headers(headers: Vec<String>, index: bool) -> Vec<NuRecordsValue> {
|
||||
// The header with the INDEX is removed from the table headers since
|
||||
// it is added to the natural table index
|
||||
|
||||
if !index {
|
||||
headers
|
||||
.into_iter()
|
||||
.filter(|header| header != INDEX_COLUMN_NAME)
|
||||
.map(NuRecordsValue::new)
|
||||
.collect()
|
||||
} else {
|
||||
let mut v = Vec::with_capacity(headers.len() + 1);
|
||||
v.insert(0, NuRecordsValue::new("#".into()));
|
||||
for text in headers {
|
||||
v.push(NuRecordsValue::new(text));
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{Config, Signals, Span, TableIndent, TableIndexMode, TableMode};
|
||||
use nu_protocol::{Config, Signals, Span, TableIndexMode, TableMode};
|
||||
|
||||
use crate::{common::INDEX_COLUMN_NAME, NuTable};
|
||||
|
||||
|
@ -37,36 +37,35 @@ impl TableOutput {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableOpts<'a> {
|
||||
signals: &'a Signals,
|
||||
config: &'a Config,
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
span: Span,
|
||||
width: usize,
|
||||
indent: TableIndent,
|
||||
mode: TableMode,
|
||||
index_offset: usize,
|
||||
index_remove: bool,
|
||||
pub signals: &'a Signals,
|
||||
pub config: &'a Config,
|
||||
pub style_computer: std::rc::Rc<StyleComputer<'a>>,
|
||||
pub span: Span,
|
||||
pub width: usize,
|
||||
pub mode: TableMode,
|
||||
pub index_offset: usize,
|
||||
pub index_remove: bool,
|
||||
}
|
||||
|
||||
impl<'a> TableOpts<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
config: &'a Config,
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
style_computer: StyleComputer<'a>,
|
||||
signals: &'a Signals,
|
||||
span: Span,
|
||||
width: usize,
|
||||
indent: TableIndent,
|
||||
mode: TableMode,
|
||||
index_offset: usize,
|
||||
index_remove: bool,
|
||||
) -> Self {
|
||||
let style_computer = std::rc::Rc::new(style_computer);
|
||||
|
||||
Self {
|
||||
signals,
|
||||
config,
|
||||
style_computer,
|
||||
span,
|
||||
indent,
|
||||
width,
|
||||
mode,
|
||||
index_offset,
|
||||
|
|
Loading…
Reference in a new issue