forked from extern/nushell
@@ -1,8 +1,9 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::format::TableView;
|
||||
use crate::data::value::{format_leaf, style_leaf};
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_table::{draw_table, Alignment, StyledString, TextStyle, Theme};
|
||||
use std::time::Instant;
|
||||
|
||||
const STREAM_PAGE_SIZE: usize = 1000;
|
||||
@@ -38,12 +39,175 @@ impl WholeStreamCommand for Table {
|
||||
}
|
||||
}
|
||||
|
||||
fn str_to_color(s: String) -> Option<ansi_term::Color> {
|
||||
match s.as_str() {
|
||||
"g" | "green" => Some(ansi_term::Color::Green),
|
||||
"r" | "red" => Some(ansi_term::Color::Red),
|
||||
"u" | "blue" => Some(ansi_term::Color::Blue),
|
||||
"b" | "black" => Some(ansi_term::Color::Black),
|
||||
"y" | "yellow" => Some(ansi_term::Color::Yellow),
|
||||
"p" | "purple" => Some(ansi_term::Color::Purple),
|
||||
"c" | "cyan" => Some(ansi_term::Color::Cyan),
|
||||
"w" | "white" => Some(ansi_term::Color::White),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_list(values: &[Value], starting_idx: usize) -> nu_table::Table {
|
||||
let config = crate::data::config::config(Tag::unknown());
|
||||
|
||||
let header_style = if let Ok(config) = config {
|
||||
let header_align = config.get("header_align").map_or(Alignment::Left, |a| {
|
||||
a.as_string()
|
||||
.map_or(Alignment::Center, |a| match a.to_lowercase().as_str() {
|
||||
"center" | "c" => Alignment::Center,
|
||||
"right" | "r" => Alignment::Right,
|
||||
_ => Alignment::Center,
|
||||
})
|
||||
});
|
||||
|
||||
let header_color = match config.get("header_color") {
|
||||
Some(c) => match c.as_string() {
|
||||
Ok(color) => str_to_color(color.to_lowercase()).unwrap_or(ansi_term::Color::Green),
|
||||
_ => ansi_term::Color::Green,
|
||||
},
|
||||
_ => ansi_term::Color::Green,
|
||||
};
|
||||
|
||||
let header_bold = match config.get("header_bold") {
|
||||
Some(b) => match b.as_bool() {
|
||||
Ok(b) => b,
|
||||
_ => true,
|
||||
},
|
||||
_ => true,
|
||||
};
|
||||
|
||||
TextStyle {
|
||||
alignment: header_align,
|
||||
color: Some(header_color),
|
||||
is_bold: header_bold,
|
||||
}
|
||||
} else {
|
||||
TextStyle::default_header()
|
||||
};
|
||||
|
||||
let mut headers: Vec<StyledString> = nu_protocol::merge_descriptors(values)
|
||||
.into_iter()
|
||||
.map(|x| StyledString::new(x, header_style.clone()))
|
||||
.collect();
|
||||
let entries = values_to_entries(values, &mut headers, starting_idx);
|
||||
|
||||
nu_table::Table {
|
||||
headers,
|
||||
data: entries,
|
||||
theme: Theme::compact(),
|
||||
}
|
||||
}
|
||||
|
||||
fn are_table_indexes_disabled() -> bool {
|
||||
let config = crate::data::config::config(Tag::unknown());
|
||||
match config {
|
||||
Ok(config) => {
|
||||
let disable_indexes = config.get("disable_table_indexes");
|
||||
disable_indexes.map_or(false, |x| x.as_bool().unwrap_or(false))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn values_to_entries(
|
||||
values: &[Value],
|
||||
headers: &mut Vec<StyledString>,
|
||||
starting_idx: usize,
|
||||
) -> Vec<Vec<StyledString>> {
|
||||
let disable_indexes = are_table_indexes_disabled();
|
||||
let mut entries = vec![];
|
||||
|
||||
if headers.is_empty() {
|
||||
headers.push(StyledString::new("".to_string(), TextStyle::basic()));
|
||||
}
|
||||
|
||||
for (idx, value) in values.iter().enumerate() {
|
||||
let mut row: Vec<StyledString> = headers
|
||||
.iter()
|
||||
.map(|d: &StyledString| {
|
||||
if d.contents == "" {
|
||||
match value {
|
||||
Value {
|
||||
value: UntaggedValue::Row(..),
|
||||
..
|
||||
} => StyledString::new(
|
||||
format_leaf(&UntaggedValue::nothing()).plain_string(100_000),
|
||||
style_leaf(&UntaggedValue::nothing()),
|
||||
),
|
||||
_ => StyledString::new(
|
||||
format_leaf(value).plain_string(100_000),
|
||||
style_leaf(value),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
match value {
|
||||
Value {
|
||||
value: UntaggedValue::Row(..),
|
||||
..
|
||||
} => {
|
||||
let data = value.get_data(&d.contents);
|
||||
|
||||
StyledString::new(
|
||||
format_leaf(data.borrow()).plain_string(100_000),
|
||||
style_leaf(data.borrow()),
|
||||
)
|
||||
}
|
||||
_ => StyledString::new(
|
||||
format_leaf(&UntaggedValue::nothing()).plain_string(100_000),
|
||||
style_leaf(&UntaggedValue::nothing()),
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Indices are green, bold, right-aligned:
|
||||
if !disable_indexes {
|
||||
row.insert(
|
||||
0,
|
||||
StyledString::new(
|
||||
(starting_idx + idx).to_string(),
|
||||
TextStyle {
|
||||
alignment: Alignment::Center,
|
||||
color: Some(ansi_term::Color::Green),
|
||||
is_bold: true,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
entries.push(row);
|
||||
}
|
||||
|
||||
if !disable_indexes {
|
||||
headers.insert(
|
||||
0,
|
||||
StyledString::new(
|
||||
"#".to_owned(),
|
||||
TextStyle {
|
||||
alignment: Alignment::Center,
|
||||
color: Some(ansi_term::Color::Green),
|
||||
is_bold: true,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
entries
|
||||
}
|
||||
|
||||
async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let registry = registry.clone();
|
||||
let mut args = args.evaluate_once(®istry).await?;
|
||||
let mut finished = false;
|
||||
|
||||
let host = args.host.clone();
|
||||
// let host = args.host.clone();
|
||||
let mut start_number = match args.get("start_number") {
|
||||
Some(Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Int(i)),
|
||||
@@ -64,6 +228,8 @@ async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||
|
||||
let mut delay_slot = None;
|
||||
|
||||
let termwidth = std::cmp::max(textwrap::termwidth(), 20);
|
||||
|
||||
while !finished {
|
||||
let mut new_input: VecDeque<Value> = VecDeque::new();
|
||||
|
||||
@@ -113,12 +279,9 @@ async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||
let input: Vec<Value> = new_input.into();
|
||||
|
||||
if !input.is_empty() {
|
||||
let mut host = host.lock();
|
||||
let view = TableView::from_list(&input, start_number);
|
||||
let t = from_list(&input, start_number);
|
||||
|
||||
if let Some(view) = view {
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
draw_table(&t, termwidth);
|
||||
}
|
||||
|
||||
start_number += input.len();
|
||||
@@ -126,15 +289,3 @@ async fn table(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Table;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Table {})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user