Skip to content

Commit 382bd8c

Browse files
committed
fix: use real filesystem paths for leaf color detection with multiple args
When multiple paths are given, the synthetic "(total)" root was included in the filesystem path passed to file_color(), producing nonexistent paths like "(total)/link-dir". This caused all leaf nodes to be colored as Normal. Split build_coloring_map into two stacks: key_stack (for HashMap keys matching the visualizer's ancestor chain) and fs_path_stack (for actual filesystem type detection). For multi-arg invocations, the caller seeds key_stack with the "(total)" root name but starts fs_path_stack empty, so children resolve to real paths on disk. https://claude.ai/code/session_01YKNARZMxcXeYyGZhHMurHA
1 parent 17f5dbe commit 382bd8c

1 file changed

Lines changed: 28 additions & 10 deletions

File tree

src/app/sub.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,19 @@ where
200200

201201
let coloring: Option<Coloring> = color.map(|ls_colors| {
202202
let mut map = HashMap::new();
203-
build_coloring_map(&data_tree, &mut Vec::new(), &mut map);
203+
if only_one_arg {
204+
build_coloring_map(&data_tree, &mut Vec::new(), &mut Vec::new(), &mut map);
205+
} else {
206+
// For multi-arg invocations the root is the synthetic "(total)" node.
207+
// Include it in the map key (the visualizer's ancestor chain contains it)
208+
// but skip it in the filesystem path (it doesn't exist on disk).
209+
let root_name = data_tree.name().as_os_str();
210+
for child in data_tree.children() {
211+
let mut key_stack = vec![root_name];
212+
let mut fs_stack = Vec::new();
213+
build_coloring_map(child, &mut key_stack, &mut fs_stack, &mut map);
214+
}
215+
}
204216
Coloring::new(ls_colors, map)
205217
});
206218

@@ -282,27 +294,33 @@ where
282294

283295
/// Recursively walk a pruned [`DataTree`] and build a map of path-component vectors to [`Color`] values.
284296
///
285-
/// The `path_stack` argument is a reusable buffer of path components representing the current
286-
/// ancestor chain. Each recursive call pushes the node's name and pops it on return, so no
287-
/// cloning occurs during traversal — only at leaf insertions.
297+
/// `key_stack` tracks the ancestor chain used as the HashMap key (must match what the
298+
/// [`Visualizer`] constructs). `fs_path_stack` tracks the real filesystem path used for
299+
/// file-type detection. These two stacks diverge when the root is a synthetic node like
300+
/// `(total)` that has no corresponding directory on disk.
301+
///
288302
/// Leaf nodes (files or childless directories after pruning) are added to the map.
289303
/// Nodes with children are skipped because the [`Visualizer`] uses the children count to
290304
/// determine their color at render time.
291305
fn build_coloring_map<'a>(
292306
node: &'a DataTree<OsStringDisplay, impl size::Size>,
293-
path_stack: &mut Vec<&'a OsStr>,
307+
key_stack: &mut Vec<&'a OsStr>,
308+
fs_path_stack: &mut Vec<&'a OsStr>,
294309
map: &mut HashMap<Vec<&'a OsStr>, Color>,
295310
) {
296-
path_stack.push(node.name().as_os_str());
311+
let name = node.name().as_os_str();
312+
key_stack.push(name);
313+
fs_path_stack.push(name);
297314
if node.children().is_empty() {
298-
let color = file_color(&path_stack.iter().collect::<PathBuf>());
299-
map.insert(path_stack.clone(), color);
315+
let color = file_color(&fs_path_stack.iter().collect::<PathBuf>());
316+
map.insert(key_stack.clone(), color);
300317
} else {
301318
for child in node.children() {
302-
build_coloring_map(child, path_stack, map);
319+
build_coloring_map(child, key_stack, fs_path_stack, map);
303320
}
304321
}
305-
path_stack.pop();
322+
key_stack.pop();
323+
fs_path_stack.pop();
306324
}
307325

308326
fn file_color(path: &Path) -> Color {

0 commit comments

Comments
 (0)