Skip to content

Commit

Permalink
dircolors: implement --print-ls-colors
Browse files Browse the repository at this point in the history
  • Loading branch information
cakebaker committed May 26, 2022
1 parent 172f5c4 commit d361d31
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 11 deletions.
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 @@ -184,6 +197,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 @@ -252,6 +271,7 @@ enum ParseState {
Continue,
Pass,
}

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

Expand All @@ -260,11 +280,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);
match fmt {
OutputFmt::Shell => result.push_str("LS_COLORS='"),
OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
OutputFmt::Display => (),
_ => unreachable!(),
}

Expand Down Expand Up @@ -343,13 +364,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 @@ -365,6 +398,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 @@ -61,6 +61,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 @@ -95,6 +103,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

0 comments on commit d361d31

Please sign in to comment.