From 34a824af71705279e6f3a213668c495e0e6bd396 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 21 Apr 2021 16:58:37 +0200 Subject: [PATCH 1/7] ls: use lscolors crate --- src/uu/ls/Cargo.toml | 5 +- src/uu/ls/src/ls.rs | 253 ++++++++++++++++----------------------- tests/by-util/test_ls.rs | 27 ++--- 3 files changed, 116 insertions(+), 169 deletions(-) diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index dacdc7cd9..addca6fbb 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -16,17 +16,14 @@ path = "src/ls.rs" [dependencies] clap = "2.33" -lazy_static = "1.0.1" number_prefix = "0.4" term_grid = "0.1.5" termsize = "0.1.6" time = "0.1.40" -unicode-width = "0.1.5" globset = "0.4.6" +lscolors = { version="0.7.1", features=["ansi_term"] } uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["entries", "fs"] } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } - -[target.'cfg(unix)'.dependencies] atty = "0.2" [[bin]] diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 514539809..c08e604f9 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -7,9 +7,6 @@ // spell-checker:ignore (ToDO) cpio svgz webm somegroup nlink rmvb xspf -#[cfg(unix)] -#[macro_use] -extern crate lazy_static; #[macro_use] extern crate uucore; @@ -18,10 +15,9 @@ mod version_cmp; use clap::{App, Arg}; use globset::{self, Glob, GlobSet, GlobSetBuilder}; +use lscolors::LsColors; use number_prefix::NumberPrefix; use quoting_style::{escape_name, QuotingStyle}; -#[cfg(unix)] -use std::collections::HashMap; use std::fs; use std::fs::{DirEntry, FileType, Metadata}; #[cfg(unix)] @@ -41,7 +37,7 @@ use time::{strftime, Timespec}; #[cfg(unix)] use unicode_width::UnicodeWidthStr; #[cfg(unix)] -use uucore::libc::{mode_t, S_ISGID, S_ISUID, S_ISVTX, S_IWOTH, S_IXGRP, S_IXOTH, S_IXUSR}; +use uucore::libc::{mode_t, S_IXGRP, S_IXOTH, S_IXUSR}; static VERSION: &str = env!("CARGO_PKG_VERSION"); static ABOUT: &str = " @@ -54,30 +50,6 @@ fn get_usage() -> String { format!("{0} [OPTION]... [FILE]...", executable!()) } -#[cfg(unix)] -static DEFAULT_COLORS: &str = "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"; - -#[cfg(unix)] -lazy_static! { - static ref LS_COLORS: String = - std::env::var("LS_COLORS").unwrap_or_else(|_| DEFAULT_COLORS.to_string()); - static ref COLOR_MAP: HashMap<&'static str, &'static str> = { - let codes = LS_COLORS.split(':'); - let mut map = HashMap::new(); - for c in codes { - let p: Vec<_> = c.splitn(2, '=').collect(); - if p.len() == 2 { - map.insert(p[0], p[1]); - } - } - map - }; - static ref RESET_CODE: &'static str = COLOR_MAP.get("rs").unwrap_or(&"0"); - static ref LEFT_CODE: &'static str = COLOR_MAP.get("lc").unwrap_or(&"\x1b["); - static ref RIGHT_CODE: &'static str = COLOR_MAP.get("rc").unwrap_or(&"m"); - static ref END_CODE: &'static str = COLOR_MAP.get("ec").unwrap_or(&""); -} - pub mod options { pub mod format { pub static ONELINE: &str = "1"; @@ -212,8 +184,7 @@ struct Config { time: Time, #[cfg(unix)] inode: bool, - #[cfg(unix)] - color: bool, + color: Option, long: LongFormat, width: Option, quoting_style: QuotingStyle, @@ -337,8 +308,7 @@ impl Config { Time::Modification }; - #[cfg(unix)] - let color = match options.value_of(options::COLOR) { + let needs_color = match options.value_of(options::COLOR) { None => options.is_present(options::COLOR), Some(val) => match val { "" | "always" | "yes" | "force" => true, @@ -347,6 +317,12 @@ impl Config { }, }; + let color = if needs_color { + Some(LsColors::from_env().unwrap_or_default()) + } else { + None + }; + let size_format = if options.is_present(options::size::HUMAN_READABLE) { SizeFormat::Binary } else if options.is_present(options::size::SI) { @@ -520,7 +496,6 @@ impl Config { size_format, directory: options.is_present(options::DIRECTORY), time, - #[cfg(unix)] color, #[cfg(unix)] inode: options.is_present(options::INODE), @@ -1470,64 +1445,44 @@ fn get_file_name(name: &Path, strip: Option<&Path>) -> String { name.to_string_lossy().into_owned() } -#[cfg(not(unix))] -fn display_file_name( - path: &Path, - strip: Option<&Path>, - metadata: &Metadata, - config: &Config, -) -> Cell { - let mut name = escape_name(get_file_name(path, strip), &config.quoting_style); - let file_type = metadata.file_type(); +// #[cfg(not(unix))] +// fn display_file_name( +// path: &Path, +// strip: Option<&Path>, +// metadata: &Metadata, +// config: &Config, +// ) -> Cell { +// let mut name = escape_name(get_file_name(path, strip), &config.quoting_style); +// let file_type = metadata.file_type(); - match config.indicator_style { - IndicatorStyle::Classify | IndicatorStyle::FileType => { - if file_type.is_dir() { - name.push('/'); - } - if file_type.is_symlink() { - name.push('@'); - } - } - IndicatorStyle::Slash => { - if file_type.is_dir() { - name.push('/'); - } - } - _ => (), - }; +// match config.indicator_style { +// IndicatorStyle::Classify | IndicatorStyle::FileType => { +// if file_type.is_dir() { +// name.push('/'); +// } +// if file_type.is_symlink() { +// name.push('@'); +// } +// } +// IndicatorStyle::Slash => { +// if file_type.is_dir() { +// name.push('/'); +// } +// } +// _ => (), +// }; - if config.format == Format::Long && metadata.file_type().is_symlink() { - if let Ok(target) = path.read_link() { - // We don't bother updating width here because it's not used for long listings - let target_name = target.to_string_lossy().to_string(); - name.push_str(" -> "); - name.push_str(&target_name); - } - } +// if config.format == Format::Long && metadata.file_type().is_symlink() { +// if let Ok(target) = path.read_link() { +// // We don't bother updating width here because it's not used for long listings +// let target_name = target.to_string_lossy().to_string(); +// name.push_str(" -> "); +// name.push_str(&target_name); +// } +// } - name.into() -} - -#[cfg(unix)] -fn color_name(name: String, typ: &str) -> String { - let mut typ = typ; - if !COLOR_MAP.contains_key(typ) { - if typ == "or" { - typ = "ln"; - } else if typ == "mi" { - typ = "fi"; - } - }; - if let Some(code) = COLOR_MAP.get(typ) { - format!( - "{}{}{}{}{}{}{}{}", - *LEFT_CODE, code, *RIGHT_CODE, name, *END_CODE, *LEFT_CODE, *RESET_CODE, *RIGHT_CODE, - ) - } else { - name - } -} +// name.into() +// } #[cfg(unix)] macro_rules! has { @@ -1537,6 +1492,40 @@ macro_rules! has { } #[cfg(unix)] +fn classify_file(md: &Metadata) -> Option { + let file_type = md.file_type(); + if file_type.is_dir() { + Some('/') + } else if file_type.is_symlink() { + Some('@') + } else if file_type.is_socket() { + Some('=') + } else if file_type.is_fifo() { + Some('|') + } else if file_type.is_file() { + let mode = md.mode() as mode_t; + if has!(mode, S_IXUSR | S_IXGRP | S_IXOTH) { + Some('*') + } else { + None + } + } else { + None + } +} + +#[cfg(not(unix))] +fn classify_file(md: &Metadata) -> Option { + let file_type = md.file_type(); + if file_type.is_dir() { + Some('/') + } else if file_type.is_symlink() { + Some('@') + } else { + None + } +} + #[allow(clippy::cognitive_complexity)] fn display_file_name( path: &Path, @@ -1545,65 +1534,18 @@ fn display_file_name( config: &Config, ) -> Cell { let mut name = escape_name(get_file_name(path, strip), &config.quoting_style); + + #[cfg(unix)] if config.format != Format::Long && config.inode { name = get_inode(metadata) + " " + &name; } - let mut width = UnicodeWidthStr::width(&*name); - let ext; - if config.color || config.indicator_style != IndicatorStyle::None { - let file_type = metadata.file_type(); + if let Some(ls_colors) = &config.color { + name = color_name(&ls_colors, path, name, metadata).to_string(); + } - let (code, sym) = if file_type.is_dir() { - ("di", Some('/')) - } else if file_type.is_symlink() { - if path.exists() { - ("ln", Some('@')) - } else { - ("or", Some('@')) - } - } else if file_type.is_socket() { - ("so", Some('=')) - } else if file_type.is_fifo() { - ("pi", Some('|')) - } else if file_type.is_block_device() { - ("bd", None) - } else if file_type.is_char_device() { - ("cd", None) - } else if file_type.is_file() { - let mode = metadata.mode() as mode_t; - let sym = if has!(mode, S_IXUSR | S_IXGRP | S_IXOTH) { - Some('*') - } else { - None - }; - if has!(mode, S_ISUID) { - ("su", sym) - } else if has!(mode, S_ISGID) { - ("sg", sym) - } else if has!(mode, S_ISVTX) && has!(mode, S_IWOTH) { - ("tw", sym) - } else if has!(mode, S_ISVTX) { - ("st", sym) - } else if has!(mode, S_IWOTH) { - ("ow", sym) - } else if has!(mode, S_IXUSR | S_IXGRP | S_IXOTH) { - ("ex", sym) - } else if metadata.nlink() > 1 { - ("mh", sym) - } else if let Some(e) = path.extension() { - ext = format!("*.{}", e.to_string_lossy()); - (ext.as_str(), None) - } else { - ("fi", None) - } - } else { - ("", None) - }; - - if config.color { - name = color_name(name, code); - } + if config.indicator_style != IndicatorStyle::None { + let sym = classify_file(metadata); let char_opt = match config.indicator_style { IndicatorStyle::Classify => sym, @@ -1626,23 +1568,32 @@ fn display_file_name( if let Some(c) = char_opt { name.push(c); - width += 1; } } if config.format == Format::Long && metadata.file_type().is_symlink() { if let Ok(target) = path.read_link() { - // We don't bother updating width here because it's not used for long listings - let code = if target.exists() { "fi" } else { "mi" }; - let target_name = color_name(target.to_string_lossy().to_string(), code); + // We don't bother updating width here because it's not used for long + let mut target_name = target.to_string_lossy().to_string(); + if let Some(ls_colors) = &config.color { + target_name = color_name(&ls_colors, &target, target_name, metadata); + } name.push_str(" -> "); + name.push_str(&target_name); } } - Cell { - contents: name, - width, + name.into() +} + +fn color_name(ls_colors: &LsColors, path: &Path, name: String, md: &Metadata) -> String { + match ls_colors.style_for_path_with_metadata(path, Some(&md)) { + Some(style) => { + dbg!(style); + style.to_ansi_term_style().paint(name).to_string() + } + None => dbg!(name), } } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index d810cdc29..ed95c3034 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -621,20 +621,27 @@ fn test_ls_recursive() { result.stdout_contains(&"a\\b:\nb"); } -#[cfg(unix)] #[test] fn test_ls_ls_color() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; at.mkdir("a"); - at.mkdir("a/nested_dir"); + let nested_dir = Path::new("a") + .join("nested_dir") + .to_string_lossy() + .to_string(); + at.mkdir(&nested_dir); at.mkdir("z"); - at.touch(&at.plus_as_string("a/nested_file")); + let nested_file = Path::new("a") + .join("nested_file") + .to_string_lossy() + .to_string(); + at.touch(&nested_file); at.touch("test-color"); - let a_with_colors = "\x1b[01;34ma\x1b[0m"; - let z_with_colors = "\x1b[01;34mz\x1b[0m"; - let nested_dir_with_colors = "\x1b[01;34mnested_dir\x1b[0m"; + let a_with_colors = "\x1b[1;34ma\x1b[0m"; + let z_with_colors = "\x1b[1;34mz\x1b[0m"; + let nested_dir_with_colors = "\x1b[1;34mnested_dir\x1b[0m"; // Color is disabled by default let result = scene.ucmd().succeeds(); @@ -670,14 +677,6 @@ fn test_ls_ls_color() { .succeeds() .stdout_contains(nested_dir_with_colors); - // Color has no effect - scene - .ucmd() - .arg("--color=always") - .arg("a/nested_file") - .succeeds() - .stdout_contains("a/nested_file\n"); - // No output scene .ucmd() From e382f7fa830a59e1b6832987db2f0f8a9835ef9a Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 21 Apr 2021 17:43:57 +0200 Subject: [PATCH 2/7] ls: fix test warnings on Windows --- tests/by-util/test_ls.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index ed95c3034..c53091c94 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -816,7 +816,7 @@ fn test_ls_indicator_style() { let options = vec!["classify", "file-type", "slash"]; for opt in options { // Verify that classify and file-type both contain indicators for symlinks. - let result = scene + scene .ucmd() .arg(format!("--indicator-style={}", opt)) .succeeds() @@ -826,7 +826,7 @@ fn test_ls_indicator_style() { // Same test as above, but with the alternate flags. let options = vec!["--classify", "--file-type", "-p"]; for opt in options { - let result = scene + scene .ucmd() .arg(format!("{}", opt)) .succeeds() @@ -837,7 +837,7 @@ fn test_ls_indicator_style() { let options = vec!["classify", "file-type"]; for opt in options { // Verify that classify and file-type both contain indicators for symlinks. - let result = scene + scene .ucmd() .arg(format!("--indicator-style={}", opt)) .succeeds() @@ -961,7 +961,7 @@ fn test_ls_hidden_windows() { let result = scene.ucmd().succeeds(); assert!(!result.stdout_str().contains(file)); - let result = scene.ucmd().arg("-a").succeeds().stdout_contains(file); + scene.ucmd().arg("-a").succeeds().stdout_contains(file); } #[test] From ff3953837515257a32426e22d9f3bab75c984d5b Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 21 Apr 2021 17:57:17 +0200 Subject: [PATCH 3/7] ls: further refactor --color and classification --- src/uu/ls/src/ls.rs | 90 ++++++++-------------------------------- tests/by-util/test_ls.rs | 2 +- 2 files changed, 19 insertions(+), 73 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index c08e604f9..9f0c56245 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -35,8 +35,6 @@ use std::{cmp::Reverse, process::exit}; use term_grid::{Cell, Direction, Filling, Grid, GridOptions}; use time::{strftime, Timespec}; #[cfg(unix)] -use unicode_width::UnicodeWidthStr; -#[cfg(unix)] use uucore::libc::{mode_t, S_IXGRP, S_IXOTH, S_IXUSR}; static VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -1445,45 +1443,6 @@ fn get_file_name(name: &Path, strip: Option<&Path>) -> String { name.to_string_lossy().into_owned() } -// #[cfg(not(unix))] -// fn display_file_name( -// path: &Path, -// strip: Option<&Path>, -// metadata: &Metadata, -// config: &Config, -// ) -> Cell { -// let mut name = escape_name(get_file_name(path, strip), &config.quoting_style); -// let file_type = metadata.file_type(); - -// match config.indicator_style { -// IndicatorStyle::Classify | IndicatorStyle::FileType => { -// if file_type.is_dir() { -// name.push('/'); -// } -// if file_type.is_symlink() { -// name.push('@'); -// } -// } -// IndicatorStyle::Slash => { -// if file_type.is_dir() { -// name.push('/'); -// } -// } -// _ => (), -// }; - -// if config.format == Format::Long && metadata.file_type().is_symlink() { -// if let Ok(target) = path.read_link() { -// // We don't bother updating width here because it's not used for long listings -// let target_name = target.to_string_lossy().to_string(); -// name.push_str(" -> "); -// name.push_str(&target_name); -// } -// } - -// name.into() -// } - #[cfg(unix)] macro_rules! has { ($mode:expr, $perm:expr) => { @@ -1491,42 +1450,32 @@ macro_rules! has { }; } -#[cfg(unix)] fn classify_file(md: &Metadata) -> Option { let file_type = md.file_type(); + + #[allow(clippy::clippy::collapsible_else_if)] if file_type.is_dir() { Some('/') } else if file_type.is_symlink() { Some('@') - } else if file_type.is_socket() { - Some('=') - } else if file_type.is_fifo() { - Some('|') - } else if file_type.is_file() { - let mode = md.mode() as mode_t; - if has!(mode, S_IXUSR | S_IXGRP | S_IXOTH) { - Some('*') - } else { - None + } else { + #[cfg(unix)] + { + if file_type.is_socket() { + Some('=') + } else if file_type.is_fifo() { + Some('|') + } else if file_type.is_file() || has!(md.mode(), S_IXUSR | S_IXGRP | S_IXOTH) { + Some('*') + } else { + None + } } - } else { + #[cfg(not(unix))] None } } -#[cfg(not(unix))] -fn classify_file(md: &Metadata) -> Option { - let file_type = md.file_type(); - if file_type.is_dir() { - Some('/') - } else if file_type.is_symlink() { - Some('@') - } else { - None - } -} - -#[allow(clippy::cognitive_complexity)] fn display_file_name( path: &Path, strip: Option<&Path>, @@ -1541,7 +1490,7 @@ fn display_file_name( } if let Some(ls_colors) = &config.color { - name = color_name(&ls_colors, path, name, metadata).to_string(); + name = color_name(&ls_colors, path, name, metadata); } if config.indicator_style != IndicatorStyle::None { @@ -1589,11 +1538,8 @@ fn display_file_name( fn color_name(ls_colors: &LsColors, path: &Path, name: String, md: &Metadata) -> String { match ls_colors.style_for_path_with_metadata(path, Some(&md)) { - Some(style) => { - dbg!(style); - style.to_ansi_term_style().paint(name).to_string() - } - None => dbg!(name), + Some(style) => style.to_ansi_term_style().paint(name).to_string(), + None => name, } } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index c53091c94..5538864ca 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -622,7 +622,7 @@ fn test_ls_recursive() { } #[test] -fn test_ls_ls_color() { +fn test_ls_color() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; at.mkdir("a"); From 3fc8d2e42270d9ef08521346ca2e754f63f6c9b8 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 21 Apr 2021 18:05:02 +0200 Subject: [PATCH 4/7] ls: make compatible with Rust 1.40 again --- Cargo.lock | 41 +++++++++++++++++++++++++++++------------ src/uu/ls/src/ls.rs | 8 +++++--- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 461716b1b..5370c50e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "arrayvec" version = "0.4.12" @@ -127,9 +136,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cast" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +checksum = "cc38c385bfd7e444464011bb24820f40dd1c76bcdfa1b78611cb7c2e5cafab75" dependencies = [ "rustc_version", ] @@ -169,7 +178,7 @@ version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "ansi_term", + "ansi_term 0.11.0", "atty", "bitflags", "strsim", @@ -452,9 +461,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -580,7 +589,7 @@ checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", "winapi 0.3.9", ] @@ -783,6 +792,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "lscolors" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e" +dependencies = [ + "ansi_term 0.12.1", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -1176,9 +1194,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" dependencies = [ "bitflags", ] @@ -1189,7 +1207,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" dependencies = [ - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", ] [[package]] @@ -1454,7 +1472,7 @@ checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" dependencies = [ "libc", "numtoa", - "redox_syscall 0.2.5", + "redox_syscall 0.2.6", "redox_termios", ] @@ -1989,12 +2007,11 @@ dependencies = [ "atty", "clap", "globset", - "lazy_static", + "lscolors", "number_prefix", "term_grid", "termsize", "time", - "unicode-width", "uucore", "uucore_procs", ] diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 9f0c56245..07147ae4b 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1450,10 +1450,10 @@ macro_rules! has { }; } +#[allow(clippy::clippy::collapsible_else_if)] fn classify_file(md: &Metadata) -> Option { let file_type = md.file_type(); - #[allow(clippy::clippy::collapsible_else_if)] if file_type.is_dir() { Some('/') } else if file_type.is_symlink() { @@ -1485,8 +1485,10 @@ fn display_file_name( let mut name = escape_name(get_file_name(path, strip), &config.quoting_style); #[cfg(unix)] - if config.format != Format::Long && config.inode { - name = get_inode(metadata) + " " + &name; + { + if config.format != Format::Long && config.inode { + name = get_inode(metadata) + " " + &name; + } } if let Some(ls_colors) = &config.color { From 1d7e206d722b884bd65d59f267f2337351bdd5eb Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Wed, 21 Apr 2021 20:04:52 +0200 Subject: [PATCH 5/7] ls: fix mac build --- src/uu/ls/src/ls.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 07147ae4b..8c8033744 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -35,7 +35,7 @@ use std::{cmp::Reverse, process::exit}; use term_grid::{Cell, Direction, Filling, Grid, GridOptions}; use time::{strftime, Timespec}; #[cfg(unix)] -use uucore::libc::{mode_t, S_IXGRP, S_IXOTH, S_IXUSR}; +use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR}; static VERSION: &str = env!("CARGO_PKG_VERSION"); static ABOUT: &str = " @@ -1444,10 +1444,13 @@ fn get_file_name(name: &Path, strip: Option<&Path>) -> String { } #[cfg(unix)] -macro_rules! has { - ($mode:expr, $perm:expr) => { - $mode & ($perm as mode_t) != 0 - }; +fn file_is_executable(md: &Metadata) -> bool { + // Mode always returns u32, but the flags might not be, based on the platform + // e.g. linux has u32, mac has u16. + // S_IXUSR -> user has execute permission + // S_IXGRP -> group has execute persmission + // S_IXOTH -> other users have execute permission + md.mode() & ((S_IXUSR | S_IXGRP | S_IXOTH) as u32) != 0 } #[allow(clippy::clippy::collapsible_else_if)] @@ -1465,7 +1468,7 @@ fn classify_file(md: &Metadata) -> Option { Some('=') } else if file_type.is_fifo() { Some('|') - } else if file_type.is_file() || has!(md.mode(), S_IXUSR | S_IXGRP | S_IXOTH) { + } else if file_type.is_file() && file_is_executable(&md) { Some('*') } else { None From 4e4c3aba0066d3fbc27f44acab668cffe4959ee5 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Thu, 22 Apr 2021 11:16:33 +0200 Subject: [PATCH 6/7] ls: don't color symlink target --- src/uu/ls/src/ls.rs | 7 +------ tests/by-util/test_ls.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 8c8033744..88f26e604 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1528,13 +1528,8 @@ fn display_file_name( if config.format == Format::Long && metadata.file_type().is_symlink() { if let Ok(target) = path.read_link() { // We don't bother updating width here because it's not used for long - let mut target_name = target.to_string_lossy().to_string(); - if let Some(ls_colors) = &config.color { - target_name = color_name(&ls_colors, &target, target_name, metadata); - } name.push_str(" -> "); - - name.push_str(&target_name); + name.push_str(&target.to_string_lossy()); } } diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 5538864ca..f74443877 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -639,14 +639,18 @@ fn test_ls_color() { at.touch(&nested_file); at.touch("test-color"); + at.symlink_file(&nested_file, "link"); + let a_with_colors = "\x1b[1;34ma\x1b[0m"; let z_with_colors = "\x1b[1;34mz\x1b[0m"; let nested_dir_with_colors = "\x1b[1;34mnested_dir\x1b[0m"; + let link_with_color = "\x1b[1;36mlink\x1b[0m"; // Color is disabled by default let result = scene.ucmd().succeeds(); assert!(!result.stdout_str().contains(a_with_colors)); assert!(!result.stdout_str().contains(z_with_colors)); + assert!(!result.stdout_str().contains(link_with_color)); // Color should be enabled scene @@ -654,7 +658,8 @@ fn test_ls_color() { .arg("--color") .succeeds() .stdout_contains(a_with_colors) - .stdout_contains(z_with_colors); + .stdout_contains(z_with_colors) + .stdout_contains(link_with_color); // Color should be enabled scene @@ -662,12 +667,14 @@ fn test_ls_color() { .arg("--color=always") .succeeds() .stdout_contains(a_with_colors) - .stdout_contains(z_with_colors); + .stdout_contains(z_with_colors) + .stdout_contains(link_with_color); // Color should be disabled let result = scene.ucmd().arg("--color=never").succeeds(); assert!(!result.stdout_str().contains(a_with_colors)); assert!(!result.stdout_str().contains(z_with_colors)); + assert!(!result.stdout_str().contains(link_with_color)); // Nested dir should be shown and colored scene From b9f4964a96a45cfbff4ff7c6277c5357892093a6 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Thu, 22 Apr 2021 11:39:08 +0200 Subject: [PATCH 7/7] ls: bring up to date with recent changes --- Cargo.lock | 5 +++-- src/uu/ls/Cargo.toml | 3 +++ src/uu/ls/src/ls.rs | 10 ++++++---- tests/by-util/test_ls.rs | 11 ++--------- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5370c50e6..7ae0d078f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1412,9 +1412,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" dependencies = [ "proc-macro2", "quote 1.0.9", @@ -2007,6 +2007,7 @@ dependencies = [ "atty", "clap", "globset", + "lazy_static", "lscolors", "number_prefix", "term_grid", diff --git a/src/uu/ls/Cargo.toml b/src/uu/ls/Cargo.toml index addca6fbb..9fa06c6a6 100644 --- a/src/uu/ls/Cargo.toml +++ b/src/uu/ls/Cargo.toml @@ -26,6 +26,9 @@ uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=[" uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } atty = "0.2" +[target.'cfg(unix)'.dependencies] +lazy_static = "1.4.0" + [[bin]] name = "ls" path = "src/main.rs" diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 99c41bdb8..3feee0f07 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -9,6 +9,9 @@ #[macro_use] extern crate uucore; +#[cfg(unix)] +#[macro_use] +extern crate lazy_static; mod quoting_style; mod version_cmp; @@ -18,12 +21,11 @@ use globset::{self, Glob, GlobSet, GlobSetBuilder}; use lscolors::LsColors; use number_prefix::NumberPrefix; use quoting_style::{escape_name, QuotingStyle}; -use std::fs; -use std::fs::{DirEntry, FileType, Metadata}; #[cfg(unix)] -use std::os::unix::fs::FileTypeExt; +use std::collections::HashMap; +use std::fs::{self, DirEntry, FileType, Metadata}; #[cfg(any(unix, target_os = "redox"))] -use std::os::unix::fs::MetadataExt; +use std::os::unix::fs::{FileTypeExt, MetadataExt}; #[cfg(windows)] use std::os::windows::fs::MetadataExt; use std::path::{Path, PathBuf}; diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 4282bcfc0..f87e64688 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -647,18 +647,14 @@ fn test_ls_color() { at.touch(&nested_file); at.touch("test-color"); - at.symlink_file(&nested_file, "link"); - let a_with_colors = "\x1b[1;34ma\x1b[0m"; let z_with_colors = "\x1b[1;34mz\x1b[0m"; let nested_dir_with_colors = "\x1b[1;34mnested_dir\x1b[0m"; - let link_with_color = "\x1b[1;36mlink\x1b[0m"; // Color is disabled by default let result = scene.ucmd().succeeds(); assert!(!result.stdout_str().contains(a_with_colors)); assert!(!result.stdout_str().contains(z_with_colors)); - assert!(!result.stdout_str().contains(link_with_color)); // Color should be enabled scene @@ -666,8 +662,7 @@ fn test_ls_color() { .arg("--color") .succeeds() .stdout_contains(a_with_colors) - .stdout_contains(z_with_colors) - .stdout_contains(link_with_color); + .stdout_contains(z_with_colors); // Color should be enabled scene @@ -675,14 +670,12 @@ fn test_ls_color() { .arg("--color=always") .succeeds() .stdout_contains(a_with_colors) - .stdout_contains(z_with_colors) - .stdout_contains(link_with_color); + .stdout_contains(z_with_colors); // Color should be disabled let result = scene.ucmd().arg("--color=never").succeeds(); assert!(!result.stdout_str().contains(a_with_colors)); assert!(!result.stdout_str().contains(z_with_colors)); - assert!(!result.stdout_str().contains(link_with_color)); // Nested dir should be shown and colored scene