matrix_sdk_ui/room_list_service/filters/
fuzzy_match_room_name.rs1pub use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher as _};
16
17use super::{normalize_string, Filter};
18
19struct FuzzyMatcher {
20 matcher: SkimMatcherV2,
21 pattern: Option<String>,
22}
23
24impl FuzzyMatcher {
25 fn new() -> Self {
26 Self { matcher: SkimMatcherV2::default().smart_case().use_cache(true), pattern: None }
27 }
28
29 fn with_pattern(mut self, pattern: &str) -> Self {
30 self.pattern = Some(normalize_string(pattern));
31
32 self
33 }
34
35 fn matches(&self, subject: &str) -> bool {
36 let Some(pattern) = self.pattern.as_ref() else { return true };
38
39 self.matcher.fuzzy_match(&normalize_string(subject), pattern).is_some()
40 }
41}
42
43pub fn new_filter(pattern: &str) -> impl Filter {
48 let searcher = FuzzyMatcher::new().with_pattern(pattern);
49
50 move |room| -> bool {
51 let Some(room_name) = room.cached_display_name() else { return false };
52
53 searcher.matches(&room_name)
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use std::ops::Not;
60
61 use super::*;
62
63 #[test]
64 fn test_no_pattern() {
65 let matcher = FuzzyMatcher::new();
66
67 assert!(matcher.matches("hello"));
68 }
69
70 #[test]
71 fn test_empty_pattern() {
72 let matcher = FuzzyMatcher::new();
73
74 assert!(matcher.matches("hello"));
75 }
76
77 #[test]
78 fn test_literal() {
79 let matcher = FuzzyMatcher::new();
80
81 let matcher = matcher.with_pattern("mtx");
82 assert!(matcher.matches("matrix"));
83
84 let matcher = matcher.with_pattern("mxt");
85 assert!(matcher.matches("matrix").not());
86 }
87
88 #[test]
89 fn test_ignore_case() {
90 let matcher = FuzzyMatcher::new();
91
92 let matcher = matcher.with_pattern("mtx");
93 assert!(matcher.matches("MaTrIX"));
94
95 let matcher = matcher.with_pattern("mxt");
96 assert!(matcher.matches("MaTrIX").not());
97 }
98
99 #[test]
100 fn test_smart_case() {
101 let matcher = FuzzyMatcher::new();
102
103 let matcher = matcher.with_pattern("mtx");
104 assert!(matcher.matches("matrix"));
105 assert!(matcher.matches("Matrix"));
106
107 let matcher = matcher.with_pattern("Mtx");
108 assert!(matcher.matches("matrix").not());
109 assert!(matcher.matches("Matrix"));
110 }
111
112 #[test]
113 fn test_normalization() {
114 let matcher = FuzzyMatcher::new();
115
116 let matcher = matcher.with_pattern("ubété");
117
118 assert_eq!(matcher.pattern, Some("ubete".to_owned()));
120
121 assert!(matcher.matches("un bel été"));
123
124 let matcher = matcher.with_pattern("stf");
126 assert!(matcher.matches("Ștefan"));
127 }
128}