mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
Merge pull request #5778 from RenjiSann/main
ls: Support QUOTING_STYLE environment variable
This commit is contained in:
commit
e13f0d80ee
2 changed files with 136 additions and 38 deletions
|
@ -621,7 +621,52 @@ fn extract_hyperlink(options: &clap::ArgMatches) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Match the argument given to --quoting-style or the QUOTING_STYLE env variable.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `style`: the actual argument string
|
||||
/// * `show_control` - A boolean value representing whether or not to show control characters.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * An option with None if the style string is invalid, or a `QuotingStyle` wrapped in `Some`.
|
||||
fn match_quoting_style_name(style: &str, show_control: bool) -> Option<QuotingStyle> {
|
||||
match style {
|
||||
"literal" => Some(QuotingStyle::Literal { show_control }),
|
||||
"shell" => Some(QuotingStyle::Shell {
|
||||
escape: false,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
}),
|
||||
"shell-always" => Some(QuotingStyle::Shell {
|
||||
escape: false,
|
||||
always_quote: true,
|
||||
show_control,
|
||||
}),
|
||||
"shell-escape" => Some(QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
}),
|
||||
"shell-escape-always" => Some(QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: true,
|
||||
show_control,
|
||||
}),
|
||||
"c" => Some(QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::Double,
|
||||
}),
|
||||
"escape" => Some(QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::None,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the quoting style to use based on the options provided.
|
||||
/// If no options are given, it looks if a default quoting style is provided
|
||||
/// through the QUOTING_STYLE environment variable.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
|
@ -632,38 +677,12 @@ fn extract_hyperlink(options: &clap::ArgMatches) -> bool {
|
|||
///
|
||||
/// A QuotingStyle variant representing the quoting style to use.
|
||||
fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> QuotingStyle {
|
||||
let opt_quoting_style = options.get_one::<String>(options::QUOTING_STYLE).cloned();
|
||||
let opt_quoting_style = options.get_one::<String>(options::QUOTING_STYLE);
|
||||
|
||||
if let Some(style) = opt_quoting_style {
|
||||
match style.as_str() {
|
||||
"literal" => QuotingStyle::Literal { show_control },
|
||||
"shell" => QuotingStyle::Shell {
|
||||
escape: false,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
},
|
||||
"shell-always" => QuotingStyle::Shell {
|
||||
escape: false,
|
||||
always_quote: true,
|
||||
show_control,
|
||||
},
|
||||
"shell-escape" => QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
},
|
||||
"shell-escape-always" => QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: true,
|
||||
show_control,
|
||||
},
|
||||
"c" => QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::Double,
|
||||
},
|
||||
"escape" => QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::None,
|
||||
},
|
||||
_ => unreachable!("Should have been caught by Clap"),
|
||||
match match_quoting_style_name(style, show_control) {
|
||||
Some(qs) => qs,
|
||||
None => unreachable!("Should have been caught by Clap"),
|
||||
}
|
||||
} else if options.get_flag(options::quoting::LITERAL) {
|
||||
QuotingStyle::Literal { show_control }
|
||||
|
@ -675,16 +694,31 @@ fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> Quot
|
|||
QuotingStyle::C {
|
||||
quotes: quoting_style::Quotes::Double,
|
||||
}
|
||||
} else if options.get_flag(options::DIRED) || !std::io::stdout().is_terminal() {
|
||||
// By default, `ls` uses Literal quoting when
|
||||
// writing to a non-terminal file descriptor
|
||||
} else if options.get_flag(options::DIRED) {
|
||||
QuotingStyle::Literal { show_control }
|
||||
} else {
|
||||
// TODO: use environment variable if available
|
||||
QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
// If set, the QUOTING_STYLE environment variable specifies a default style.
|
||||
if let Ok(style) = std::env::var("QUOTING_STYLE") {
|
||||
match match_quoting_style_name(style.as_str(), show_control) {
|
||||
Some(qs) => return qs,
|
||||
None => eprintln!(
|
||||
"{}: Ignoring invalid value of environment variable QUOTING_STYLE: '{}'",
|
||||
std::env::args().next().unwrap_or("ls".to_string()),
|
||||
style
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// By default, `ls` uses Shell escape quoting style when writing to a terminal file
|
||||
// descriptor and Literal otherwise.
|
||||
if std::io::stdout().is_terminal() {
|
||||
QuotingStyle::Shell {
|
||||
escape: true,
|
||||
always_quote: false,
|
||||
show_control,
|
||||
}
|
||||
} else {
|
||||
QuotingStyle::Literal { show_control }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2622,6 +2622,70 @@ fn test_ls_quoting_style() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_quoting_style_env_var_default() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch(at.plus_as_string("foo-1"));
|
||||
at.touch(at.plus_as_string("bar-2"));
|
||||
|
||||
// If no quoting style argument is provided, the QUOTING_STYLE environment variable
|
||||
// shall be used.
|
||||
|
||||
let correct_c = "\"bar-2\"\n\"foo-1\"";
|
||||
scene
|
||||
.ucmd()
|
||||
.env("QUOTING_STYLE", "c")
|
||||
.succeeds()
|
||||
.stdout_only(format!("{correct_c}\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_quoting_style_arg_overrides_env_var() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.touch(at.plus_as_string("foo-1"));
|
||||
at.touch(at.plus_as_string("bar-2"));
|
||||
|
||||
// The quoting style given by the env variable should be
|
||||
// overridden by any escape style provided by argument.
|
||||
for (arg, correct) in [
|
||||
("--quoting-style=literal", "foo-1"),
|
||||
("-N", "foo-1"),
|
||||
("--quoting-style=escape", "foo-1"),
|
||||
("-b", "foo-1"),
|
||||
("--quoting-style=shell-escape", "foo-1"),
|
||||
("--quoting-style=shell-escape-always", "'foo-1'"),
|
||||
("--quoting-style=shell", "foo-1"),
|
||||
("--quoting-style=shell-always", "'foo-1'"),
|
||||
] {
|
||||
scene
|
||||
.ucmd()
|
||||
.env("QUOTING_STYLE", "c")
|
||||
.arg("--hide-control-chars")
|
||||
.arg(arg)
|
||||
.arg("foo-1")
|
||||
.succeeds()
|
||||
.stdout_only(format!("{correct}\n"));
|
||||
}
|
||||
|
||||
// Another loop to check for the C quoting style that is used as a default above.
|
||||
for (arg, correct) in [
|
||||
("--quoting-style=c", "\"foo-1\""),
|
||||
("-Q", "\"foo-1\""),
|
||||
("--quote-name", "\"foo-1\""),
|
||||
] {
|
||||
scene
|
||||
.ucmd()
|
||||
.env("QUOTING_STYLE", "literal")
|
||||
.arg("--hide-control-chars")
|
||||
.arg(arg)
|
||||
.arg("foo-1")
|
||||
.succeeds()
|
||||
.stdout_only(format!("{correct}\n"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ls_quoting_and_color() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue