@@ -46,7 +46,7 @@ pub struct Filters {
4646pub enum ProviderListItem {
4747 All ,
4848 CategoryHeader ( ProviderCategory ) ,
49- Provider ( usize ) , // Index into providers
49+ Provider ( usize , usize ) , // (index into providers, match count)
5050}
5151
5252#[ derive( Debug , Clone ) ]
@@ -118,15 +118,40 @@ impl ModelsApp {
118118 providers : & ' a [ ( String , Provider ) ] ,
119119 ) -> Option < & ' a ( String , Provider ) > {
120120 match self . provider_list_items . get ( self . selected_provider ) {
121- Some ( ProviderListItem :: Provider ( idx) ) => providers. get ( * idx) ,
121+ Some ( ProviderListItem :: Provider ( idx, _ ) ) => providers. get ( * idx) ,
122122 _ => None ,
123123 }
124124 }
125125
126+ fn has_active_filters ( & self ) -> bool {
127+ !self . search_query . is_empty ( )
128+ || self . filters . reasoning
129+ || self . filters . tools
130+ || self . filters . open_weights
131+ || self . filters . free
132+ }
133+
134+ fn provider_match_count ( & self , provider_id : & str , provider : & Provider ) -> usize {
135+ let query_lower = self . search_query . to_lowercase ( ) ;
136+ provider
137+ . models
138+ . iter ( )
139+ . filter ( |( model_id, model) | {
140+ let search_matches = query_lower. is_empty ( )
141+ || model_id. to_lowercase ( ) . contains ( & query_lower)
142+ || model. name . to_lowercase ( ) . contains ( & query_lower)
143+ || provider_id. to_lowercase ( ) . contains ( & query_lower) ;
144+ search_matches && self . passes_filters ( model)
145+ } )
146+ . count ( )
147+ }
148+
126149 pub fn update_provider_list ( & mut self , providers : & [ ( String , Provider ) ] ) {
127150 self . provider_list_items . clear ( ) ;
128151 self . provider_list_items . push ( ProviderListItem :: All ) ;
129152
153+ let filtering = self . has_active_filters ( ) ;
154+
130155 if self . group_by_category {
131156 let categories = [
132157 ProviderCategory :: Origin ,
@@ -143,35 +168,55 @@ impl ModelsApp {
143168 continue ;
144169 }
145170
146- let mut indices : Vec < usize > = providers
171+ let mut items : Vec < ( usize , usize ) > = providers
147172 . iter ( )
148173 . enumerate ( )
149174 . filter ( |( _, ( id, _) ) | provider_category ( id) == * cat)
150- . map ( |( idx, _) | idx)
175+ . filter_map ( |( idx, ( id, provider) ) | {
176+ let count = if filtering {
177+ let c = self . provider_match_count ( id, provider) ;
178+ if c == 0 {
179+ return None ;
180+ }
181+ c
182+ } else {
183+ provider. models . len ( )
184+ } ;
185+ Some ( ( idx, count) )
186+ } )
151187 . collect ( ) ;
152188
153- if indices . is_empty ( ) {
189+ if items . is_empty ( ) {
154190 continue ;
155191 }
156192
157- indices . sort_by ( |a, b| providers[ * a ] . 0 . cmp ( & providers[ * b ] . 0 ) ) ;
193+ items . sort_by ( |a, b| providers[ a . 0 ] . 0 . cmp ( & providers[ b . 0 ] . 0 ) ) ;
158194
159195 self . provider_list_items
160196 . push ( ProviderListItem :: CategoryHeader ( * cat) ) ;
161- for idx in indices {
197+ for ( idx, count ) in items {
162198 self . provider_list_items
163- . push ( ProviderListItem :: Provider ( idx) ) ;
199+ . push ( ProviderListItem :: Provider ( idx, count ) ) ;
164200 }
165201 }
166202 } else {
167- for ( idx, ( id, _ ) ) in providers. iter ( ) . enumerate ( ) {
203+ for ( idx, ( id, provider ) ) in providers. iter ( ) . enumerate ( ) {
168204 if self . provider_category_filter != ProviderCategory :: All
169205 && provider_category ( id) != self . provider_category_filter
170206 {
171207 continue ;
172208 }
209+ let count = if filtering {
210+ let c = self . provider_match_count ( id, provider) ;
211+ if c == 0 {
212+ continue ;
213+ }
214+ c
215+ } else {
216+ provider. models . len ( )
217+ } ;
173218 self . provider_list_items
174- . push ( ProviderListItem :: Provider ( idx) ) ;
219+ . push ( ProviderListItem :: Provider ( idx, count ) ) ;
175220 }
176221 }
177222 }
@@ -365,20 +410,14 @@ impl ModelsApp {
365410 & self . filtered_models
366411 }
367412
368- pub fn total_model_count ( & self , providers : & [ ( String , Provider ) ] ) -> usize {
369- providers. iter ( ) . map ( |( _, p) | p. models . len ( ) ) . sum ( )
370- }
371-
372- pub fn filtered_model_count ( & self , providers : & [ ( String , Provider ) ] ) -> usize {
373- if self . provider_category_filter == ProviderCategory :: All {
374- self . total_model_count ( providers)
375- } else {
376- providers
377- . iter ( )
378- . filter ( |( id, _) | provider_category ( id) == self . provider_category_filter )
379- . map ( |( _, p) | p. models . len ( ) )
380- . sum ( )
381- }
413+ pub fn filtered_model_count ( & self ) -> usize {
414+ self . provider_list_items
415+ . iter ( )
416+ . filter_map ( |item| match item {
417+ ProviderListItem :: Provider ( _, count) => Some ( count) ,
418+ _ => None ,
419+ } )
420+ . sum ( )
382421 }
383422
384423 pub fn get_copy_full ( & self ) -> Option < String > {
@@ -554,34 +593,22 @@ impl ModelsApp {
554593
555594 pub fn toggle_reasoning ( & mut self , providers : & [ ( String , Provider ) ] ) {
556595 self . filters . reasoning = !self . filters . reasoning ;
557- self . selected_model = 0 ;
558- self . update_filtered_models ( providers) ;
559- self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
560- self . reset_detail_scroll ( ) ;
596+ self . rebuild_after_filter_change ( providers) ;
561597 }
562598
563599 pub fn toggle_tools ( & mut self , providers : & [ ( String , Provider ) ] ) {
564600 self . filters . tools = !self . filters . tools ;
565- self . selected_model = 0 ;
566- self . update_filtered_models ( providers) ;
567- self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
568- self . reset_detail_scroll ( ) ;
601+ self . rebuild_after_filter_change ( providers) ;
569602 }
570603
571604 pub fn toggle_open_weights ( & mut self , providers : & [ ( String , Provider ) ] ) {
572605 self . filters . open_weights = !self . filters . open_weights ;
573- self . selected_model = 0 ;
574- self . update_filtered_models ( providers) ;
575- self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
576- self . reset_detail_scroll ( ) ;
606+ self . rebuild_after_filter_change ( providers) ;
577607 }
578608
579609 pub fn toggle_free ( & mut self , providers : & [ ( String , Provider ) ] ) {
580610 self . filters . free = !self . filters . free ;
581- self . selected_model = 0 ;
582- self . update_filtered_models ( providers) ;
583- self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
584- self . reset_detail_scroll ( ) ;
611+ self . rebuild_after_filter_change ( providers) ;
585612 }
586613
587614 pub fn cycle_provider_category ( & mut self , providers : & [ ( String , Provider ) ] ) {
@@ -610,22 +637,40 @@ impl ModelsApp {
610637
611638 pub fn search_input ( & mut self , c : char , providers : & [ ( String , Provider ) ] ) {
612639 self . search_query . push ( c) ;
613- self . selected_model = 0 ;
614- self . update_filtered_models ( providers) ;
615- self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
616- self . reset_detail_scroll ( ) ;
640+ self . rebuild_after_filter_change ( providers) ;
617641 }
618642
619643 pub fn search_backspace ( & mut self , providers : & [ ( String , Provider ) ] ) {
620644 self . search_query . pop ( ) ;
621- self . selected_model = 0 ;
622- self . update_filtered_models ( providers) ;
623- self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
624- self . reset_detail_scroll ( ) ;
645+ self . rebuild_after_filter_change ( providers) ;
625646 }
626647
627648 pub fn clear_search ( & mut self , providers : & [ ( String , Provider ) ] ) {
628649 self . search_query . clear ( ) ;
650+ self . rebuild_after_filter_change ( providers) ;
651+ }
652+
653+ /// Rebuild provider list and model list after any search/filter change.
654+ /// Preserves the selected provider if it's still visible, otherwise falls back to "All".
655+ fn rebuild_after_filter_change ( & mut self , providers : & [ ( String , Provider ) ] ) {
656+ // Remember which provider was selected (by index into providers slice)
657+ let prev_provider_idx = match self . provider_list_items . get ( self . selected_provider ) {
658+ Some ( ProviderListItem :: Provider ( idx, _) ) => Some ( * idx) ,
659+ _ => None , // All or CategoryHeader
660+ } ;
661+
662+ self . update_provider_list ( providers) ;
663+
664+ // Try to find the previously selected provider in the new list
665+ let new_pos = prev_provider_idx. and_then ( |prev_idx| {
666+ self . provider_list_items . iter ( ) . position (
667+ |item| matches ! ( item, ProviderListItem :: Provider ( idx, _) if * idx == prev_idx) ,
668+ )
669+ } ) ;
670+
671+ self . selected_provider = new_pos. unwrap_or ( 0 ) ;
672+ self . provider_list_state
673+ . select ( Some ( self . selected_provider ) ) ;
629674 self . selected_model = 0 ;
630675 self . update_filtered_models ( providers) ;
631676 self . model_list_state . select ( Some ( self . selected_model + 1 ) ) ;
0 commit comments