Skip to main content

tmx/ui/
mod.rs

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
11/// Subsequence-style fuzzy match: every char of `query` must appear in `s`
12/// in order, case-insensitively. Mirrors the Go version's behaviour but is
13/// Unicode-safe rather than byte-based.
14pub 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}