Merge pull request #102 from fdncred/ls_colors_grid

respect lscolors env var; measure width minus ansi
This commit is contained in:
Darren Schroeder 2021-10-08 10:01:23 -05:00 committed by GitHub
commit 7f3f41ff14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 21 deletions

54
Cargo.lock generated
View file

@ -35,6 +35,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "1.0.8" version = "1.0.8"
@ -402,6 +408,16 @@ dependencies = [
"cfg-if", "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]] [[package]]
name = "memchr" name = "memchr"
version = "2.4.1" version = "2.4.1"
@ -519,6 +535,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"glob", "glob",
"lscolors",
"nu-engine", "nu-engine",
"nu-json", "nu-json",
"nu-path", "nu-path",
@ -594,6 +611,7 @@ dependencies = [
name = "nu-term-grid" name = "nu-term-grid"
version = "0.36.0" version = "0.36.0"
dependencies = [ dependencies = [
"strip-ansi-escapes",
"unicode-width", "unicode-width",
] ]
@ -979,6 +997,15 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" 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]] [[package]]
name = "supports-color" name = "supports-color"
version = "1.3.0" version = "1.3.0"
@ -1148,6 +1175,33 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cf7d77f457ef8dfa11e4cd5933c5ddb5dc52a94664071951219a97710f0a32b" 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]] [[package]]
name = "wait-timeout" name = "wait-timeout"
version = "0.2.0" version = "0.2.0"

View file

@ -17,5 +17,6 @@ nu-term-grid = { path = "../nu-term-grid" }
glob = "0.3.0" glob = "0.3.0"
thiserror = "1.0.29" thiserror = "1.0.29"
sysinfo = "0.20.4" sysinfo = "0.20.4"
chrono = { version="0.4.19", features=["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
terminal_size = "0.1.17" terminal_size = "0.1.17"
lscolors = { version = "0.8.0", features = ["crossterm"] }

View file

@ -1,3 +1,4 @@
use lscolors::{LsColors, Style};
use nu_engine::CallExt; use nu_engine::CallExt;
use nu_protocol::{ use nu_protocol::{
ast::{Call, PathMember}, ast::{Call, PathMember},
@ -19,12 +20,14 @@ impl Command for Griddle {
} }
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("grid").named( Signature::build("grid")
"columns", .named(
SyntaxShape::Int, "width",
"number of columns wide", SyntaxShape::Int,
Some('c'), "number of columns wide",
) Some('w'),
)
.switch("color", "draw output with color", Some('c'))
} }
fn extra_usage(&self) -> &str { fn extra_usage(&self) -> &str {
@ -42,14 +45,15 @@ prints out the list properly."#
call: &Call, call: &Call,
input: Value, input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> { ) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
let columns_param: Option<String> = call.get_flag(context, "columns")?; let width_param: Option<String> = call.get_flag(context, "width")?;
let color_param: bool = call.has_flag("color");
match input { match input {
Value::List { vals, .. } => { Value::List { vals, .. } => {
// dbg!("value::list"); // dbg!("value::list");
let data = convert_to_list2(vals); let data = convert_to_list2(vals);
if let Some(items) = data { if let Some(items) = data {
Ok(create_grid_output2(items, call, columns_param)) Ok(create_grid_output2(items, call, width_param, color_param))
} else { } else {
Ok(Value::Nothing { span: call.head }) Ok(Value::Nothing { span: call.head })
} }
@ -58,7 +62,7 @@ prints out the list properly."#
// dbg!("value::stream"); // dbg!("value::stream");
let data = convert_to_list2(stream); let data = convert_to_list2(stream);
if let Some(items) = data { if let Some(items) = data {
Ok(create_grid_output2(items, call, columns_param)) Ok(create_grid_output2(items, call, width_param, color_param))
} else { } else {
// dbg!(data); // dbg!(data);
Ok(Value::Nothing { span: call.head }) Ok(Value::Nothing { span: call.head })
@ -72,7 +76,7 @@ prints out the list properly."#
items.push((i, c, v.into_string())) 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 => { x => {
// dbg!("other value"); // dbg!("other value");
@ -86,8 +90,10 @@ prints out the list properly."#
fn create_grid_output2( fn create_grid_output2(
items: Vec<(usize, String, String)>, items: Vec<(usize, String, String)>,
call: &Call, call: &Call,
columns_param: Option<String>, width_param: Option<String>,
color_param: bool,
) -> Value { ) -> Value {
let ls_colors = LsColors::from_env().unwrap_or_default();
let mut grid = Grid::new(GridOptions { let mut grid = Grid::new(GridOptions {
direction: Direction::TopToBottom, direction: Direction::TopToBottom,
filling: Filling::Text(" | ".into()), filling: Filling::Text(" | ".into()),
@ -96,13 +102,21 @@ fn create_grid_output2(
for (_row_index, header, value) in items { for (_row_index, header, value) in items {
// only output value if the header name is 'name' // only output value if the header name is 'name'
if header == "name" { if header == "name" {
let mut cell = Cell::from(value); if color_param {
cell.alignment = Alignment::Right; let style = ls_colors.style_for_path(value.clone());
grid.add(cell); 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::<u16>().unwrap_or(80) col.parse::<u16>().unwrap_or(80)
} else if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() { } else if let Some((Width(w), Height(_h))) = terminal_size::terminal_size() {
w w

View file

@ -13,3 +13,4 @@ path = "src/main.rs"
[dependencies] [dependencies]
unicode-width = "0.1.9" unicode-width = "0.1.9"
strip-ansi-escapes = "0.1.1"

View file

@ -94,10 +94,21 @@
use std::cmp::max; use std::cmp::max;
use std::fmt; use std::fmt;
use std::iter::repeat; use std::iter::repeat;
use strip_ansi_escapes::strip;
// extern crate unicode_width;
use unicode_width::UnicodeWidthStr; 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 /// Alignment indicate on which side the content should stick if some filling
/// is required. /// is required.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -129,7 +140,7 @@ pub struct Cell {
impl From<String> for Cell { impl From<String> for Cell {
fn from(string: String) -> Self { fn from(string: String) -> Self {
Self { Self {
width: UnicodeWidthStr::width(&*string), width: unicode_width_strip_ansi(&*string),
contents: string, contents: string,
alignment: Alignment::Left, alignment: Alignment::Left,
} }
@ -139,7 +150,7 @@ impl From<String> for Cell {
impl<'a> From<&'a str> for Cell { impl<'a> From<&'a str> for Cell {
fn from(string: &'a str) -> Self { fn from(string: &'a str) -> Self {
Self { Self {
width: UnicodeWidthStr::width(&*string), width: unicode_width_strip_ansi(&*string),
contents: string.into(), contents: string.into(),
alignment: Alignment::Left, alignment: Alignment::Left,
} }
@ -177,7 +188,7 @@ impl Filling {
fn width(&self) -> Width { fn width(&self) -> Width {
match *self { match *self {
Filling::Spaces(w) => w, Filling::Spaces(w) => w,
Filling::Text(ref t) => UnicodeWidthStr::width(&t[..]), Filling::Text(ref t) => unicode_width_strip_ansi(&t[..]),
} }
} }
} }