Skip to content

Commit

Permalink
ls --dired -R: fix the positions
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvestre committed Oct 1, 2023
1 parent a165ac2 commit 680f31c
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 9 deletions.
125 changes: 119 additions & 6 deletions src/uu/ls/src/dired.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct BytePosition {
}

/// Represents the output structure for DIRED, containing positions for both DIRED and SUBDIRED.
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, PartialEq)]
pub struct DiredOutput {
pub dired_positions: Vec<BytePosition>,
pub subdired_positions: Vec<BytePosition>,
Expand Down Expand Up @@ -76,7 +76,7 @@ pub fn print_dired_output(
) -> UResult<()> {
out.flush()?;
// TODO manage when -R and the last doesn't have file
if dired.padding == 0 && dired.dired_positions.len() >= 1 {
if dired.padding == 0 && !dired.dired_positions.is_empty() {
print_positions("//DIRED//", &dired.dired_positions);
}
if config.recursive {
Expand All @@ -96,9 +96,23 @@ fn print_positions(prefix: &str, positions: &Vec<BytePosition>) {
}

pub fn add_total(total_len: usize, dired: &mut DiredOutput) {
// when dealing with " total: xx", it isn't part of the //DIRED//
// so, we just keep the size line to add it to the position of the next file
dired.padding = total_len + DIRED_TRAILING_OFFSET;
if dired.padding == 0 {
let offset_from_previous_line = get_offset_from_previous_line(&dired.dired_positions);
// when dealing with " total: xx", it isn't part of the //DIRED//
// so, we just keep the size line to add it to the position of the next file
dired.padding = total_len + offset_from_previous_line + DIRED_TRAILING_OFFSET;
} else {
// += because if we are in -R, we have " dir:\n total X". So, we need to take the
// previous padding too.
// and we already have the previous position in mind
dired.padding += total_len + DIRED_TRAILING_OFFSET;
}
}

// when using -R, we have the dirname. we need to add it to the padding
pub fn add_dir_name(dir_len: usize, dired: &mut DiredOutput) {
// 1 for the ":" in " dirname:"
dired.padding += dir_len + DIRED_TRAILING_OFFSET + 1;
}

/// Calculates byte positions and updates the dired structure.
Expand All @@ -122,7 +136,7 @@ pub fn calculate_and_update_positions(
/// update when it is the first element in the list (to manage "total X")
/// insert when it isn't the about total
pub fn update_positions(start: usize, end: usize, dired: &mut DiredOutput) {
// padding can be 0 but as it doesn't matter<
// padding can be 0 but as it doesn't matter
dired.dired_positions.push(BytePosition {
start: start + dired.padding,
end: end + dired.padding,
Expand Down Expand Up @@ -173,6 +187,79 @@ mod tests {
vec![BytePosition { start: 14, end: 19 }],
);
}

#[test]
fn test_add_dir_name() {
let mut dired = DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
],
subdired_positions: vec![],
padding: 0,
};
let dir_len = 5;
add_dir_name(dir_len, &mut dired);
assert_eq!(
dired,
DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
],
subdired_positions: vec![],
// 8 = 1 for the \n + 5 for dir_len + 2 for " " + 1 for :
padding: 8
}
);
}

#[test]
fn test_add_total() {
let mut dired = DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
],
subdired_positions: vec![],
padding: 0,
};
// if we have "total: 2"
let total_len = 8;
add_total(total_len, &mut dired);
// 22 = 8 (len) + 2 (padding) + 11 (previous position) + 1 (\n)
assert_eq!(dired.padding, 22);
}

#[test]
fn test_add_dir_name_and_total() {
// test when we have
// dirname:
// total 0
// -rw-r--r-- 1 sylvestre sylvestre 0 Sep 30 09:41 ab

let mut dired = DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
],
subdired_positions: vec![],
padding: 0,
};
let dir_len = 5;
add_dir_name(dir_len, &mut dired);
// 8 = 2 (" ") + 1 (\n) + 5 + 1 (: of dirname)
assert_eq!(dired.padding, 8);

let total_len = 8;
add_total(total_len, &mut dired);
assert_eq!(dired.padding, 18);
}

#[test]
fn test_dired_update_positions() {
let mut dired = DiredOutput {
Expand All @@ -193,4 +280,30 @@ mod tests {
assert_eq!(last_position.start, 30);
assert_eq!(last_position.end, 35);
}

#[test]
fn test_calculate_and_update_positions() {
let mut dired = DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
],
subdired_positions: vec![],
padding: 5,
};
let output_display_len = 15;
let dfn_len = 5;
calculate_and_update_positions(output_display_len, dfn_len, &mut dired);
assert_eq!(
dired.dired_positions,
vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
BytePosition { start: 32, end: 37 },
]
);
assert_eq!(dired.padding, 0);
}
}
33 changes: 30 additions & 3 deletions src/uu/ls/src/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,10 @@ impl PathData {
}
}

