diff --git a/Cargo.lock b/Cargo.lock index 433c8b4a2d..6d6b7893b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "assert_cmd" version = "1.0.8" @@ -402,6 +408,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lscolors" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0aa49b10c47f9a4391a99198b5e65c74f9ca771c0dcc856bb75a3f46c8627d" +dependencies = [ + "ansi_term", + "crossterm", +] + [[package]] name = "memchr" version = "2.4.1" @@ -519,6 +535,7 @@ version = "0.1.0" dependencies = [ "chrono", "glob", + "lscolors", "nu-engine", "nu-json", "nu-path", @@ -594,6 +611,7 @@ dependencies = [ name = "nu-term-grid" version = "0.36.0" dependencies = [ + "strip-ansi-escapes", "unicode-width", ] @@ -979,6 +997,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + [[package]] name = "supports-color" version = "1.3.0" @@ -1148,6 +1175,33 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cf7d77f457ef8dfa11e4cd5933c5ddb5dc52a94664071951219a97710f0a32b" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 4d0f13c78b..2120c39384 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -17,5 +17,6 @@ nu-term-grid = { path = "../nu-term-grid" } glob = "0.3.0" thiserror = "1.0.29" sysinfo = "0.20.4" -chrono = { version="0.4.19", features=["serde"] } +chrono = { version = "0.4.19", features = ["serde"] } terminal_size = "0.1.17" +lscolors = { version = "0.8.0", features = ["crossterm"] } diff --git a/crates/nu-command/src/viewers/griddle.rs b/crates/nu-command/src/viewers/griddle.rs index f16ec4a743..42a0e58f33 100644 --- a/crates/nu-command/src/viewers/griddle.rs +++ b/crates/nu-command/src/viewers/griddle.rs @@ -1,3 +1,4 @@ +use lscolors::{LsColors, Style}; use nu_engine::CallExt; use nu_protocol::{ ast::{Call, PathMember}, @@ -19,12 +20,14 @@ impl Command for Griddle { } fn signature(&self) -> nu_protocol::Signature { - Signature::build("grid").named( - "columns", - SyntaxShape::Int, - "number of columns wide", - Some('c'), - ) + Signature::build("grid") + .named( + "width", + SyntaxShape::Int, + "number of columns wide", + Some('w'), + ) + .switch("color", "draw output with color", Some('c')) } fn extra_usage(&self) -> &str { @@ -42,14 +45,15 @@ prints out the list properly."# call: &Call, input: Value, ) -> Result { - let columns_param: Option = call.get_flag(context, "columns")?; + let width_param: Option = call.get_flag(context, "width")?; + let color_param: bool = call.has_flag("color"); match input { Value::List { vals, .. } => { // dbg!("value::list"); let data = convert_to_list2(vals); if let Some(items) = data { - Ok(create_grid_output2(items, call, columns_param)) + Ok(create_grid_output2(items, call, width_param, color_param)) } else { Ok(Value::Nothing { span: call.head }) } @@ -58,7 +62,7 @@ prints out the list properly."# // dbg!("value::stream"); let data = convert_to_list2(stream); if let Some(items) = data { - Ok(create_grid_output2(items, call, columns_param)) + Ok(create_grid_output2(items, call, width_param, color_param)) } else { // dbg!(data); Ok(Value::Nothing { span: call.head }) @@ -72,7 +76,7 @@ prints out the list properly."# items.push((i, c, v.into_string())) } - Ok(create_grid_output2(items, call, columns_param)) + Ok(create_grid_output2(items, call, width_param, color_param)) } x => { // dbg!("other value"); @@ -86,8 +90,10 @@ prints out the list properly."# fn create_grid_output2( items: Vec<(usize, String, String)>, call: &Call, - columns_param: Option, + width_param: Option, + color_param: bool, ) -> Value { + let ls_colors = LsColors::from_env().unwrap_or_default(); let mut grid = Grid::new(GridOptions { direction: Direction::TopToBottom, filling: Filling::Text(" | ".into()), @@ -96,13 +102,21 @@ fn create_grid_output2( for (_row_index, header, value) in items { // only output value if the header name is 'name' if header == "name" { - let mut cell = Cell::from(value); - cell.alignment = Alignment::Right; - grid.add(cell); + if color_param { + let style = ls_colors.style_for_path(value.clone()); + let ansi_style = style.map(Style::to_crossterm_style).unwrap_or_default(); + let mut cell = Cell::from(ansi_style.apply(value).to_string()); + cell.alignment = Alignment::Right; + grid.add(cell); + } else { + let mut cell = Cell::from(value); + cell.alignment = Alignment::Right; + grid.add(cell); + } } } - let cols = if let Some(col) = columns_param { + let cols = if let Some(col) = width_param { col.parse::().unwrap_or(80) } else if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() { w diff --git a/crates/nu-term-grid/Cargo.toml b/crates/nu-term-grid/Cargo.toml index 183de8ecc9..aa24839b94 100644 --- a/crates/nu-term-grid/Cargo.toml +++ b/crates/nu-term-grid/Cargo.toml @@ -13,3 +13,4 @@ path = "src/main.rs" [dependencies] unicode-width = "0.1.9" +strip-ansi-escapes = "0.1.1" diff --git a/crates/nu-term-grid/src/grid.rs b/crates/nu-term-grid/src/grid.rs index 212005354c..5c10ef86a1 100644 --- a/crates/nu-term-grid/src/grid.rs +++ b/crates/nu-term-grid/src/grid.rs @@ -94,10 +94,21 @@ use std::cmp::max; use std::fmt; use std::iter::repeat; - -// extern crate unicode_width; +use strip_ansi_escapes::strip; use unicode_width::UnicodeWidthStr; +fn unicode_width_strip_ansi(astring: &str) -> usize { + let stripped_string: String = { + if let Ok(bytes) = strip(astring) { + String::from_utf8_lossy(&bytes).to_string() + } else { + astring.to_string() + } + }; + + UnicodeWidthStr::width(&stripped_string[..]) +} + /// Alignment indicate on which side the content should stick if some filling /// is required. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -129,7 +140,7 @@ pub struct Cell { impl From for Cell { fn from(string: String) -> Self { Self { - width: UnicodeWidthStr::width(&*string), + width: unicode_width_strip_ansi(&*string), contents: string, alignment: Alignment::Left, } @@ -139,7 +150,7 @@ impl From for Cell { impl<'a> From<&'a str> for Cell { fn from(string: &'a str) -> Self { Self { - width: UnicodeWidthStr::width(&*string), + width: unicode_width_strip_ansi(&*string), contents: string.into(), alignment: Alignment::Left, } @@ -177,7 +188,7 @@ impl Filling { fn width(&self) -> Width { match *self { Filling::Spaces(w) => w, - Filling::Text(ref t) => UnicodeWidthStr::width(&t[..]), + Filling::Text(ref t) => unicode_width_strip_ansi(&t[..]), } } }