teksilo_preview/
source_loc.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct SourceLoc {
13 pub file: &'static str,
14 pub line: u32,
15}
16
17impl SourceLoc {
18 pub const fn new(file: &'static str, line: u32) -> Self {
19 Self { file, line }
20 }
21
22 pub fn matches_path(&self, target: &str) -> bool {
28 fn norm(s: &str) -> String {
30 s.replace('\\', "/")
31 }
32 fn suffix_on_boundary(hay: &str, needle: &str) -> bool {
35 hay == needle || hay.strip_suffix(needle).is_some_and(|p| p.ends_with('/'))
36 }
37 let a = norm(self.file);
38 let b = norm(target);
39 suffix_on_boundary(&a, &b) || suffix_on_boundary(&b, &a)
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn matches_path_handles_suffix_matches() {
49 let loc = SourceLoc::new("crates/teksilo-widgets/src/button.rs", 42);
50 assert!(loc.matches_path("crates/teksilo-widgets/src/button.rs"));
51 assert!(loc.matches_path("button.rs"));
52 assert!(loc.matches_path("src/button.rs"));
53 assert!(!loc.matches_path("crates/teksilo-widgets/src/checkbox.rs"));
54 }
55
56 #[test]
57 fn suffix_match_respects_component_boundaries() {
58 let radio = SourceLoc::new("crates/teksilo-widgets/src/radio_button.rs", 1);
60 assert!(!radio.matches_path("button.rs"));
61 assert!(radio.matches_path("radio_button.rs"));
62 assert!(radio.matches_path("src/radio_button.rs"));
63 }
64
65 #[test]
66 fn matches_path_normalises_separators() {
67 let loc = SourceLoc::new("crates\\teksilo-widgets\\src\\button.rs", 1);
68 assert!(loc.matches_path("button.rs"));
69 assert!(loc.matches_path("src/button.rs"));
70 }
71}