1+ use fuzzy_matcher:: FuzzyMatcher ;
2+ use fuzzy_matcher:: skim:: SkimMatcherV2 ;
3+
14type SearchableFn < T > = dyn FnMut ( & & T , & str ) -> bool ;
25
6+ pub trait SearchableItem {
7+ fn search_text ( & self ) -> & str ;
8+ }
9+
310pub struct Searchable < T >
411where
5- T : Clone ,
12+ T : Clone + SearchableItem ,
613{
14+ sort_by_levenshtein : bool ,
715 vec : Vec < T > ,
8-
16+ matcher : SkimMatcherV2 ,
917 filter : Box < SearchableFn < T > > ,
1018 filtered : Vec < T > ,
1119}
1220
1321impl < T > Searchable < T >
1422where
15- T : Clone ,
23+ T : Clone + SearchableItem ,
1624{
1725 #[ must_use]
18- pub fn new < P > ( vec : Vec < T > , search_value : & str , predicate : P ) -> Self
26+ pub fn new < P > ( sort_by_levenshtein : bool , vec : Vec < T > , search_value : & str , predicate : P ) -> Self
1927 where
2028 P : FnMut ( & & T , & str ) -> bool + ' static ,
2129 {
2230 let mut searchable = Self {
31+ sort_by_levenshtein,
2332 vec,
24-
33+ matcher : SkimMatcherV2 :: default ( ) ,
2534 filter : Box :: new ( predicate) ,
2635 filtered : Vec :: new ( ) ,
2736 } ;
@@ -35,12 +44,22 @@ where
3544 return ;
3645 }
3746
38- self . filtered = self
47+ let mut items : Vec < _ > = self
3948 . vec
4049 . iter ( )
4150 . filter ( |host| ( self . filter ) ( host, value) )
42- . cloned ( )
51+ . map ( |item| {
52+ let score = self . matcher . fuzzy_match ( item. search_text ( ) , value) . unwrap_or ( 0 ) ;
53+ ( item. clone ( ) , score)
54+ } )
4355 . collect ( ) ;
56+
57+ // Sort by Levenshtein distance in descending order (higher score = better match)
58+ if self . sort_by_levenshtein {
59+ items. sort_by ( |a, b| b. 1 . cmp ( & a. 1 ) ) ;
60+ }
61+
62+ self . filtered = items. into_iter ( ) . map ( |( item, _) | item) . collect ( ) ;
4463 }
4564
4665 #[ allow( clippy:: must_use_candidate) ]
6483
6584impl < ' a , T > IntoIterator for & ' a Searchable < T >
6685where
67- T : Clone ,
86+ T : Clone + SearchableItem ,
6887{
6988 type Item = & ' a T ;
7089 type IntoIter = std:: slice:: Iter < ' a , T > ;
7695
7796impl < T > std:: ops:: Index < usize > for Searchable < T >
7897where
79- T : Clone ,
98+ T : Clone + SearchableItem ,
8099{
81100 type Output = T ;
82101
0 commit comments