1use std::path::Path;
2
3pub fn format(path: &Path) -> String {
4 normalize(&path.to_string_lossy())
5}
6
7pub fn format_home(path: &Path, home_dir: &Path) -> String {
8 match path.strip_prefix(home_dir) {
9 Ok(relative) if relative.as_os_str().is_empty() => "~".to_string(),
10 Ok(relative) => format!("~/{}", normalize(&relative.to_string_lossy())),
11 Err(_) => format(path),
12 }
13}
14
15pub fn format_tilde_path(path: &str, home_dir: &Path) -> String {
16 let expanded = crate::config::tilde_expand(path);
17 format_home(Path::new(&expanded), home_dir)
18}
19
20pub fn strip_windows_verbatim_prefix(value: &str) -> String {
21 value
22 .strip_prefix(r"\\?\UNC\")
23 .map(|path| format!(r"\\{path}"))
24 .or_else(|| value.strip_prefix(r"\\?\").map(str::to_string))
25 .unwrap_or_else(|| value.to_string())
26}
27
28fn normalize(value: &str) -> String {
29 strip_windows_verbatim_prefix(value).replace('\\', "/")
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use std::path::PathBuf;
36
37 #[test]
38 fn formats_paths_with_forward_slashes() {
39 assert_eq!(
40 format(Path::new(r"C:\Users\alice\file.txt")),
41 "C:/Users/alice/file.txt"
42 );
43 }
44
45 #[test]
46 fn strips_windows_verbatim_disk_prefix() {
47 assert_eq!(
48 format(Path::new(r"\\?\C:\Users\alice\file.txt")),
49 "C:/Users/alice/file.txt"
50 );
51 }
52
53 #[test]
54 fn strips_windows_verbatim_unc_prefix() {
55 assert_eq!(
56 format(Path::new(r"\\?\UNC\server\share\file.txt")),
57 "//server/share/file.txt"
58 );
59 }
60
61 #[test]
62 fn strips_windows_verbatim_prefix_without_changing_separators() {
63 assert_eq!(
64 strip_windows_verbatim_prefix(r"\\?\D:\Github\Biulight\shine\preset.ps1"),
65 r"D:\Github\Biulight\shine\preset.ps1"
66 );
67 assert_eq!(
68 strip_windows_verbatim_prefix(r"\\?\UNC\server\share\preset.ps1"),
69 r"\\server\share\preset.ps1"
70 );
71 }
72
73 #[test]
74 fn collapses_home_prefix() {
75 let home = PathBuf::from(r"C:\Users\alice");
76 let path = home.join("AppData").join("Roaming").join("Docker");
77 assert_eq!(format_home(&path, &home), "~/AppData/Roaming/Docker");
78 }
79
80 #[test]
81 fn formats_tilde_path_via_home_display_rules() {
82 let expanded = crate::config::tilde_expand("~/Library/Application Support");
83 let home = PathBuf::from(crate::config::tilde_expand("~"));
84 assert_eq!(
85 format_tilde_path("~/Library/Application Support", &home),
86 format_home(Path::new(&expanded), &home)
87 );
88 }
89}