forked from extern/nushell
table -e
Fix stackoverflow (cause endless empty list) (#6847)
Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com> Signed-off-by: Maxim Zhiburt <zhiburt@gmail.com>
This commit is contained in:
parent
89f3cbf318
commit
a3dce8ff19
@ -451,7 +451,7 @@ fn build_expanded_table(
|
|||||||
let deep = expand_limit.map(|i| i - 1);
|
let deep = expand_limit.map(|i| i - 1);
|
||||||
let table = convert_to_table2(
|
let table = convert_to_table2(
|
||||||
0,
|
0,
|
||||||
&vals,
|
vals.iter(),
|
||||||
ctrlc.clone(),
|
ctrlc.clone(),
|
||||||
config,
|
config,
|
||||||
span,
|
span,
|
||||||
@ -775,9 +775,9 @@ fn convert_to_table(
|
|||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[allow(clippy::into_iter_on_ref)]
|
#[allow(clippy::into_iter_on_ref)]
|
||||||
fn convert_to_table2(
|
fn convert_to_table2<'a>(
|
||||||
row_offset: usize,
|
row_offset: usize,
|
||||||
input: &[Value],
|
input: impl Iterator<Item = &'a Value> + ExactSizeIterator + Clone,
|
||||||
ctrlc: Option<Arc<AtomicBool>>,
|
ctrlc: Option<Arc<AtomicBool>>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
head: Span,
|
head: Span,
|
||||||
@ -787,13 +787,13 @@ fn convert_to_table2(
|
|||||||
flatten: bool,
|
flatten: bool,
|
||||||
flatten_sep: &str,
|
flatten_sep: &str,
|
||||||
) -> Result<Option<NuTable>, ShellError> {
|
) -> Result<Option<NuTable>, ShellError> {
|
||||||
if input.is_empty() {
|
if input.len() == 0 {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let float_precision = config.float_precision as usize;
|
let float_precision = config.float_precision as usize;
|
||||||
|
|
||||||
let mut headers = get_columns(input);
|
let mut headers = get_columns(input.clone());
|
||||||
let with_index = match config.table_index_mode {
|
let with_index = match config.table_index_mode {
|
||||||
TableIndexMode::Always => true,
|
TableIndexMode::Always => true,
|
||||||
TableIndexMode::Never => false,
|
TableIndexMode::Never => false,
|
||||||
@ -876,29 +876,52 @@ fn convert_to_table2(
|
|||||||
} else {
|
} else {
|
||||||
let skip_num = if with_index { 1 } else { 0 };
|
let skip_num = if with_index { 1 } else { 0 };
|
||||||
for (col, header) in data[0].iter().enumerate().skip(skip_num) {
|
for (col, header) in data[0].iter().enumerate().skip(skip_num) {
|
||||||
let result = match item {
|
let value = match item {
|
||||||
Value::Record { .. } => item.clone().follow_cell_path(
|
Value::Record { .. } => {
|
||||||
&[PathMember::String {
|
let val = item.clone().follow_cell_path(
|
||||||
val: header.as_ref().to_owned(),
|
&[PathMember::String {
|
||||||
span: head,
|
val: header.as_ref().to_owned(),
|
||||||
}],
|
span: head,
|
||||||
false,
|
}],
|
||||||
),
|
false,
|
||||||
_ => Ok(item.clone()),
|
);
|
||||||
};
|
|
||||||
|
|
||||||
let value = convert_to_table2_entry(
|
match val {
|
||||||
result.ok().as_ref(),
|
Ok(val) => convert_to_table2_entry(
|
||||||
config,
|
Some(&val),
|
||||||
&ctrlc,
|
config,
|
||||||
color_hm,
|
&ctrlc,
|
||||||
col,
|
color_hm,
|
||||||
theme,
|
col,
|
||||||
with_index,
|
theme,
|
||||||
deep,
|
with_index,
|
||||||
flatten,
|
deep,
|
||||||
flatten_sep,
|
flatten,
|
||||||
);
|
flatten_sep,
|
||||||
|
),
|
||||||
|
Err(_) => make_styled_string(
|
||||||
|
item.into_abbreviated_string(config),
|
||||||
|
&item.get_type().to_string(),
|
||||||
|
col,
|
||||||
|
with_index,
|
||||||
|
color_hm,
|
||||||
|
float_precision,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => convert_to_table2_entry(
|
||||||
|
Some(item),
|
||||||
|
config,
|
||||||
|
&ctrlc,
|
||||||
|
color_hm,
|
||||||
|
col,
|
||||||
|
theme,
|
||||||
|
with_index,
|
||||||
|
deep,
|
||||||
|
flatten,
|
||||||
|
flatten_sep,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
let value = NuTable::create_cell(value.0, value.1);
|
let value = NuTable::create_cell(value.0, value.1);
|
||||||
row.push(value);
|
row.push(value);
|
||||||
@ -951,75 +974,131 @@ fn convert_to_table2_entry(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_record_or_list = matches!(item, Value::Record { .. } | Value::List { .. });
|
let is_limit_reached = matches!(deep, Some(0));
|
||||||
let is_simple = matches!(deep, Some(0)) || !is_record_or_list;
|
if is_limit_reached {
|
||||||
|
return make_styled_string(
|
||||||
let mut text = None;
|
|
||||||
if !is_simple {
|
|
||||||
let mut arr: [Value; 1] = [Value::default()];
|
|
||||||
let (list, span): (&[Value], Span) = match item {
|
|
||||||
Value::Record { span, .. } => {
|
|
||||||
arr[0] = item.clone();
|
|
||||||
(&arr, *span)
|
|
||||||
}
|
|
||||||
Value::List { vals, span } => (vals, *span),
|
|
||||||
_ => unreachable!("we checked the values already"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let is_simple_list = list
|
|
||||||
.iter()
|
|
||||||
.all(|v| !matches!(v, Value::Record { .. } | Value::List { .. }));
|
|
||||||
|
|
||||||
text = if flatten && is_simple_list {
|
|
||||||
let mut buf = Vec::new();
|
|
||||||
for value in list {
|
|
||||||
let (text, _) = make_styled_string(
|
|
||||||
value.into_abbreviated_string(config),
|
|
||||||
&value.get_type().to_string(),
|
|
||||||
col,
|
|
||||||
with_index,
|
|
||||||
color_hm,
|
|
||||||
float_precision,
|
|
||||||
);
|
|
||||||
|
|
||||||
buf.push(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
let text = buf.join(flatten_sep);
|
|
||||||
|
|
||||||
Some(text)
|
|
||||||
} else {
|
|
||||||
let table = convert_to_table2(
|
|
||||||
0,
|
|
||||||
list,
|
|
||||||
ctrlc.clone(),
|
|
||||||
config,
|
|
||||||
span,
|
|
||||||
color_hm,
|
|
||||||
theme,
|
|
||||||
deep.map(|i| i - 1),
|
|
||||||
flatten,
|
|
||||||
flatten_sep,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Ok(Some(table)) = table {
|
|
||||||
table.draw_table(config, color_hm, alignments, theme, usize::MAX)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match text {
|
|
||||||
Some(text) => (text, TextStyle::default()),
|
|
||||||
None => make_styled_string(
|
|
||||||
item.into_abbreviated_string(config),
|
item.into_abbreviated_string(config),
|
||||||
&item.get_type().to_string(),
|
&item.get_type().to_string(),
|
||||||
col,
|
col,
|
||||||
with_index,
|
with_index,
|
||||||
color_hm,
|
color_hm,
|
||||||
float_precision,
|
float_precision,
|
||||||
),
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match &item {
|
||||||
|
Value::Record { span, cols, vals } => {
|
||||||
|
if cols.is_empty() && vals.is_empty() {
|
||||||
|
make_styled_string(
|
||||||
|
item.into_abbreviated_string(config),
|
||||||
|
&item.get_type().to_string(),
|
||||||
|
col,
|
||||||
|
with_index,
|
||||||
|
color_hm,
|
||||||
|
float_precision,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let table = convert_to_table2(
|
||||||
|
0,
|
||||||
|
std::iter::once(item),
|
||||||
|
ctrlc.clone(),
|
||||||
|
config,
|
||||||
|
*span,
|
||||||
|
color_hm,
|
||||||
|
theme,
|
||||||
|
deep.map(|i| i - 1),
|
||||||
|
flatten,
|
||||||
|
flatten_sep,
|
||||||
|
);
|
||||||
|
|
||||||
|
let inner_table = table.map(|table| {
|
||||||
|
table.and_then(|table| {
|
||||||
|
table.draw_table(config, color_hm, alignments, theme, usize::MAX)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if let Ok(Some(table)) = inner_table {
|
||||||
|
(table, TextStyle::default())
|
||||||
|
} else {
|
||||||
|
// error so back down to the default
|
||||||
|
make_styled_string(
|
||||||
|
item.into_abbreviated_string(config),
|
||||||
|
&item.get_type().to_string(),
|
||||||
|
col,
|
||||||
|
with_index,
|
||||||
|
color_hm,
|
||||||
|
float_precision,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::List { vals, span } => {
|
||||||
|
let is_simple_list = vals
|
||||||
|
.iter()
|
||||||
|
.all(|v| !matches!(v, Value::Record { .. } | Value::List { .. }));
|
||||||
|
|
||||||
|
if flatten && is_simple_list {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
for value in vals {
|
||||||
|
let (text, _) = make_styled_string(
|
||||||
|
value.into_abbreviated_string(config),
|
||||||
|
&value.get_type().to_string(),
|
||||||
|
col,
|
||||||
|
with_index,
|
||||||
|
color_hm,
|
||||||
|
float_precision,
|
||||||
|
);
|
||||||
|
|
||||||
|
buf.push(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = buf.join(flatten_sep);
|
||||||
|
|
||||||
|
(text, TextStyle::default())
|
||||||
|
} else {
|
||||||
|
let table = convert_to_table2(
|
||||||
|
0,
|
||||||
|
vals.iter(),
|
||||||
|
ctrlc.clone(),
|
||||||
|
config,
|
||||||
|
*span,
|
||||||
|
color_hm,
|
||||||
|
theme,
|
||||||
|
deep.map(|i| i - 1),
|
||||||
|
flatten,
|
||||||
|
flatten_sep,
|
||||||
|
);
|
||||||
|
|
||||||
|
let inner_table = table.map(|table| {
|
||||||
|
table.and_then(|table| {
|
||||||
|
table.draw_table(config, color_hm, alignments, theme, usize::MAX)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if let Ok(Some(table)) = inner_table {
|
||||||
|
(table, TextStyle::default())
|
||||||
|
} else {
|
||||||
|
// error so back down to the default
|
||||||
|
make_styled_string(
|
||||||
|
item.into_abbreviated_string(config),
|
||||||
|
&item.get_type().to_string(),
|
||||||
|
col,
|
||||||
|
with_index,
|
||||||
|
color_hm,
|
||||||
|
float_precision,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// unknown type.
|
||||||
|
make_styled_string(
|
||||||
|
item.into_abbreviated_string(config),
|
||||||
|
&item.get_type().to_string(),
|
||||||
|
col,
|
||||||
|
with_index,
|
||||||
|
color_hm,
|
||||||
|
float_precision,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1112,7 +1191,7 @@ impl PagingTableCreator {
|
|||||||
let color_hm = get_color_config(&self.config);
|
let color_hm = get_color_config(&self.config);
|
||||||
let table = convert_to_table2(
|
let table = convert_to_table2(
|
||||||
self.row_offset,
|
self.row_offset,
|
||||||
batch,
|
batch.iter(),
|
||||||
self.ctrlc.clone(),
|
self.ctrlc.clone(),
|
||||||
&self.config,
|
&self.config,
|
||||||
self.head,
|
self.head,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use nu_protocol::Value;
|
use nu_protocol::Value;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub fn get_columns(input: &[Value]) -> Vec<String> {
|
pub fn get_columns<'a>(input: impl IntoIterator<Item = &'a Value>) -> Vec<String> {
|
||||||
let mut columns = vec![];
|
let mut columns = vec![];
|
||||||
|
|
||||||
for item in input {
|
for item in input {
|
||||||
|
Loading…
Reference in New Issue
Block a user