Skip to content

Commit 8bd5db2

Browse files
SAY-5RaphGL
andauthored
fixed #146: stopped panicking on multi-byte chars in config paths
* fix: avoid panic on multi-byte chars in config group names to_target_path sliced the path component at byte index 1, which panics when the first character is multi-byte (e.g. a folder named Übersicht). Iterate chars instead of slicing bytes. * fixed unit test for unicode in dotfile paths --------- Co-authored-by: RaphGL <raphfl.dev@gmail.com>
1 parent 3526272 commit 8bd5db2

1 file changed

Lines changed: 52 additions & 9 deletions

File tree

src/dotfiles.rs

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,15 @@ impl Dotfile {
275275
while let Some(comp) = group_path_components.next() {
276276
let comp = comp.as_os_str().to_str().unwrap();
277277

278-
if comp.len() < 2 {
278+
let mut comp_chars = comp.chars();
279+
let Some(prefix) = comp_chars.next() else {
279280
continue;
280-
}
281+
};
282+
let comp = comp_chars.as_str();
281283

282-
let prefix = comp.chars().next().unwrap();
283-
let comp = &comp[1..];
284+
if comp.is_empty() {
285+
continue;
286+
}
284287

285288
if prefix == '%' {
286289
let Ok(comp) = env::var(comp) else {
@@ -345,7 +348,9 @@ pub fn get_potential_dotfiles_paths(profile: Option<String>) -> PotentialDotfile
345348
PotentialDotfilePaths {
346349
home: dirs::home_dir().unwrap().join(format!(".{dotfiles_dir}")),
347350
config: dirs::config_dir().unwrap().join(&dotfiles_dir),
348-
env: std::env::var("TUCKR_HOME").map(|p| PathBuf::from(p).join(dotfiles_dir)).ok(),
351+
env: std::env::var("TUCKR_HOME")
352+
.map(|p| PathBuf::from(p).join(dotfiles_dir))
353+
.ok(),
349354
test: std::env::temp_dir()
350355
.join(format!(
351356
"tuckr-{}",
@@ -564,6 +569,27 @@ mod tests {
564569
);
565570
}
566571

572+
#[test]
573+
fn dotfile_to_target_path_non_ascii_name() {
574+
let stem = std::path::PathBuf::new()
575+
.join(".config")
576+
.join("übersicht")
577+
.join("widgets")
578+
.join("道具");
579+
580+
// Names with multi-byte characters must not panic on byte slicing.
581+
let group = get_dotfiles_path(None)
582+
.unwrap()
583+
.join("Configs")
584+
.join("übersicht")
585+
.join(&stem);
586+
587+
assert_eq!(
588+
Dotfile::try_from(group).unwrap().to_target_path().unwrap(),
589+
super::get_dotfiles_target_dir_path().unwrap().join(stem)
590+
);
591+
}
592+
567593
#[test]
568594
fn dotfile_targets_root() {
569595
let dotfiles_dir = super::get_dotfiles_path(None).unwrap().join("Configs");
@@ -672,9 +698,26 @@ mod tests {
672698
};
673699

674700
let potential_paths = super::get_potential_dotfiles_paths(Some("whatever".into()));
675-
assert_eq!(potential_paths.config.file_name().unwrap(), "dotfiles_whatever");
676-
assert_eq!(potential_paths.home.file_name().unwrap(), ".dotfiles_whatever");
677-
assert_eq!(potential_paths.env.unwrap().file_name().unwrap(), "dotfiles_whatever");
678-
assert!(potential_paths.test.file_name().unwrap().to_str().unwrap().starts_with("dotfiles"));
701+
assert_eq!(
702+
potential_paths.config.file_name().unwrap(),
703+
"dotfiles_whatever"
704+
);
705+
assert_eq!(
706+
potential_paths.home.file_name().unwrap(),
707+
".dotfiles_whatever"
708+
);
709+
assert_eq!(
710+
potential_paths.env.unwrap().file_name().unwrap(),
711+
"dotfiles_whatever"
712+
);
713+
assert!(
714+
potential_paths
715+
.test
716+
.file_name()
717+
.unwrap()
718+
.to_str()
719+
.unwrap()
720+
.starts_with("dotfiles")
721+
);
679722
}
680723
}

0 commit comments

Comments
 (0)