Skip to content

Commit 6c4da4c

Browse files
CopilotKSXGitHub
andcommitted
refactor: use Vec<OsString> as coloring map keys instead of PathBuf
Co-authored-by: KSXGitHub <11488886+KSXGitHub@users.noreply.github.com>
1 parent 5eb9190 commit 6c4da4c

4 files changed

Lines changed: 84 additions & 32 deletions

File tree

src/app/sub.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use pipe_trait::Pipe;
1717
use serde::Serialize;
1818
use std::{
1919
collections::HashMap,
20+
ffi::OsString,
2021
io::stdout,
2122
iter::once,
2223
path::{Path, PathBuf},
@@ -199,7 +200,7 @@ where
199200

200201
let coloring: Option<Coloring> = color.map(|ls_colors| {
201202
let mut map = HashMap::new();
202-
build_coloring_map(&data_tree, PathBuf::new(), &mut map);
203+
build_coloring_map(&data_tree, &mut Vec::new(), &mut map);
203204
Coloring::new(ls_colors, map)
204205
});
205206

@@ -279,26 +280,29 @@ where
279280
}
280281
}
281282

282-
/// Recursively walk a pruned [`DataTree`] and build a map of full paths to [`Color`] values.
283+
/// Recursively walk a pruned [`DataTree`] and build a map of path-component vectors to [`Color`] values.
283284
///
284-
/// The `path` argument should be the current path prefix for reconstructing full filesystem paths.
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.
285288
/// Leaf nodes (files or childless directories after pruning) are added to the map.
286289
/// Nodes with children are skipped because the [`Visualizer`] uses the children count to
287290
/// determine their color at render time.
288291
fn build_coloring_map(
289292
node: &DataTree<OsStringDisplay, impl size::Size>,
290-
path: PathBuf,
291-
map: &mut HashMap<PathBuf, Color>,
293+
path_stack: &mut Vec<OsString>,
294+
map: &mut HashMap<Vec<OsString>, Color>,
292295
) {
293-
let node_path = path.join(node.name().as_os_str());
294-
if !node.children().is_empty() {
296+
path_stack.push(node.name().as_os_str().to_os_string());
297+
if node.children().is_empty() {
298+
let color = file_color(&path_stack.iter().collect::<PathBuf>());
299+
map.insert(path_stack.clone(), color);
300+
} else {
295301
for child in node.children() {
296-
build_coloring_map(child, node_path.clone(), map);
302+
build_coloring_map(child, path_stack, map);
297303
}
298-
return;
299304
}
300-
let color = file_color(&node_path);
301-
map.insert(node_path, color);
305+
path_stack.pop();
302306
}
303307

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

src/visualizer/coloring.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,34 @@ use crate::ls_colors::LsColors;
33
use derive_more::Display;
44
use std::{
55
collections::HashMap,
6+
ffi::OsString,
67
fmt,
7-
path::{Path, PathBuf},
88
};
99
use zero_copy_pads::Width;
1010

1111
/// Coloring configuration: ANSI prefix strings from the environment and a full-path-to-color map.
1212
#[derive(Debug)]
1313
pub struct Coloring {
1414
ls_colors: LsColors,
15-
map: HashMap<PathBuf, Color>,
15+
map: HashMap<Vec<OsString>, Color>,
1616
}
1717

1818
impl Coloring {
19-
/// Create a new [`Coloring`] from LS_COLORS prefixes and a full-path-to-color map.
20-
pub fn new(ls_colors: LsColors, map: HashMap<PathBuf, Color>) -> Self {
19+
/// Create a new [`Coloring`] from LS_COLORS prefixes and a path-components-to-color map.
20+
pub fn new(ls_colors: LsColors, map: HashMap<Vec<OsString>, Color>) -> Self {
2121
Coloring { ls_colors, map }
2222
}
2323

2424
/// Return `(color, ls_colors)` for a node, used to build a colored slice for rendering.
25-
pub(super) fn node_color(&self, path: &Path, has_children: bool) -> Option<(Color, &LsColors)> {
25+
pub(super) fn node_color(
26+
&self,
27+
path_components: &[OsString],
28+
has_children: bool,
29+
) -> Option<(Color, &LsColors)> {
2630
let color = if has_children {
2731
Some(Color::Directory)
2832
} else {
29-
self.map.get(path).copied()
33+
self.map.get(path_components).copied()
3034
}?;
3135
Some((color, &self.ls_colors))
3236
}

src/visualizer/methods.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use tree_table::*;
1414

1515
use super::{coloring::ColoredTreeHorizontalSlice, ColumnWidthDistribution, Visualizer};
1616
use crate::size;
17-
use std::{cmp::min, ffi::OsStr, fmt::Display, path::PathBuf};
17+
use std::{cmp::min, ffi::{OsStr, OsString}, fmt::Display};
1818
use zero_copy_pads::{align_left, align_right};
1919

2020
impl<'a, Name, Size> Visualizer<'a, Name, Size>
@@ -92,15 +92,15 @@ where
9292
} = tree_row;
9393

9494
let colored = self.coloring.and_then(|coloring| {
95-
let path: PathBuf = initial_row
95+
let path_components: Vec<OsString> = initial_row
9696
.ancestors
9797
.iter()
98-
.map(|a| a.name.as_ref() as &OsStr)
98+
.map(|a| a.name.as_ref().to_os_string())
9999
.chain(std::iter::once(
100-
initial_row.node_info.name.as_ref() as &OsStr
100+
initial_row.node_info.name.as_ref().to_os_string(),
101101
))
102102
.collect();
103-
coloring.node_color(&path, initial_row.node_info.children_count > 0)
103+
coloring.node_color(&path_components, initial_row.node_info.children_count > 0)
104104
});
105105

106106
let aligned_colored_slice;

tests/usual_cli.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use parallel_disk_usage::{
2727
visualizer::{Color, Coloring},
2828
};
2929
#[cfg(unix)]
30-
use std::{collections::HashMap, path::PathBuf};
30+
use std::{collections::HashMap, ffi::OsString};
3131

3232
#[cfg(unix)]
3333
use parallel_disk_usage::get_size::{GetBlockCount, GetBlockSize};
@@ -932,15 +932,59 @@ fn color_always() {
932932

933933
let ls_colors = LsColors::from_ls_colors_string(LS_COLORS);
934934
let map = HashMap::from([
935-
(PathBuf::from("./dir-a/file-a1.txt"), Color::Normal),
936-
(PathBuf::from("./dir-a/file-a2.txt"), Color::Normal),
937-
(PathBuf::from("./dir-a/subdir-a/file-a3.txt"), Color::Normal),
938-
(PathBuf::from("./dir-b/file-b1.txt"), Color::Normal),
939-
(PathBuf::from("./file-root.txt"), Color::Normal),
940-
(PathBuf::from("./link-dir"), Color::Symlink),
941-
(PathBuf::from("./link-file.txt"), Color::Symlink),
942-
(PathBuf::from("./empty-dir-1"), Color::Directory),
943-
(PathBuf::from("./empty-dir-2"), Color::Directory),
935+
(
936+
vec![
937+
OsString::from("."),
938+
OsString::from("dir-a"),
939+
OsString::from("file-a1.txt"),
940+
],
941+
Color::Normal,
942+
),
943+
(
944+
vec![
945+
OsString::from("."),
946+
OsString::from("dir-a"),
947+
OsString::from("file-a2.txt"),
948+
],
949+
Color::Normal,
950+
),
951+
(
952+
vec![
953+
OsString::from("."),
954+
OsString::from("dir-a"),
955+
OsString::from("subdir-a"),
956+
OsString::from("file-a3.txt"),
957+
],
958+
Color::Normal,
959+
),
960+
(
961+
vec![
962+
OsString::from("."),
963+
OsString::from("dir-b"),
964+
OsString::from("file-b1.txt"),
965+
],
966+
Color::Normal,
967+
),
968+
(
969+
vec![OsString::from("."), OsString::from("file-root.txt")],
970+
Color::Normal,
971+
),
972+
(
973+
vec![OsString::from("."), OsString::from("link-dir")],
974+
Color::Symlink,
975+
),
976+
(
977+
vec![OsString::from("."), OsString::from("link-file.txt")],
978+
Color::Symlink,
979+
),
980+
(
981+
vec![OsString::from("."), OsString::from("empty-dir-1")],
982+
Color::Directory,
983+
),
984+
(
985+
vec![OsString::from("."), OsString::from("empty-dir-2")],
986+
Color::Directory,
987+
),
944988
]);
945989
let coloring = Coloring::new(ls_colors, map);
946990

0 commit comments

Comments
 (0)