miden_debug_engine/
source_path.rs1use miden_debug_types::Uri;
2
3pub fn normalize_source_path(path: &str) -> String {
5 let path = path.trim();
6 let path = Uri::new(path)
7 .to_path()
8 .map(|path| path.to_string_lossy().into_owned())
9 .unwrap_or_else(|| path.to_owned());
10 let mut path = path.replace('\\', "/");
11 if path
12 .as_bytes()
13 .get(0..2)
14 .is_some_and(|bytes| bytes[0].is_ascii_alphabetic() && bytes[1] == b':')
15 {
16 path.replace_range(..1, &path[..1].to_ascii_lowercase());
17 }
18
19 let is_absolute = path.starts_with('/');
20 let mut parts = Vec::new();
21 for part in path.split('/') {
22 match part {
23 "" | "." => {}
24 ".." => {
25 if parts.last().is_some_and(|last| *last != "..") {
26 parts.pop();
27 } else {
28 parts.push(part);
29 }
30 }
31 _ => parts.push(part),
32 }
33 }
34
35 let normalized = parts.join("/");
36 if is_absolute && !normalized.is_empty() {
37 format!("/{normalized}")
38 } else {
39 normalized
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::normalize_source_path;
46
47 #[test]
48 fn normalizes_file_uris_and_windows_drive_letters() {
49 assert_eq!(
50 normalize_source_path("file:///C:/Users/me/program.masm"),
51 "c:/Users/me/program.masm"
52 );
53 assert_eq!(
54 normalize_source_path("file:///c:/Users/me/program.masm"),
55 "c:/Users/me/program.masm"
56 );
57 assert_eq!(
58 normalize_source_path("file://localhost/C:/Users/me/program.masm"),
59 "c:/Users/me/program.masm"
60 );
61 assert_eq!(
62 normalize_source_path("C:\\Users\\me\\program.masm"),
63 "c:/Users/me/program.masm"
64 );
65 }
66
67 #[test]
68 fn normalizes_path_components() {
69 assert_eq!(
70 normalize_source_path("/home/me/./src/../program.masm"),
71 "/home/me/program.masm"
72 );
73 assert_eq!(
74 normalize_source_path("relative/./src/../program.masm"),
75 "relative/program.masm"
76 );
77 }
78}