Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ls: fix issue #6697 (different "ls -lF --dired" from GNU) #6699

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 202 additions & 43 deletions src/uu/ls/src/dired.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ use uucore::error::UResult;
#[derive(Debug, Clone, PartialEq)]
pub struct BytePosition {
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not a big deal because --dired isn't used a lot but we are storing extra data every time even this case happens rarely

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this solution might be a bit silly, but I'm not good at programming.

It seems like 'end_line' is only used to calculate the offset for the next line, so it should be fine to just store 'end_filename' maybe.

I'll try to optimize it. :)

pub start: usize,
// this is end of line
pub end: usize,
pub end_filename: usize,
}

/// Represents the output structure for DIRED, containing positions for both DIRED and SUBDIRED.
Expand All @@ -55,7 +57,7 @@ pub struct DiredOutput {

impl fmt::Display for BytePosition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.start, self.end)
write!(f, "{} {}", self.start, self.end_filename)
}
}

Expand All @@ -74,13 +76,15 @@ fn get_offset_from_previous_line(dired_positions: &[BytePosition]) -> usize {
pub fn calculate_dired(
dired_positions: &[BytePosition],
output_display_len: usize,
dfn_len: usize,
) -> (usize, usize) {
end_line_len: usize,
end_filename_len: usize,
) -> (usize, usize, usize) {
let offset_from_previous_line = get_offset_from_previous_line(dired_positions);

let start = output_display_len + offset_from_previous_line;
let end = start + dfn_len;
(start, end)
let end = start + end_line_len;
let end_filename = start + end_filename_len;
(start, end, end_filename)
}

pub fn indent(out: &mut BufWriter<Stdout>) -> UResult<()> {
Expand All @@ -100,7 +104,11 @@ pub fn calculate_subdired(dired: &mut DiredOutput, path_len: usize) {

let start = offset_from_previous_line + DIRED_TRAILING_OFFSET + additional_offset;
let end = start + path_len;
dired.subdired_positions.push(BytePosition { start, end });
dired.subdired_positions.push(BytePosition {
start,
end,
end_filename: end,
});
}

/// Prints the dired output based on the given configuration and dired structure.
Expand Down Expand Up @@ -153,7 +161,8 @@ pub fn add_dir_name(dired: &mut DiredOutput, dir_len: usize) {
pub fn calculate_and_update_positions(
dired: &mut DiredOutput,
output_display_len: usize,
dfn_len: usize,
end_line_len: usize,
end_filename_len: usize,
) {
let offset = dired
.dired_positions
Expand All @@ -162,17 +171,19 @@ pub fn calculate_and_update_positions(
last_position.start + DIRED_TRAILING_OFFSET
});
let start = output_display_len + offset + DIRED_TRAILING_OFFSET;
let end = start + dfn_len;
update_positions(dired, start, end);
let end = start + end_line_len;
let end_filename = start + end_filename_len;
update_positions(dired, start, end, end_filename);
}

/// Updates the dired positions based on the given start and end 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(dired: &mut DiredOutput, start: usize, end: usize) {
pub fn update_positions(dired: &mut DiredOutput, start: usize, end: usize, end_filename: usize) {
// padding can be 0 but as it doesn't matter
dired.dired_positions.push(BytePosition {
start: start + dired.padding,
end_filename: end_filename + dired.padding,
end: end + dired.padding,
});
// Remove the previous padding
Expand All @@ -195,29 +206,87 @@ mod tests {
fn test_calculate_dired() {
Copy link
Sponsor Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a new tests which shows when end and end_filename are different ?

let output_display = "sample_output".to_string();
let dfn = "sample_file".to_string();
let dired_positions = vec![BytePosition { start: 5, end: 10 }];
let (start, end) = calculate_dired(&dired_positions, output_display.len(), dfn.len());
let dired_positions = vec![BytePosition {
start: 5,
end: 10,
end_filename: 10,
}];
let (start, end, end_filename) =
calculate_dired(&dired_positions, output_display.len(), dfn.len(), dfn.len());

assert_eq!(start, 24);
assert_eq!(end, 35);
assert_eq!(end_filename, 35);
}

#[test]
fn test_calculate_dired_end_line_diff_end_filename() {
// test when we have
// ls -lF

// total 0
// lrwxrwxrwx 1 somebody somegroup 0 Sep 15 22:29 aaa@ -> d:\test\dir\aaa
// drwxrwxrwx 1 somebody somegroup 0 Sep 15 22:29 dir/
let output_display = "sample_output".to_string();
let end_line = "aaa@ -> d:\\test\\dir\\aaa".to_string();
let end_filename = "aaa".to_string();
let dired_positions = vec![BytePosition {
start: 5,
end: 10,
end_filename: 10,
}];
let (start, end, end_filename) = calculate_dired(
&dired_positions,
output_display.len(),
end_line.len(),
end_filename.len(),
);

assert_eq!(start, 24);
assert_eq!(end, 47);
assert_eq!(end_filename, 27);
}

#[test]
fn test_get_offset_from_previous_line() {
let positions = vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
BytePosition {
start: 0,
end: 3,
end_filename: 3,
},
BytePosition {
start: 4,
end: 7,
end_filename: 7,
},
BytePosition {
start: 8,
end: 11,
end_filename: 11,
},
];
assert_eq!(get_offset_from_previous_line(&positions), 12);
}
#[test]
fn test_calculate_subdired() {
let mut dired = DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
BytePosition {
start: 0,
end: 3,
end_filename: 3,
},
BytePosition {
start: 4,
end: 7,
end_filename: 7,
},
BytePosition {
start: 8,
end: 11,
end_filename: 11,
},
],
subdired_positions: vec![],
padding: 0,
Expand All @@ -226,17 +295,33 @@ mod tests {
calculate_subdired(&mut dired, path_len);
assert_eq!(
dired.subdired_positions,
vec![BytePosition { start: 14, end: 19 }],
vec![BytePosition {
start: 14,
end: 19,
end_filename: 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 },
BytePosition {
start: 0,
end: 3,
end_filename: 3,
},
BytePosition {
start: 4,
end: 7,
end_filename: 7,
},
BytePosition {
start: 8,
end: 11,
end_filename: 11,
},
],
subdired_positions: vec![],
padding: 0,
Expand All @@ -247,9 +332,21 @@ mod tests {
dired,
DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
BytePosition {
start: 0,
end: 3,
end_filename: 3
},
BytePosition {
start: 4,
end: 7,
end_filename: 7
},
BytePosition {
start: 8,
end: 11,
end_filename: 11
},
],
subdired_positions: vec![],
// 8 = 1 for the \n + 5 for dir_len + 2 for " " + 1 for :
Expand All @@ -262,9 +359,21 @@ mod tests {
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 },
BytePosition {
start: 0,
end: 3,
end_filename: 3,
},
BytePosition {
start: 4,
end: 7,
end_filename: 7,
},
BytePosition {
start: 8,
end: 11,
end_filename: 11,
},
],
subdired_positions: vec![],
padding: 0,
Expand All @@ -285,9 +394,21 @@ mod tests {

let mut dired = DiredOutput {
dired_positions: vec![
BytePosition { start: 0, end: 3 },
BytePosition { start: 4, end: 7 },
BytePosition { start: 8, end: 11 },
BytePosition {
start: 0,
end: 3,
end_filename: 3,
},
BytePosition {
start: 4,
end: 7,
end_filename: 7,
},
BytePosition {
start: 8,
end: 11,
end_filename: 11,
},
],
subdired_positions: vec![],
padding: 0,
Expand All @@ -305,19 +426,23 @@ mod tests {
#[test]
fn test_dired_update_positions() {
let mut dired = DiredOutput {
dired_positions: vec![BytePosition { start: 5, end: 10 }],
dired_positions: vec![BytePosition {
start: 5,
end: 10,
end_filename: 10,
}],
subdired_positions: vec![],
padding: 10,
};

// Test with adjust = true
update_positions(&mut dired, 15, 20);
update_positions(&mut dired, 15, 20, 20);
let last_position = dired.dired_positions.last().unwrap();
assert_eq!(last_position.start, 25); // 15 + 10 (end of the previous position)
assert_eq!(last_position.end, 30); // 20 + 10 (end of the previous position)

// Test with adjust = false
update_positions(&mut dired, 30, 35);
update_positions(&mut dired, 30, 35, 35);
let last_position = dired.dired_positions.last().unwrap();
assert_eq!(last_position.start, 30);
assert_eq!(last_position.end, 35);
Expand All @@ -327,23 +452,57 @@ mod tests {
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 },
BytePosition {
start: 0,
end: 3,
end_filename: 3,
},
BytePosition {
start: 4,
end: 7,
end_filename: 7,
},
BytePosition {
start: 8,
end: 11,
end_filename: 11,
},
],
subdired_positions: vec![],
padding: 5,
};
let output_display_len = 15;
let dfn_len = 5;
calculate_and_update_positions(&mut dired, output_display_len, dfn_len);
let end_line_len = 5;
let end_filename_len = 5;
calculate_and_update_positions(
&mut dired,
output_display_len,
end_line_len,
end_filename_len,
);
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 },
BytePosition {
start: 0,
end: 3,
end_filename: 3
},
BytePosition {
start: 4,
end: 7,
end_filename: 7
},
BytePosition {
start: 8,
end: 11,
end_filename: 11
},
BytePosition {
start: 32,
end: 37,
end_filename: 37
},
]
);
assert_eq!(dired.padding, 0);
Expand Down
Loading
Loading