1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

dircolors: implement --print-ls-colors

This commit is contained in:
Daniel Hofstetter 2022-05-19 08:00:56 +02:00
parent 7861cc9dca
commit 6d82523a99
4 changed files with 217 additions and 11 deletions

View file

@ -4,6 +4,7 @@ Create the test fixtures by writing the output of the GNU dircolors commands to
``` ```
$ dircolors --print-database > /PATH_TO_COREUTILS/tests/fixtures/dircolors/internal.expected $ dircolors --print-database > /PATH_TO_COREUTILS/tests/fixtures/dircolors/internal.expected
$ dircolors --print-ls-colors > /PATH_TO_COREUTILS/tests/fixtures/dircolors/ls_colors.expected
$ dircolors -b > /PATH_TO_COREUTILS/tests/fixtures/dircolors/bash_def.expected $ dircolors -b > /PATH_TO_COREUTILS/tests/fixtures/dircolors/bash_def.expected
$ dircolors -c > /PATH_TO_COREUTILS/tests/fixtures/dircolors/csh_def.expected $ dircolors -c > /PATH_TO_COREUTILS/tests/fixtures/dircolors/csh_def.expected
``` ```

View file

@ -21,6 +21,7 @@ mod options {
pub const BOURNE_SHELL: &str = "bourne-shell"; pub const BOURNE_SHELL: &str = "bourne-shell";
pub const C_SHELL: &str = "c-shell"; pub const C_SHELL: &str = "c-shell";
pub const PRINT_DATABASE: &str = "print-database"; pub const PRINT_DATABASE: &str = "print-database";
pub const PRINT_LS_COLORS: &str = "print-ls-colors";
pub const FILE: &str = "FILE"; pub const FILE: &str = "FILE";
} }
@ -39,6 +40,7 @@ use self::colors::INTERNAL_DB;
pub enum OutputFmt { pub enum OutputFmt {
Shell, Shell,
CShell, CShell,
Display,
Unknown, Unknown,
} }
@ -76,7 +78,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// clap provides .conflicts_with / .conflicts_with_all, but we want to // clap provides .conflicts_with / .conflicts_with_all, but we want to
// manually handle conflicts so we can match the output of GNU coreutils // manually handle conflicts so we can match the output of GNU coreutils
if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL)) if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL))
&& matches.is_present(options::PRINT_DATABASE) && (matches.is_present(options::PRINT_DATABASE)
|| matches.is_present(options::PRINT_LS_COLORS))
{ {
return Err(UUsageError::new( return Err(UUsageError::new(
1, 1,
@ -85,6 +88,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
)); ));
} }
if matches.is_present(options::PRINT_DATABASE) && matches.is_present(options::PRINT_LS_COLORS) {
return Err(UUsageError::new(
1,
"options --print-database and --print-ls-colors are mutually exclusive",
));
}
if matches.is_present(options::PRINT_DATABASE) { if matches.is_present(options::PRINT_DATABASE) {
if !files.is_empty() { if !files.is_empty() {
return Err(UUsageError::new( return Err(UUsageError::new(
@ -100,12 +110,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
return Ok(()); return Ok(());
} }
let mut out_format = OutputFmt::Unknown; let mut out_format = if matches.is_present(options::C_SHELL) {
if matches.is_present(options::C_SHELL) { OutputFmt::CShell
out_format = OutputFmt::CShell;
} else if matches.is_present(options::BOURNE_SHELL) { } else if matches.is_present(options::BOURNE_SHELL) {
out_format = OutputFmt::Shell; OutputFmt::Shell
} } else if matches.is_present(options::PRINT_LS_COLORS) {
OutputFmt::Display
} else {
OutputFmt::Unknown
};
if out_format == OutputFmt::Unknown { if out_format == OutputFmt::Unknown {
match guess_syntax() { match guess_syntax() {
@ -186,6 +199,12 @@ pub fn uu_app<'a>() -> Command<'a> {
.help("print the byte counts") .help("print the byte counts")
.display_order(3), .display_order(3),
) )
.arg(
Arg::new(options::PRINT_LS_COLORS)
.long("print-ls-colors")
.help("output fully escaped colors for display")
.display_order(4),
)
.arg( .arg(
Arg::new(options::FILE) Arg::new(options::FILE)
.hide(true) .hide(true)
@ -254,6 +273,7 @@ enum ParseState {
Continue, Continue,
Pass, Pass,
} }
use std::collections::HashMap; use std::collections::HashMap;
use uucore::{format_usage, InvalidEncodingHandling}; use uucore::{format_usage, InvalidEncodingHandling};
@ -262,11 +282,12 @@ where
T: IntoIterator, T: IntoIterator,
T::Item: Borrow<str>, T::Item: Borrow<str>,
{ {
// 1440 > $(dircolors | wc -m) // 1790 > $(dircolors | wc -m)
let mut result = String::with_capacity(1440); let mut result = String::with_capacity(1790);
match fmt { match fmt {
OutputFmt::Shell => result.push_str("LS_COLORS='"), OutputFmt::Shell => result.push_str("LS_COLORS='"),
OutputFmt::CShell => result.push_str("setenv LS_COLORS '"), OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
OutputFmt::Display => (),
_ => unreachable!(), _ => unreachable!(),
} }
@ -345,13 +366,25 @@ where
} }
if state != ParseState::Pass { if state != ParseState::Pass {
if key.starts_with('.') { if key.starts_with('.') {
result.push_str(format!("*{}={}:", key, val).as_str()); if *fmt == OutputFmt::Display {
result.push_str(format!("\x1b[{1}m*{0}\t{1}\x1b[0m\n", key, val).as_str());
} else {
result.push_str(format!("*{}={}:", key, val).as_str());
}
} else if key.starts_with('*') { } else if key.starts_with('*') {
result.push_str(format!("{}={}:", key, val).as_str()); if *fmt == OutputFmt::Display {
result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", key, val).as_str());
} else {
result.push_str(format!("{}={}:", key, val).as_str());
}
} else if lower == "options" || lower == "color" || lower == "eightbit" { } else if lower == "options" || lower == "color" || lower == "eightbit" {
// Slackware only. Ignore // Slackware only. Ignore
} else if let Some(s) = table.get(lower.as_str()) { } else if let Some(s) = table.get(lower.as_str()) {
result.push_str(format!("{}={}:", s, val).as_str()); if *fmt == OutputFmt::Display {
result.push_str(format!("\x1b[{1}m{0}\t{1}\x1b[0m\n", s, val).as_str());
} else {
result.push_str(format!("{}={}:", s, val).as_str());
}
} else { } else {
return Err(format!( return Err(format!(
"{}:{}: unrecognized keyword {}", "{}:{}: unrecognized keyword {}",
@ -367,6 +400,10 @@ where
match fmt { match fmt {
OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"), OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
OutputFmt::CShell => result.push('\''), OutputFmt::CShell => result.push('\''),
OutputFmt::Display => {
// remove latest "\n"
result.pop();
}
_ => unreachable!(), _ => unreachable!(),
} }

View file

@ -62,6 +62,14 @@ fn test_internal_db() {
.stdout_is_fixture("internal.expected"); .stdout_is_fixture("internal.expected");
} }
#[test]
fn test_ls_colors() {
new_ucmd!()
.arg("--print-ls-colors")
.run()
.stdout_is_fixture("ls_colors.expected");
}
#[test] #[test]
fn test_bash_default() { fn test_bash_default() {
new_ucmd!() new_ucmd!()
@ -109,6 +117,18 @@ fn test_exclusive_option() {
.arg("-cp") .arg("-cp")
.fails() .fails()
.stderr_contains("mutually exclusive"); .stderr_contains("mutually exclusive");
new_ucmd!()
.args(&["-b", "--print-ls-colors"])
.fails()
.stderr_contains("mutually exclusive");
new_ucmd!()
.args(&["-c", "--print-ls-colors"])
.fails()
.stderr_contains("mutually exclusive");
new_ucmd!()
.args(&["-p", "--print-ls-colors"])
.fails()
.stderr_contains("mutually exclusive");
} }
fn test_helper(file_name: &str, term: &str) { fn test_helper(file_name: &str, term: &str) {

View file

@ -0,0 +1,148 @@
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 00
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
*.dz 01;31
*.gz 01;31
*.lrz 01;31
*.lz 01;31
*.lzo 01;31
*.xz 01;31
*.zst 01;31
*.tzst 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
*.wim 01;31
*.swm 01;31
*.dwm 01;31
*.esd 01;31
*.avif 01;35
*.jpg 01;35
*.jpeg 01;35
*.mjpg 01;35
*.mjpeg 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
*.webp 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
*~ 00;90
*# 00;90
*.bak 00;90
*.old 00;90
*.orig 00;90
*.part 00;90
*.rej 00;90
*.swp 00;90
*.tmp 00;90
*.dpkg-dist 00;90
*.dpkg-old 00;90
*.ucf-dist 00;90
*.ucf-new 00;90
*.ucf-old 00;90
*.rpmnew 00;90
*.rpmorig 00;90
*.rpmsave 00;90