Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dircolors: implement --print-ls-colors #3566

Merged
merged 1 commit into from
Jun 1, 2022
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/dircolors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-ls-colors > /PATH_TO_COREUTILS/tests/fixtures/dircolors/ls_colors.expected
$ dircolors -b > /PATH_TO_COREUTILS/tests/fixtures/dircolors/bash_def.expected
$ dircolors -c > /PATH_TO_COREUTILS/tests/fixtures/dircolors/csh_def.expected
```
Expand Down
59 changes: 48 additions & 11 deletions src/uu/dircolors/src/dircolors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod options {
pub const BOURNE_SHELL: &str = "bourne-shell";
pub const C_SHELL: &str = "c-shell";
pub const PRINT_DATABASE: &str = "print-database";
pub const PRINT_LS_COLORS: &str = "print-ls-colors";
pub const FILE: &str = "FILE";
}

Expand All @@ -39,6 +40,7 @@ use self::colors::INTERNAL_DB;
pub enum OutputFmt {
Shell,
CShell,
Display,
Unknown,
}

Expand Down Expand Up @@ -76,7 +78,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// clap provides .conflicts_with / .conflicts_with_all, but we want to
// 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))
&& matches.is_present(options::PRINT_DATABASE)
&& (matches.is_present(options::PRINT_DATABASE)
|| matches.is_present(options::PRINT_LS_COLORS))
{
return Err(UUsageError::new(
1,
Expand All @@ -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 !files.is_empty() {
return Err(UUsageError::new(
Expand All @@ -100,12 +110,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
return Ok(());
}

let mut out_format = OutputFmt::Unknown;
if matches.is_present(options::C_SHELL) {
out_format = OutputFmt::CShell;
let mut out_format = if matches.is_present(options::C_SHELL) {
OutputFmt::CShell
} 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 {
match guess_syntax() {
Expand Down Expand Up @@ -186,6 +199,12 @@ pub fn uu_app<'a>() -> Command<'a> {
.help("print the byte counts")
.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::new(options::FILE)
.hide(true)
Expand Down Expand Up @@ -254,6 +273,7 @@ enum ParseState {
Continue,
Pass,
}

use std::collections::HashMap;
use uucore::{format_usage, InvalidEncodingHandling};

Expand All @@ -262,11 +282,12 @@ where
T: IntoIterator,
T::Item: Borrow<str>,
{
// 1440 > $(dircolors | wc -m)
let mut result = String::with_capacity(1440);
// 1790 > $(dircolors | wc -m)
let mut result = String::with_capacity(1790);
sylvestre marked this conversation as resolved.
Show resolved Hide resolved
match fmt {
OutputFmt::Shell => result.push_str("LS_COLORS='"),
OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
OutputFmt::Display => (),
_ => unreachable!(),
}

Expand Down Expand Up @@ -345,13 +366,25 @@ where
}
if state != ParseState::Pass {
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('*') {
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" {
// Slackware only. Ignore
} 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 {
return Err(format!(
"{}:{}: unrecognized keyword {}",
Expand All @@ -367,6 +400,10 @@ where
match fmt {
OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
OutputFmt::CShell => result.push('\''),
OutputFmt::Display => {
// remove latest "\n"
result.pop();
}
_ => unreachable!(),
}

Expand Down
20 changes: 20 additions & 0 deletions tests/by-util/test_dircolors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ fn test_internal_db() {
.stdout_is_fixture("internal.expected");
}

#[test]
fn test_ls_colors() {
new_ucmd!()
.arg("--print-ls-colors")
.run()
.stdout_is_fixture("ls_colors.expected");
}

#[test]
fn test_bash_default() {
new_ucmd!()
Expand Down Expand Up @@ -109,6 +117,18 @@ fn test_exclusive_option() {
.arg("-cp")
.fails()
.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) {
Expand Down
148 changes: 148 additions & 0 deletions tests/fixtures/dircolors/ls_colors.expected
Original file line number Diff line number Diff line change
@@ -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