@@ -83,29 +83,42 @@ impl ImportMap {
8383 . iter ( )
8484 // We've only collected items, whose name cannot be tuple field so unwrapping is fine.
8585 . flat_map ( |( & item, ( info, _) ) | {
86- info. iter ( ) . enumerate ( ) . map ( move | ( idx , info ) | {
87- ( item , info . name . as_str ( ) . unwrap ( ) . to_ascii_lowercase ( ) , idx as u32 )
88- } )
86+ info. iter ( )
87+ . enumerate ( )
88+ . map ( move | ( idx , info ) | ( item , info . name . to_smol_str ( ) , idx as u32 ) )
8989 } )
9090 . collect ( ) ;
91- importables. sort_by ( |( _, lhs_name, _) , ( _, rhs_name, _) | lhs_name. cmp ( rhs_name) ) ;
91+ importables. sort_by ( |( _, l_info, _) , ( _, r_info, _) | {
92+ let lhs_chars = l_info. chars ( ) . map ( |c| c. to_ascii_lowercase ( ) ) ;
93+ let rhs_chars = r_info. chars ( ) . map ( |c| c. to_ascii_lowercase ( ) ) ;
94+ lhs_chars. cmp ( rhs_chars)
95+ } ) ;
9296 importables. dedup ( ) ;
9397
9498 // Build the FST, taking care not to insert duplicate values.
9599 let mut builder = fst:: MapBuilder :: memory ( ) ;
96- let iter = importables
100+ let mut iter = importables
97101 . iter ( )
98102 . enumerate ( )
99- . dedup_by ( |( _, ( _, lhs, _) ) , ( _, ( _, rhs, _) ) | lhs == rhs) ;
100- for ( start_idx, ( _, name, _) ) in iter {
101- let _ = builder. insert ( name, start_idx as u64 ) ;
103+ . dedup_by ( |& ( _, ( _, lhs, _) ) , & ( _, ( _, rhs, _) ) | lhs. eq_ignore_ascii_case ( rhs) ) ;
104+
105+ let mut insert = |name : & str , start, end| {
106+ builder. insert ( name. to_ascii_lowercase ( ) , ( ( start as u64 ) << 32 ) | end as u64 ) . unwrap ( )
107+ } ;
108+
109+ if let Some ( ( mut last, ( _, name, _) ) ) = iter. next ( ) {
110+ debug_assert_eq ! ( last, 0 ) ;
111+ let mut last_name = name;
112+ for ( next, ( _, next_name, _) ) in iter {
113+ insert ( last_name, last, next) ;
114+ last = next;
115+ last_name = next_name;
116+ }
117+ insert ( last_name, last, importables. len ( ) ) ;
102118 }
103119
104- Arc :: new ( ImportMap {
105- item_to_info_map : map,
106- fst : builder. into_map ( ) ,
107- importables : importables. into_iter ( ) . map ( |( item, _, idx) | ( item, idx) ) . collect ( ) ,
108- } )
120+ let importables = importables. into_iter ( ) . map ( |( item, _, idx) | ( item, idx) ) . collect ( ) ;
121+ Arc :: new ( ImportMap { item_to_info_map : map, fst : builder. into_map ( ) , importables } )
109122 }
110123
111124 pub fn import_info_for ( & self , item : ItemInNs ) -> Option < & [ ImportInfo ] > {
@@ -266,8 +279,8 @@ impl fmt::Debug for ImportMap {
266279}
267280
268281/// A way to match import map contents against the search query.
269- #[ derive( Copy , Clone , Debug ) ]
270- enum SearchMode {
282+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
283+ pub enum SearchMode {
271284 /// Import map entry should strictly match the query string.
272285 Exact ,
273286 /// Import map entry should contain all letters from the query string,
@@ -277,6 +290,42 @@ enum SearchMode {
277290 Prefix ,
278291}
279292
293+ impl SearchMode {
294+ pub fn check ( self , query : & str , case_sensitive : bool , candidate : & str ) -> bool {
295+ match self {
296+ SearchMode :: Exact if case_sensitive => candidate == query,
297+ SearchMode :: Exact => candidate. eq_ignore_ascii_case ( & query) ,
298+ SearchMode :: Prefix => {
299+ query. len ( ) <= candidate. len ( ) && {
300+ let prefix = & candidate[ ..query. len ( ) as usize ] ;
301+ if case_sensitive {
302+ prefix == query
303+ } else {
304+ prefix. eq_ignore_ascii_case ( & query)
305+ }
306+ }
307+ }
308+ SearchMode :: Fuzzy => {
309+ let mut name = candidate;
310+ query. chars ( ) . all ( |query_char| {
311+ let m = if case_sensitive {
312+ name. match_indices ( query_char) . next ( )
313+ } else {
314+ name. match_indices ( [ query_char, query_char. to_ascii_uppercase ( ) ] ) . next ( )
315+ } ;
316+ match m {
317+ Some ( ( index, _) ) => {
318+ name = & name[ index + 1 ..] ;
319+ true
320+ }
321+ None => false ,
322+ }
323+ } )
324+ }
325+ }
326+ }
327+ }
328+
280329/// Three possible ways to search for the name in associated and/or other items.
281330#[ derive( Debug , Clone , Copy ) ]
282331pub enum AssocSearchMode {
@@ -392,67 +441,28 @@ fn search_maps(
392441 query : & Query ,
393442) -> FxHashSet < ItemInNs > {
394443 let mut res = FxHashSet :: default ( ) ;
395- while let Some ( ( key , indexed_values) ) = stream. next ( ) {
444+ while let Some ( ( _ , indexed_values) ) = stream. next ( ) {
396445 for & IndexedValue { index : import_map_idx, value } in indexed_values {
397- let import_map = & import_maps[ import_map_idx] ;
398- let importables = & import_map. importables [ value as usize ..] ;
446+ let end = ( value & 0xFFFF_FFFF ) as usize ;
447+ let start = ( value >> 32 ) as usize ;
448+ let ImportMap { item_to_info_map, importables, .. } = & * import_maps[ import_map_idx] ;
449+ let importables = & importables[ start as usize ..end] ;
399450
400451 let iter = importables
401452 . iter ( )
402453 . copied ( )
403- . map ( |( item, info_idx) | {
404- let ( import_infos, assoc_mode) = & import_map. item_to_info_map [ & item] ;
405- ( item, & import_infos[ info_idx as usize ] , * assoc_mode)
454+ . filter_map ( |( item, info_idx) | {
455+ let ( import_infos, assoc_mode) = & item_to_info_map[ & item] ;
456+ query
457+ . matches_assoc_mode ( * assoc_mode)
458+ . then ( || ( item, & import_infos[ info_idx as usize ] ) )
406459 } )
407- // we put all entries with the same lowercased name in a row, so stop once we find a
408- // different name in the importables
409- // FIXME: Consider putting a range into the value: u64 as (u32, u32)?
410- . take_while ( |& ( _, info, _) | {
411- info. name . to_smol_str ( ) . as_bytes ( ) . eq_ignore_ascii_case ( & key)
412- } )
413- . filter ( |& ( _, info, assoc_mode) | {
414- if !query. matches_assoc_mode ( assoc_mode) {
415- return false ;
416- }
417- if !query. case_sensitive {
418- return true ;
419- }
420- let name = info. name . to_smol_str ( ) ;
421- // FIXME: Deduplicate this from ide-db
422- match query. search_mode {
423- SearchMode :: Exact => !query. case_sensitive || name == query. query ,
424- SearchMode :: Prefix => {
425- query. query . len ( ) <= name. len ( ) && {
426- let prefix = & name[ ..query. query . len ( ) as usize ] ;
427- if query. case_sensitive {
428- prefix == query. query
429- } else {
430- prefix. eq_ignore_ascii_case ( & query. query )
431- }
432- }
433- }
434- SearchMode :: Fuzzy => {
435- let mut name = & * name;
436- query. query . chars ( ) . all ( |query_char| {
437- let m = if query. case_sensitive {
438- name. match_indices ( query_char) . next ( )
439- } else {
440- name. match_indices ( [
441- query_char,
442- query_char. to_ascii_uppercase ( ) ,
443- ] )
444- . next ( )
445- } ;
446- match m {
447- Some ( ( index, _) ) => {
448- name = & name[ index + 1 ..] ;
449- true
450- }
451- None => false ,
452- }
453- } )
454- }
455- }
460+ . filter ( |& ( _, info) | {
461+ query. search_mode . check (
462+ & query. query ,
463+ query. case_sensitive ,
464+ & info. name . to_smol_str ( ) ,
465+ )
456466 } ) ;
457467 res. extend ( iter. map ( TupleExt :: head) ) ;
458468 }
0 commit comments