Skip to content

Commit 92c3de5

Browse files
authored
Merge pull request #6144 from sylvestre/dired
ls --dired: adjust our code after GNU v9.5
2 parents 9b11753 + ececddd commit 92c3de5

File tree

3 files changed

+79
-17
lines changed

3 files changed

+79
-17
lines changed

src/uu/ls/src/dired.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ pub fn update_positions(dired: &mut DiredOutput, start: usize, end: usize) {
179179
dired.padding = 0;
180180
}
181181

182+
/// Checks if the "--dired" or "-D" argument is present in the command line arguments.
183+
/// we don't use clap here because we need to know if the argument is present
184+
/// as it can be overridden by --hyperlink
185+
pub fn is_dired_arg_present() -> bool {
186+
let args: Vec<String> = std::env::args().collect();
187+
args.iter().any(|x| x == "--dired" || x == "-D")
188+
}
189+
182190
#[cfg(test)]
183191
mod tests {
184192
use super::*;

src/uu/ls/src/ls.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use uucore::{
6767
};
6868
use uucore::{help_about, help_section, help_usage, parse_glob, show, show_error, show_warning};
6969
mod dired;
70-
use dired::DiredOutput;
70+
use dired::{is_dired_arg_present, DiredOutput};
7171
#[cfg(not(feature = "selinux"))]
7272
static CONTEXT_HELP_TEXT: &str = "print any security context of each file (not enabled)";
7373
#[cfg(feature = "selinux")]
@@ -174,7 +174,6 @@ enum LsError {
174174
IOError(std::io::Error),
175175
IOErrorContext(std::io::Error, PathBuf, bool),
176176
BlockSizeParseError(String),
177-
ConflictingArgumentDired,
178177
DiredAndZeroAreIncompatible,
179178
AlreadyListedError(PathBuf),
180179
TimeStyleParseError(String, Vec<String>),
@@ -188,7 +187,6 @@ impl UError for LsError {
188187
Self::IOErrorContext(_, _, false) => 1,
189188
Self::IOErrorContext(_, _, true) => 2,
190189
Self::BlockSizeParseError(_) => 2,
191-
Self::ConflictingArgumentDired => 1,
192190
Self::DiredAndZeroAreIncompatible => 2,
193191
Self::AlreadyListedError(_) => 2,
194192
Self::TimeStyleParseError(_, _) => 2,
@@ -204,9 +202,6 @@ impl Display for LsError {
204202
Self::BlockSizeParseError(s) => {
205203
write!(f, "invalid --block-size argument {}", s.quote())
206204
}
207-
Self::ConflictingArgumentDired => {
208-
write!(f, "--dired requires --format=long")
209-
}
210205
Self::DiredAndZeroAreIncompatible => {
211206
write!(f, "--dired and --zero are incompatible")
212207
}
@@ -1084,10 +1079,13 @@ impl Config {
10841079
};
10851080

10861081
let dired = options.get_flag(options::DIRED);
1087-
if dired && format != Format::Long {
1088-
return Err(Box::new(LsError::ConflictingArgumentDired));
1082+
if dired || is_dired_arg_present() {
1083+
// --dired implies --format=long
1084+
// if we have --dired --hyperlink, we don't show dired but we still want to see the
1085+
// long format
1086+
format = Format::Long;
10891087
}
1090-
if dired && format == Format::Long && options.get_flag(options::ZERO) {
1088+
if dired && options.get_flag(options::ZERO) {
10911089
return Err(Box::new(LsError::DiredAndZeroAreIncompatible));
10921090
}
10931091

@@ -1215,6 +1213,7 @@ pub fn uu_app() -> Command {
12151213
options::format::LONG,
12161214
options::format::ACROSS,
12171215
options::format::COLUMNS,
1216+
options::DIRED,
12181217
]),
12191218
)
12201219
.arg(
@@ -1291,7 +1290,8 @@ pub fn uu_app() -> Command {
12911290
.long(options::DIRED)
12921291
.short('D')
12931292
.help("generate output designed for Emacs' dired (Directory Editor) mode")
1294-
.action(ArgAction::SetTrue),
1293+
.action(ArgAction::SetTrue)
1294+
.overrides_with(options::HYPERLINK),
12951295
)
12961296
.arg(
12971297
Arg::new(options::HYPERLINK)
@@ -1306,7 +1306,8 @@ pub fn uu_app() -> Command {
13061306
.num_args(0..=1)
13071307
.default_missing_value("always")
13081308
.default_value("never")
1309-
.value_name("WHEN"),
1309+
.value_name("WHEN")
1310+
.overrides_with(options::DIRED),
13101311
)
13111312
// The next four arguments do not override with the other format
13121313
// options, see the comment in Config::from for the reason.
@@ -2022,7 +2023,7 @@ impl PathData {
20222023
}
20232024

20242025
fn show_dir_name(path_data: &PathData, out: &mut BufWriter<Stdout>, config: &Config) {
2025-
if config.hyperlink {
2026+
if config.hyperlink && !config.dired {
20262027
let name = escape_name(&path_data.display_name, &config.quoting_style);
20272028
let hyperlink = create_hyperlink(&name, path_data);
20282029
write!(out, "{}:", hyperlink).unwrap();
@@ -2127,7 +2128,7 @@ pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
21272128
&mut style_manager,
21282129
)?;
21292130
}
2130-
if config.dired {
2131+
if config.dired && !config.hyperlink {
21312132
dired::print_dired_output(config, &dired, &mut out)?;
21322133
}
21332134
Ok(())

tests/by-util/test_ls.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3929,15 +3929,68 @@ fn test_ls_perm_io_errors() {
39293929
}
39303930

39313931
#[test]
3932-
fn test_ls_dired_incompatible() {
3932+
fn test_ls_dired_implies_long() {
39333933
let scene = TestScenario::new(util_name!());
39343934

39353935
scene
39363936
.ucmd()
39373937
.arg("--dired")
3938-
.fails()
3939-
.code_is(1)
3940-
.stderr_contains("--dired requires --format=long");
3938+
.succeeds()
3939+
.stdout_does_not_contain("//DIRED//")
3940+
.stdout_contains(" total 0")
3941+
.stdout_contains("//DIRED-OPTIONS// --quoting-style");
3942+
}
3943+
3944+
#[test]
3945+
fn test_ls_dired_hyperlink() {
3946+
// we will have link but not the DIRED output
3947+
// note that the order matters
3948+
let scene = TestScenario::new(util_name!());
3949+
let at = &scene.fixtures;
3950+
at.mkdir("dir");
3951+
at.touch("dir/a");
3952+
scene
3953+
.ucmd()
3954+
.arg("--dired")
3955+
.arg("--hyperlink")
3956+
.arg("-R")
3957+
.succeeds()
3958+
.stdout_contains("file://")
3959+
.stdout_contains("-rw") // we should have the long output
3960+
// even if dired isn't actually run
3961+
.stdout_does_not_contain("//DIRED//");
3962+
// dired is passed after hyperlink
3963+
// so we will have DIRED output
3964+
scene
3965+
.ucmd()
3966+
.arg("--hyperlink")
3967+
.arg("--dired")
3968+
.arg("-R")
3969+
.succeeds()
3970+
.stdout_does_not_contain("file://")
3971+
.stdout_contains("//DIRED//");
3972+
}
3973+
3974+
#[test]
3975+
fn test_ls_dired_order_format() {
3976+
let scene = TestScenario::new(util_name!());
3977+
let at = &scene.fixtures;
3978+
at.mkdir("dir");
3979+
at.touch("dir/a");
3980+
scene
3981+
.ucmd()
3982+
.arg("--dired")
3983+
.arg("--format=vertical")
3984+
.arg("-R")
3985+
.succeeds()
3986+
.stdout_does_not_contain("//DIRED//");
3987+
scene
3988+
.ucmd()
3989+
.arg("--format=vertical")
3990+
.arg("--dired")
3991+
.arg("-R")
3992+
.succeeds()
3993+
.stdout_contains("//DIRED//");
39413994
}
39423995

39433996
#[test]

0 commit comments

Comments
 (0)