Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/uu/ls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ terminal_size = { workspace = true }
glob = { workspace = true }
lscolors = { workspace = true }
uucore = { workspace = true, features = [
"colors",
"entries",
"fs",
"quoting-style",
Expand Down
33 changes: 32 additions & 1 deletion src/uu/ls/src/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype
// spell-checker:ignore (ToDO) somegroup nlink tabsize dired subdired dtype colorterm

use clap::{
builder::{NonEmptyStringValueParser, ValueParser},
Expand Down Expand Up @@ -553,12 +553,43 @@ fn extract_time(options: &clap::ArgMatches) -> Time {
}
}

// Some env variables can be passed
// For now, we are only verifying if empty or not and known for TERM
fn is_color_compatible_term() -> bool {
let is_term_set = std::env::var("TERM").is_ok();
let is_colorterm_set = std::env::var("COLORTERM").is_ok();

let term = std::env::var("TERM").unwrap_or_default();
let colorterm = std::env::var("COLORTERM").unwrap_or_default();

// Search function in the TERM struct to manage the wildcards
let term_matches = |term: &str| -> bool {
uucore::colors::TERMS.iter().any(|&pattern| {
term == pattern
|| (pattern.ends_with('*') && term.starts_with(&pattern[..pattern.len() - 1]))
})
};

if is_term_set && term.is_empty() && is_colorterm_set && colorterm.is_empty() {
return false;
}

if !term.is_empty() && !term_matches(&term) {
return false;
}
true
}

/// Extracts the color option to use based on the options provided.
///
/// # Returns
///
/// A boolean representing whether or not to use color.
fn extract_color(options: &clap::ArgMatches) -> bool {
if !is_color_compatible_term() {
return false;
}

match options.get_one::<String>(options::COLOR) {
None => options.contains_id(options::COLOR),
Some(val) => match val.as_str() {
Expand Down
61 changes: 60 additions & 1 deletion tests/by-util/test_ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) READMECAREFULLY birthtime doesntexist oneline somebackup lrwx somefile somegroup somehiddenbackup somehiddenfile tabsize aaaaaaaa bbbb cccc dddddddd ncccc neee naaaaa nbcdef nfffff dired subdired tmpfs mdir
// spell-checker:ignore (words) READMECAREFULLY birthtime doesntexist oneline somebackup lrwx somefile somegroup somehiddenbackup somehiddenfile tabsize aaaaaaaa bbbb cccc dddddddd ncccc neee naaaaa nbcdef nfffff dired subdired tmpfs mdir COLORTERM mexe

#[cfg(any(unix, feature = "feat_selinux"))]
use crate::common::util::expected_result;
Expand Down Expand Up @@ -3988,3 +3988,62 @@ fn test_ls_color_do_not_reset() {
"\\u{1b}[0m\\u{1b}[01;34ma\\u{1b}[0m\\n\\u{1b}[01;34mb\\u{1b}[0m\\n"
);
}

#[cfg(all(unix, feature = "chmod"))]
#[test]
fn test_term_colorterm() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("exe");
scene.ccmd("chmod").arg("+x").arg("exe").succeeds();

// Should show colors
let result = scene
.ucmd()
.arg("--color=always")
.env("LS_COLORS", "")
.env("TERM", "")
.succeeds();
assert_eq!(
result.stdout_str().trim().escape_default().to_string(),
"\\u{1b}[0m\\u{1b}[01;32mexe\\u{1b}[0m"
);

// Should show colors
let result = scene
.ucmd()
.arg("--color=always")
.env("LS_COLORS", "")
.env("COLORTERM", "")
.succeeds();
assert_eq!(
result.stdout_str().trim().escape_default().to_string(),
"\\u{1b}[0m\\u{1b}[01;32mexe\\u{1b}[0m"
);

// No colors
let result = scene
.ucmd()
.arg("--color=always")
.env("LS_COLORS", "")
.env("TERM", "")
.env("COLORTERM", "")
.succeeds();
assert_eq!(
result.stdout_str().trim().escape_default().to_string(),
"exe"
);

// No colors
let result = scene
.ucmd()
.arg("--color=always")
.env("LS_COLORS", "")
.env("TERM", "dumb")
.env("COLORTERM", "")
.succeeds();
assert_eq!(
result.stdout_str().trim().escape_default().to_string(),
"exe"
);
}