1pub mod picker;
2pub mod project_selector;
3pub mod session_switcher;
4pub mod theme;
5pub mod worktree_picker;
6
7pub use project_selector::{open_project, run_project_selector};
8pub use session_switcher::run_session_switcher;
9pub use worktree_picker::{run_worktree_picker, run_worktree_picker_stderr};
10
11pub fn fuzzy_match(s: &str, query: &str) -> bool {
15 let s = s.to_lowercase();
16 let q = query.to_lowercase();
17 let mut q_chars = q.chars();
18 let Some(mut needle) = q_chars.next() else {
19 return true;
20 };
21 for c in s.chars() {
22 if c == needle {
23 match q_chars.next() {
24 Some(next) => needle = next,
25 None => return true,
26 }
27 }
28 }
29 false
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35
36 #[test]
37 fn fuzzy_match_empty_query_always_matches() {
38 assert!(fuzzy_match("anything", ""));
39 assert!(fuzzy_match("", ""));
40 }
41
42 #[test]
43 fn fuzzy_match_subsequence_hits() {
44 assert!(fuzzy_match("session-manager", "sm"));
45 assert!(fuzzy_match("project-selector", "pjsl"));
46 assert!(fuzzy_match("Hello World", "hw"));
47 }
48
49 #[test]
50 fn fuzzy_match_misses() {
51 assert!(!fuzzy_match("abc", "abcd"));
52 assert!(!fuzzy_match("abc", "zz"));
53 assert!(!fuzzy_match("", "x"));
54 }
55
56 #[test]
57 fn fuzzy_match_is_case_insensitive() {
58 assert!(fuzzy_match("AbCdEf", "ace"));
59 assert!(fuzzy_match("abcdef", "ACE"));
60 }
61}