From 4b759ddc972761eb1839b41048d952d3e7baa53a Mon Sep 17 00:00:00 2001 From: Guilherme-M-Mateus Date: Sun, 25 Oct 2026 19:07:31 +0000 Subject: [PATCH] ls: keep pending dired padding before directory headings After a directory that lists no entry, its heading and "total" line were dropped from the --dired byte count, shifting every later offset. Fixes #15800 Co-Authored-By: Claude Opus 5.5 --- src/uu/ls/src/ls.rs | 5 +++-- tests/by-util/test_ls.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index c7e6fd48804..a2e923f86d4 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1078,8 +1078,9 @@ impl LsOutput for TextOutput<'_> { if !is_first { writeln!(self.state.out)?; if config.dired { - self.dired.line_offset += 1; // account for the blank line before recursive directory headings - self.dired.padding = 0; + // Account for the blank line before the heading. Keep the padding: after a + // directory that listed no entry it still holds that heading and "total" line. + self.dired.line_offset += 1; } } if config.dired { diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 91445abd734..0dfc8a6585d 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -6256,6 +6256,40 @@ fn names_at_offsets(output: &str, tag: &str) -> Vec { .collect() } +#[test] +fn test_ls_dired_offsets_after_empty_dir() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.mkdir("d"); + at.mkdir("d/empty"); + at.mkdir("d/hidden"); + at.touch("d/hidden/.dot"); + at.mkdir("d/zfull"); + at.touch("d/zfull/f"); + + // Directories listing no entry must still count their heading and "total" line. + let result = scene + .ucmd() + .args(&["--dired", "-l", "d/empty", "d/hidden", "d/zfull"]) + .succeeds(); + assert_eq!(dired_names(result.stdout_str()), ["f"]); + assert_eq!( + subdired_names(result.stdout_str()), + ["d/empty", "d/hidden", "d/zfull"] + ); + + let result = scene.ucmd().args(&["--dired", "-lR", "d"]).succeeds(); + assert_eq!( + dired_names(result.stdout_str()), + ["empty", "hidden", "zfull", "f"] + ); + assert_eq!( + subdired_names(result.stdout_str()), + ["d", "d/empty", "d/hidden", "d/zfull"] + ); +} + #[test] fn test_ls_dired_name_boundaries() { let scene = TestScenario::new(util_name!());