hex_patch/app/files/
path.rs

1use regex::Regex;
2
3pub fn is_absolute(path: &str) -> bool {
4    path.starts_with('/')
5        || Regex::new(r"(^(\\\\\?\\)?[a-zA-Z]:)|(^\\\\\?\\[a-zA-Z]{1,})")
6            .expect(&t!("errors.invalid_regex"))
7            .is_match(path)
8}
9
10pub fn is_root(path: &str) -> bool {
11    path == "/"
12        || Regex::new(r"(^(\\\\\?\\)?[a-zA-Z]:\\?$)|(^\\\\\?\\[a-zA-Z]{1,}\\?$)")
13            .expect(&t!("errors.invalid_regex"))
14            .is_match(path)
15}
16
17pub fn parent(path: &str) -> Option<&str> {
18    if is_root(path) {
19        return None;
20    }
21    let path = path.trim_end_matches(['/', '\\']);
22    let last_delimiter_index = path.rfind(['/', '\\']);
23    Some(path.split_at(last_delimiter_index? + 1).0)
24}
25
26pub fn join(start: &str, end: &str, separator: char) -> String {
27    let start = start.trim_end_matches(separator);
28    let end = end.trim_start_matches(separator);
29    if end == ".." {
30        parent(start).unwrap_or(start).to_string()
31    } else if end == "." {
32        start.to_string()
33    } else {
34        format!("{start}{separator}{end}")
35    }
36}
37
38pub fn filename(path: &str) -> Option<&str> {
39    if is_root(path) {
40        None
41    } else {
42        let path = path.trim_end_matches(['/', '\\']);
43        path.rsplit(['/', '\\']).next()
44    }
45}
46
47pub fn diff<'a>(full_path: &'a str, prefix_path: &str) -> &'a str {
48    if full_path == prefix_path {
49        "."
50    } else if let Some(unprefixed_path) = full_path.strip_prefix(prefix_path) {
51        unprefixed_path.trim_start_matches(['/', '\\'])
52    } else if let Some(unprefixed_path_reverse_logic) = prefix_path.strip_prefix(full_path) {
53        if unprefixed_path_reverse_logic
54            .split(['/', '\\'])
55            .filter(|s| !s.is_empty())
56            .count()
57            == 1
58        {
59            ".."
60        } else {
61            full_path
62        }
63    } else {
64        full_path
65    }
66}
67
68#[cfg(test)]
69mod test {
70    use super::*;
71
72    #[test]
73    fn test_is_absolute() {
74        assert!(is_absolute("/"));
75        assert!(!is_absolute("test"));
76        assert!(is_absolute("/home/user"));
77        assert!(!is_absolute("home/user"));
78
79        assert!(!is_absolute("\\\\?\\"));
80        assert!(is_absolute("\\\\?\\C:\\Users\\"));
81        assert!(is_absolute("\\\\?\\d:\\Users"));
82        assert!(is_absolute("C:\\Users"));
83        assert!(is_absolute("d:\\Users"));
84        assert!(!is_absolute("ASDF\\Users"));
85        assert!(is_absolute("\\\\?\\ASDF\\"));
86        assert!(!is_absolute(".\\Users"));
87    }
88
89    #[test]
90    fn test_is_root() {
91        assert!(is_root("/"));
92        assert!(!is_root("test"));
93        assert!(!is_root("/home/user"));
94        assert!(!is_root("home/user"));
95
96        assert!(!is_root("\\\\?\\"));
97        assert!(is_root("\\\\?\\C:\\"));
98        assert!(is_root("\\\\?\\d:"));
99        assert!(is_root("C:\\"));
100        assert!(is_root("d:"));
101        assert!(!is_root("ASDF\\"));
102        assert!(is_root("\\\\?\\ASDF\\"));
103        assert!(!is_root(".\\Users"));
104    }
105
106    #[test]
107    fn test_parent() {
108        assert_eq!(parent("/home/user"), Some("/home/"));
109        assert_eq!(parent("/home"), Some("/"));
110        assert_eq!(parent("/"), None);
111        assert_eq!(parent("C:\\Users\\user"), Some("C:\\Users\\"));
112        assert_eq!(parent("C:\\Users"), Some("C:\\"));
113        assert_eq!(parent("C:\\"), None);
114        assert_eq!(parent("\\\\?\\C:\\Users\\user"), Some("\\\\?\\C:\\Users\\"));
115        assert_eq!(parent("\\\\?\\C:\\Users"), Some("\\\\?\\C:\\"));
116        assert_eq!(parent("\\\\?\\C:\\"), None);
117        assert_eq!(
118            parent("\\\\?\\ASDF\\Users\\user"),
119            Some("\\\\?\\ASDF\\Users\\")
120        );
121        assert_eq!(parent("\\\\?\\ASDF\\Users"), Some("\\\\?\\ASDF\\"));
122        assert_eq!(parent("\\\\?\\ASDF"), None);
123    }
124
125    #[test]
126    fn test_join() {
127        assert_eq!(join("/home", "user", '/'), "/home/user");
128        assert_eq!(join("/home", "..", '/'), "/");
129        assert_eq!(join("/home", ".", '/'), "/home");
130
131        assert_eq!(join("C:\\Users", "user", '\\'), "C:\\Users\\user");
132        assert_eq!(join("C:\\Users", "..", '\\'), "C:\\");
133        assert_eq!(join("C:\\Users", ".", '\\'), "C:\\Users");
134    }
135
136    #[test]
137    fn test_filename() {
138        assert_eq!(filename("/home/user"), Some("user"));
139        assert_eq!(filename("/home"), Some("home"));
140        assert_eq!(filename("/"), None);
141        assert_eq!(filename("C:\\Users\\user"), Some("user"));
142        assert_eq!(filename("C:\\Users"), Some("Users"));
143        assert_eq!(filename("C:\\"), None);
144        assert_eq!(filename("\\\\?\\C:\\Users\\user"), Some("user"));
145        assert_eq!(filename("\\\\?\\C:\\Users"), Some("Users"));
146        assert_eq!(filename("\\\\?\\C:\\"), None);
147        assert_eq!(filename("\\\\?\\ASDF\\Users\\user"), Some("user"));
148        assert_eq!(filename("\\\\?\\ASDF\\Users"), Some("Users"));
149        assert_eq!(filename("\\\\?\\ASDF"), None);
150    }
151
152    #[test]
153    fn test_diff() {
154        assert_eq!(diff("/home/user", "/home"), "user");
155        assert_eq!(diff("/home", "/home/user"), "..");
156        assert_eq!(diff("/home", "/home"), ".");
157        assert_eq!(diff("/home", "/"), "home");
158        assert_eq!(diff("/", "/"), ".");
159        assert_eq!(diff("C:\\Users\\user", "C:\\Users"), "user");
160        assert_eq!(diff("C:\\Users", "C:\\Users\\user"), "..");
161        assert_eq!(diff("C:\\Users", "C:\\Users"), ".");
162        assert_eq!(diff("C:\\Users", "C:\\"), "Users");
163        assert_eq!(diff("C:\\", "C:\\"), ".");
164        assert_eq!(diff("\\\\?\\C:\\Users\\user", "\\\\?\\C:\\Users"), "user");
165        assert_eq!(diff("\\\\?\\C:\\Users", "\\\\?\\C:\\Users"), ".");
166        assert_eq!(diff("\\\\?\\C:\\Users", "\\\\?\\C:\\"), "Users");
167        assert_eq!(diff("\\\\?\\C:\\", "\\\\?\\C:\\"), ".");
168        assert_eq!(
169            diff("\\\\?\\ASDF\\Users\\user", "\\\\?\\ASDF\\Users"),
170            "user"
171        );
172        assert_eq!(diff("\\\\?\\ASDF\\Users", "\\\\?\\ASDF\\Users"), ".");
173        assert_eq!(diff("\\\\?\\ASDF\\Users", "\\\\?\\ASDF"), "Users");
174        assert_eq!(diff("\\\\?\\ASDF", "\\\\?\\ASDF"), ".");
175    }
176}