Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cc05c03

Browse files
committedJun 11, 2024
Normalize drive letters when resolving paths on Windows
When it comes to resolving paths on Windows, even though the underlying API expects drive letter prefixes to be uppercase, some sources (e.g. environment variables like `=C:`) won't normalize components, instead returning the value as-is. While this wouldn't be a problem normally as NTFS is case-insensitive on Windows, this introduces duplicates in the database when adding new entries via `zoxide add`: ```batchfile prompt > zoxide query --list D:\ d:\ D:\coding d:\coding D:\coding\.cloned d:\coding\.cloned ``` This is a cherry-pick from ajeetdsouza#567; see also rust-lang/rust-analyzer#14683. Signed-off-by: mataha <[email protected]>
1 parent dbe6f18 commit cc05c03

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- zsh: better cd completions.
1919
- elvish: `z -` now work as expected.
2020
- Lazily delete excluded directories from the database.
21+
- Normalize drive letters when resolving paths on Windows.
2122

2223
## [0.9.4] - 2024-02-21
2324

‎src/util.rs

+39-10
Original file line numberDiff line numberDiff line change
@@ -292,43 +292,72 @@ pub fn resolve_path(path: impl AsRef<Path>) -> Result<PathBuf> {
292292
}
293293

294294
fn get_drive_path(drive_letter: u8) -> PathBuf {
295-
format!(r"{}:\", drive_letter as char).into()
295+
format!(r"{}:\", drive_letter.to_ascii_uppercase() as char).into()
296296
}
297297

298298
fn get_drive_relative(drive_letter: u8) -> Result<PathBuf> {
299299
let path = current_dir()?;
300300
if Some(drive_letter) == get_drive_letter(&path) {
301-
return Ok(path);
301+
return Ok(patch_drive_prefix(path));
302302
}
303303

304-
if let Some(path) = env::var_os(format!("={}:", drive_letter as char)) {
305-
return Ok(path.into());
304+
if let Some(path) =
305+
env::var_os(format!("={}:", drive_letter.to_ascii_uppercase() as char))
306+
{
307+
return Ok(patch_drive_prefix(path.into()));
306308
}
307309

308310
let path = get_drive_path(drive_letter);
309311
Ok(path)
310312
}
311313

314+
// https://github.com/rust-lang/rust-analyzer/pull/14689
315+
fn patch_drive_prefix(path: PathBuf) -> PathBuf {
316+
let mut components = path.components();
317+
318+
match components.next() {
319+
Some(Component::Prefix(prefix)) => {
320+
let prefix = match prefix.kind() {
321+
Prefix::Disk(drive_letter) => {
322+
format!(r"{}:", drive_letter.to_ascii_uppercase() as char)
323+
}
324+
Prefix::VerbatimDisk(drive_letter) => {
325+
format!(r"\\?\{}:", drive_letter.to_ascii_uppercase() as char)
326+
}
327+
_ => return path,
328+
};
329+
330+
let mut path = PathBuf::default();
331+
path.push(prefix);
332+
path.extend(components);
333+
path
334+
}
335+
_ => path,
336+
}
337+
}
338+
312339
match components.peek() {
313340
Some(Component::Prefix(prefix)) => match prefix.kind() {
314341
Prefix::Disk(drive_letter) => {
315-
let disk = components.next().unwrap();
342+
components.next();
316343
if components.peek() == Some(&Component::RootDir) {
317-
let root = components.next().unwrap();
318-
stack.push(disk);
319-
stack.push(root);
344+
components.next();
345+
base_path = get_drive_path(drive_letter);
320346
} else {
321347
base_path = get_drive_relative(drive_letter)?;
322-
stack.extend(base_path.components());
323348
}
349+
350+
stack.extend(base_path.components());
324351
}
325352
Prefix::VerbatimDisk(drive_letter) => {
326353
components.next();
327354
if components.peek() == Some(&Component::RootDir) {
328355
components.next();
356+
base_path = get_drive_path(drive_letter);
357+
} else {
358+
bail!("illegal path: {}", path.display());
329359
}
330360

331-
base_path = get_drive_path(drive_letter);
332361
stack.extend(base_path.components());
333362
}
334363
_ => bail!("invalid path: {}", path.display()),

0 commit comments

Comments
 (0)
Please sign in to comment.