fn show_dir_name(dir: &Path, out: &mut BufWriter<Stdout>) {
write!(out, "{}:", dir.display()).unwrap();
}

pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
let mut files = Vec::<PathData>::new();
let mut dirs = Vec::<PathData>::new();
Expand Down Expand Up @@ -1921,10 +1925,17 @@ pub fn list(locs: Vec<&Path>, config: &Config) -> UResult<()> {
}
writeln!(out, "{}:", path_data.p_buf.display())?;
if config.dired {
dired::calculate_subdired(&mut dired, path_data.display_name.len());
// Fist directory displayed
let dir_len = path_data.display_name.len();
// add the //SUBDIRED// coordinates
dired::calculate_subdired(&mut dired, dir_len);
// Add the padding for the dir name
dired::add_dir_name(dir_len, &mut dired);
}
} else {
writeln!(out, "\n{}:", path_data.p_buf.display())?;
writeln!(out).unwrap();
show_dir_name(&path_data.p_buf, &mut out);
writeln!(out).unwrap();
}
}
let mut listed_ancestors = HashSet::new();
Expand Down Expand Up @@ -2131,7 +2142,23 @@ fn enter_directory(
if listed_ancestors
.insert(FileInformation::from_path(&e.p_buf, e.must_dereference)?)
{
writeln!(out, "\n{}:", e.p_buf.display())?;
// when listing several directories in recursive mode, we show
// "dirname:" at the beginning of the file list
writeln!(out)?;
if config.dired {
// We already injected the first dir
// Continue with the others
// 4= \n + \n " "
dired.padding = 4;
dired::indent(out)?;
let dir_name_size = e.display_name.len();
dired::calculate_subdired(dired, dir_name_size);
// inject dir name
dired::add_dir_name(dir_name_size, dired);
}

show_dir_name(&e.p_buf, out);
writeln!(out)?;
enter_directory(e, rd, config, out, listed_ancestors, dired)?;
listed_ancestors
.remove(&FileInformation::from_path(&e.p_buf, e.must_dereference)?);
Expand Down
58 changes: 58 additions & 0 deletions tests/by-util/test_ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3551,6 +3551,64 @@ fn test_ls_dired_recursive() {
.stdout_contains("//DIRED-OPTIONS// --quoting-style");
}

#[test]
fn test_ls_dired_recursive_multiple() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;

at.mkdir("d");
at.mkdir("d/d1");
at.mkdir("d/d2");
at.touch("d/d2/a");
at.touch("d/d2/c2");
at.touch("d/d1/f1");
let mut cmd = scene.ucmd();

cmd.arg("--dired").arg("-l").arg("-R").arg("d");

let result = cmd.succeeds();

let output = result.stdout_str().to_string();
println!("Output:\n{}", output);
// TODO: Il manque le offset du direname
let dired_line = output
.lines()
.find(|&line| line.starts_with("//DIRED//"))
.unwrap();
let positions: Vec<usize> = dired_line
.split_whitespace()
.skip(1)
.map(|s| s.parse().unwrap())
.collect();
println!("{:?}", positions);
println!("Parsed byte positions: {:?}", positions);
assert_eq!(positions.len() % 2, 0); // Ensure there's an even number of positions

let filenames: Vec<String> = positions
.chunks(2)
.map(|chunk| {
let start_pos = chunk[0];
let end_pos = chunk[1];
let filename = String::from_utf8(output.as_bytes()[start_pos..=end_pos].to_vec())
.unwrap()
.trim()
.to_string();
println!("Extracted filename: {}", filename);
filename
})
.collect();

println!("Extracted filenames: {:?}", filenames);
assert_eq!(filenames, vec!["d1", "d2", "f1", "a", "c2"]);

/* .stdout_contains(" d/d1:")
.stdout_contains(" d/d2:")
.stdout_contains(" total 0")
.stdout_contains("//DIRED//")
.stdout_contains("//SUBDIRED// 2 3")
.stdout_contains("//DIRED-OPTIONS// --quoting-style");*/
}

#[test]
fn test_ls_dired_simple() {
let scene = TestScenario::new(util_name!());
Expand Down

0 comments on commit 680f31c

Please sign in to comment.