Skip to content

Commit eea061d

Browse files
authored
ls:fix ls dired reports (#10527)
* refactor: simplify DisplayItemName struct and improve dired position handling This commit refactors the `display_item_name` function to return a `DisplayItemName` struct containing both the displayed name and its dired length, rather than just the OsString. This change simplifies the code by: 1. Eliminating the need to call `dired_name_len()` separately after getting the displayed name 2. Reducing redundant length calculations in the dired position handling 3. Making the code more maintainable by encapsulating related data together The change also fixes an issue where dired positions were being calculated incorrectly for symlink names that required quoting, ensuring proper highlighting in dired mode. Closes: #10248
1 parent e4b3b5c commit eea061d

File tree

4 files changed

+206
-94
lines changed

4 files changed

+206
-94
lines changed

src/uu/ls/src/dired.rs

Lines changed: 43 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub struct DiredOutput {
5151
pub dired_positions: Vec<BytePosition>,
5252
pub subdired_positions: Vec<BytePosition>,
5353
pub padding: usize,
54+
pub line_offset: usize,
5455
}
5556

5657
impl fmt::Display for BytePosition {
@@ -62,21 +63,13 @@ impl fmt::Display for BytePosition {
6263
// When --dired is used, all lines starts with 2 spaces
6364
static DIRED_TRAILING_OFFSET: usize = 2;
6465

65-
fn get_offset_from_previous_line(dired_positions: &[BytePosition]) -> usize {
66-
if let Some(last_position) = dired_positions.last() {
67-
last_position.end + 1
68-
} else {
69-
0
70-
}
71-
}
72-
7366
/// Calculates the byte positions for DIRED
7467
pub fn calculate_dired(
75-
dired_positions: &[BytePosition],
68+
dired: &DiredOutput,
7669
output_display_len: usize,
7770
dfn_len: usize,
7871
) -> (usize, usize) {
79-
let offset_from_previous_line = get_offset_from_previous_line(dired_positions);
72+
let offset_from_previous_line = dired.line_offset;
8073

8174
let start = output_display_len + offset_from_previous_line;
8275
let end = start + dfn_len;
@@ -89,16 +82,8 @@ pub fn indent(out: &mut BufWriter<Stdout>) -> UResult<()> {
8982
}
9083

9184
pub fn calculate_subdired(dired: &mut DiredOutput, path_len: usize) {
92-
let offset_from_previous_line = get_offset_from_previous_line(&dired.dired_positions);
93-
94-
let additional_offset = if dired.subdired_positions.is_empty() {
95-
0
96-
} else {
97-
// if we have several directories: \n\n
98-
2
99-
};
100-
101-
let start = offset_from_previous_line + DIRED_TRAILING_OFFSET + additional_offset;
85+
let offset_from_previous_line = dired.line_offset + dired.padding;
86+
let start = offset_from_previous_line + DIRED_TRAILING_OFFSET;
10287
let end = start + path_len;
10388
dired.subdired_positions.push(BytePosition { start, end });
10489
}
@@ -113,7 +98,9 @@ pub fn print_dired_output(
11398
if !dired.dired_positions.is_empty() {
11499
print_positions("//DIRED//", &dired.dired_positions);
115100
}
116-
if config.recursive {
101+
// SUBDIRED is needed whenever directory headings are printed (multiple args or -R),
102+
// so don't gate it on config.recursive.
103+
if !dired.subdired_positions.is_empty() {
117104
print_positions("//SUBDIRED//", &dired.subdired_positions);
118105
}
119106
println!("//DIRED-OPTIONS// --quoting-style={}", config.quoting_style);
@@ -131,10 +118,9 @@ fn print_positions(prefix: &str, positions: &Vec<BytePosition>) {
131118

132119
pub fn add_total(dired: &mut DiredOutput, total_len: usize) {
133120
if dired.padding == 0 {
134-
let offset_from_previous_line = get_offset_from_previous_line(&dired.dired_positions);
135121
// when dealing with " total: xx", it isn't part of the //DIRED//
136122
// so, we just keep the size line to add it to the position of the next file
137-
dired.padding = total_len + offset_from_previous_line + DIRED_TRAILING_OFFSET;
123+
dired.padding = total_len + DIRED_TRAILING_OFFSET;
138124
} else {
139125
// += because if we are in -R, we have " dir:\n total X". So, we need to take the
140126
// previous padding too.
@@ -145,36 +131,32 @@ pub fn add_total(dired: &mut DiredOutput, total_len: usize) {
145131

146132
// when using -R, we have the dirname. we need to add it to the padding
147133
pub fn add_dir_name(dired: &mut DiredOutput, dir_len: usize) {
148-
// 1 for the ":" in " dirname:"
149-
dired.padding += dir_len + DIRED_TRAILING_OFFSET + 1;
134+
// " dirname:\n"
135+
dired.padding += dir_len + DIRED_TRAILING_OFFSET + 2;
150136
}
151137

152138
/// Calculates byte positions and updates the dired structure.
153139
pub fn calculate_and_update_positions(
154140
dired: &mut DiredOutput,
155141
output_display_len: usize,
156142
dfn_len: usize,
143+
line_len: usize,
157144
) {
158-
let offset = dired
159-
.dired_positions
160-
.last()
161-
.map_or(DIRED_TRAILING_OFFSET, |last_position| {
162-
last_position.start + DIRED_TRAILING_OFFSET
163-
});
164-
let start = output_display_len + offset + DIRED_TRAILING_OFFSET;
165-
let end = start + dfn_len;
166-
update_positions(dired, start, end);
145+
let (start, end) = calculate_dired(dired, output_display_len, dfn_len);
146+
update_positions(dired, start, end, line_len);
167147
}
168148

169149
/// Updates the dired positions based on the given start and end positions.
170150
/// update when it is the first element in the list (to manage "total X")
171151
/// insert when it isn't the about total
172-
pub fn update_positions(dired: &mut DiredOutput, start: usize, end: usize) {
152+
pub fn update_positions(dired: &mut DiredOutput, start: usize, end: usize, line_len: usize) {
173153
// padding can be 0 but as it doesn't matter
154+
let padding = dired.padding;
174155
dired.dired_positions.push(BytePosition {
175-
start: start + dired.padding,
176-
end: end + dired.padding,
156+
start: start + padding,
157+
end: end + padding,
177158
});
159+
dired.line_offset = dired.line_offset + padding + line_len;
178160
// Remove the previous padding
179161
dired.padding = 0;
180162
}
@@ -194,22 +176,18 @@ mod tests {
194176
fn test_calculate_dired() {
195177
let output_display = "sample_output".to_string();
196178
let dfn = "sample_file".to_string();
197-
let dired_positions = vec![BytePosition { start: 5, end: 10 }];
198-
let (start, end) = calculate_dired(&dired_positions, output_display.len(), dfn.len());
179+
let dired = DiredOutput {
180+
dired_positions: vec![BytePosition { start: 5, end: 10 }],
181+
subdired_positions: vec![],
182+
padding: 0,
183+
line_offset: 11,
184+
};
185+
let (start, end) = calculate_dired(&dired, output_display.len(), dfn.len());
199186

200187
assert_eq!(start, 24);
201188
assert_eq!(end, 35);
202189
}
203190

204-
#[test]
205-
fn test_get_offset_from_previous_line() {
206-
let positions = vec![
207-
BytePosition { start: 0, end: 3 },
208-
BytePosition { start: 4, end: 7 },
209-
BytePosition { start: 8, end: 11 },
210-
];
211-
assert_eq!(get_offset_from_previous_line(&positions), 12);
212-
}
213191
#[test]
214192
fn test_calculate_subdired() {
215193
let mut dired = DiredOutput {
@@ -220,6 +198,7 @@ mod tests {
220198
],
221199
subdired_positions: vec![],
222200
padding: 0,
201+
line_offset: 12,
223202
};
224203
let path_len = 5;
225204
calculate_subdired(&mut dired, path_len);
@@ -239,6 +218,7 @@ mod tests {
239218
],
240219
subdired_positions: vec![],
241220
padding: 0,
221+
line_offset: 0,
242222
};
243223
let dir_len = 5;
244224
add_dir_name(&mut dired, dir_len);
@@ -251,8 +231,9 @@ mod tests {
251231
BytePosition { start: 8, end: 11 },
252232
],
253233
subdired_positions: vec![],
254-
// 8 = 1 for the \n + 5 for dir_len + 2 for " " + 1 for :
255-
padding: 8
234+
// 9 = 5 for dir_len + 2 for " " + 1 for : + 1 for \n
235+
padding: 9,
236+
line_offset: 0,
256237
}
257238
);
258239
}
@@ -267,12 +248,13 @@ mod tests {
267248
],
268249
subdired_positions: vec![],
269250
padding: 0,
251+
line_offset: 12,
270252
};
271253
// if we have "total: 2"
272254
let total_len = 8;
273255
add_total(&mut dired, total_len);
274-
// 22 = 8 (len) + 2 (padding) + 11 (previous position) + 1 (\n)
275-
assert_eq!(dired.padding, 22);
256+
// 10 = 8 (len) + 2 (" ")
257+
assert_eq!(dired.padding, 10);
276258
}
277259

278260
#[test]
@@ -290,15 +272,16 @@ mod tests {
290272
],
291273
subdired_positions: vec![],
292274
padding: 0,
275+
line_offset: 12,
293276
};
294277
let dir_len = 5;
295278
add_dir_name(&mut dired, dir_len);
296-
// 8 = 2 (" ") + 1 (\n) + 5 + 1 (: of dirname)
297-
assert_eq!(dired.padding, 8);
279+
// 9 = 2 (" ") + 1 (\n) + 5 + 1 (: of dirname)
280+
assert_eq!(dired.padding, 9);
298281

299282
let total_len = 8;
300283
add_total(&mut dired, total_len);
301-
assert_eq!(dired.padding, 18);
284+
assert_eq!(dired.padding, 19);
302285
}
303286

304287
#[test]
@@ -307,16 +290,17 @@ mod tests {
307290
dired_positions: vec![BytePosition { start: 5, end: 10 }],
308291
subdired_positions: vec![],
309292
padding: 10,
293+
line_offset: 0,
310294
};
311295

312296
// Test with adjust = true
313-
update_positions(&mut dired, 15, 20);
297+
update_positions(&mut dired, 15, 20, 1);
314298
let last_position = dired.dired_positions.last().unwrap();
315299
assert_eq!(last_position.start, 25); // 15 + 10 (end of the previous position)
316300
assert_eq!(last_position.end, 30); // 20 + 10 (end of the previous position)
317301

318302
// Test with adjust = false
319-
update_positions(&mut dired, 30, 35);
303+
update_positions(&mut dired, 30, 35, 1);
320304
let last_position = dired.dired_positions.last().unwrap();
321305
assert_eq!(last_position.start, 30);
322306
assert_eq!(last_position.end, 35);
@@ -332,10 +316,11 @@ mod tests {
332316
],
333317
subdired_positions: vec![],
334318
padding: 5,
319+
line_offset: 12,
335320
};
336321
let output_display_len = 15;
337322
let dfn_len = 5;
338-
calculate_and_update_positions(&mut dired, output_display_len, dfn_len);
323+
calculate_and_update_positions(&mut dired, output_display_len, dfn_len, 20);
339324
assert_eq!(
340325
dired.dired_positions,
341326
vec![

0 commit comments

Comments
 (0)