@@ -5,24 +5,42 @@ use promptuity::pagination::paginate;
55use promptuity:: prompts:: { DefaultSelectFormatter , SelectFormatter , SelectOption } ;
66use promptuity:: style:: * ;
77use promptuity:: { Error , InputCursor , Prompt , PromptBody , PromptInput , PromptState , RenderPayload } ;
8+
89pub struct Autocomplete {
910 formatter : DefaultSelectFormatter ,
1011 message : String ,
1112 page_size : usize ,
1213 options : Vec < SelectOption < String > > ,
13- filtered_options : Vec < usize > ,
14+ filtered_options : Vec < ( usize , i64 ) > ,
1415 index : usize ,
1516 input : InputCursor ,
1617 matcher : SkimMatcherV2 ,
18+ priority : AutocompletePriority ,
1719 strict : bool ,
1820 skip : bool ,
1921}
2022
23+ #[ derive( Clone , Copy ) ]
24+ pub enum AutocompletePriority {
25+ Hint ,
26+ Label ,
27+ }
28+
29+ impl From < AutocompletePriority > for ( i64 , i64 ) {
30+ fn from ( value : AutocompletePriority ) -> ( i64 , i64 ) {
31+ match value {
32+ AutocompletePriority :: Hint => ( 1 , 4 ) ,
33+ AutocompletePriority :: Label => ( 4 , 1 ) ,
34+ }
35+ }
36+ }
37+
2138impl Autocomplete {
2239 pub fn new (
2340 message : impl std:: fmt:: Display ,
24- options : Vec < SelectOption < String > > ,
2541 strict : bool ,
42+ priority : AutocompletePriority ,
43+ options : Vec < SelectOption < String > > ,
2644 ) -> Self {
2745 Self {
2846 formatter : DefaultSelectFormatter :: new ( ) ,
@@ -33,13 +51,15 @@ impl Autocomplete {
3351 index : 0 ,
3452 input : InputCursor :: default ( ) ,
3553 matcher : SkimMatcherV2 :: default ( ) ,
54+ priority,
3655 strict,
3756 skip : false ,
3857 }
3958 }
4059
4160 fn run_filter ( & mut self ) {
4261 let pattern = self . input . value ( ) ;
62+ let ( priority_label, priority_hint) : ( i64 , i64 ) = self . priority . into ( ) ;
4363
4464 self . filtered_options = self
4565 . options
@@ -48,19 +68,38 @@ impl Autocomplete {
4868 . filter_map ( |( i, option) | {
4969 let label = & option. label ;
5070 let hint = option. hint . clone ( ) . unwrap_or_default ( ) ;
51- self . matcher
52- . fuzzy_match ( & format ! ( "{label} {hint}" ) , & pattern)
53- . map ( |_| i)
71+ let a = self
72+ . matcher
73+ . fuzzy_match ( label, & pattern)
74+ . unwrap_or_default ( ) ;
75+ let b = self
76+ . matcher
77+ . fuzzy_match ( & hint, & pattern)
78+ . unwrap_or_default ( ) ;
79+
80+ let c = ( a. saturating_mul ( priority_label) )
81+ . saturating_add ( b. saturating_mul ( priority_hint) )
82+ . saturating_sub ( i as i64 ) ;
83+
84+ log:: trace!( "{pattern} -> {label}; {a} & {b} = {c}" ) ;
85+ if c <= 0 && !pattern. is_empty ( ) {
86+ return None ;
87+ }
88+
89+ Some ( ( i, c) )
5490 } )
5591 . collect :: < Vec < _ > > ( ) ;
5692
93+ self . filtered_options . sort_by_key ( |( _, s) | * s) ;
94+ self . filtered_options . reverse ( ) ;
95+
5796 self . index = std:: cmp:: min ( self . filtered_options . len ( ) . saturating_sub ( 1 ) , self . index ) ;
5897 }
5998
6099 fn current_option ( & self ) -> Option < & SelectOption < String > > {
61100 self . filtered_options
62101 . get ( self . index )
63- . and_then ( |idx| self . options . get ( * idx) )
102+ . and_then ( |( idx, _ ) | self . options . get ( * idx) )
64103 }
65104}
66105
@@ -78,7 +117,7 @@ impl Prompt for Autocomplete {
78117 return Err ( Error :: Config ( "options cannot be empty." . into ( ) ) ) ;
79118 }
80119
81- self . filtered_options = ( 0 ..self . options . len ( ) ) . collect ( ) ;
120+ self . filtered_options = ( 0 ..self . options . len ( ) ) . map ( |i| ( i , 0 ) ) . collect ( ) ;
82121
83122 Ok ( ( ) )
84123 }
@@ -197,7 +236,7 @@ impl Prompt for Autocomplete {
197236 . items
198237 . iter ( )
199238 . enumerate ( )
200- . map ( |( i, idx) | {
239+ . map ( |( i, ( idx, _ ) ) | {
201240 let option = self . options . get ( * idx) . unwrap ( ) ;
202241 let active = i == page. cursor ;
203242 self . formatter . option (
0 commit comments