@@ -31,9 +31,10 @@ use base_db::{
31
31
salsa:: { self , ParallelDatabase } ,
32
32
SourceDatabaseExt , SourceRootId , Upcast ,
33
33
} ;
34
- use fst:: { self , Streamer } ;
34
+ use fst:: { self , raw :: IndexedValue , Automaton , Streamer } ;
35
35
use hir:: {
36
36
db:: HirDatabase ,
37
+ import_map:: AssocSearchMode ,
37
38
symbols:: { FileSymbol , SymbolCollector } ,
38
39
Crate , Module ,
39
40
} ;
@@ -57,6 +58,7 @@ pub struct Query {
57
58
only_types : bool ,
58
59
libs : bool ,
59
60
mode : SearchMode ,
61
+ assoc_mode : AssocSearchMode ,
60
62
case_sensitive : bool ,
61
63
limit : usize ,
62
64
}
@@ -70,6 +72,7 @@ impl Query {
70
72
only_types : false ,
71
73
libs : false ,
72
74
mode : SearchMode :: Fuzzy ,
75
+ assoc_mode : AssocSearchMode :: Include ,
73
76
case_sensitive : false ,
74
77
limit : usize:: max_value ( ) ,
75
78
}
@@ -95,6 +98,11 @@ impl Query {
95
98
self . mode = SearchMode :: Prefix ;
96
99
}
97
100
101
+ /// Specifies whether we want to include associated items in the result.
102
+ pub fn assoc_search_mode ( & mut self , assoc_mode : AssocSearchMode ) {
103
+ self . assoc_mode = assoc_mode;
104
+ }
105
+
98
106
pub fn case_sensitive ( & mut self ) {
99
107
self . case_sensitive = true ;
100
108
}
@@ -225,7 +233,9 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
225
233
indices. iter ( ) . flat_map ( |indices| indices. iter ( ) . cloned ( ) ) . collect ( )
226
234
} ;
227
235
228
- query. search ( & indices)
236
+ let mut res = vec ! [ ] ;
237
+ query. search ( & indices, |f| res. push ( f. clone ( ) ) ) ;
238
+ res
229
239
}
230
240
231
241
#[ derive( Default ) ]
@@ -285,6 +295,7 @@ impl SymbolIndex {
285
295
builder. insert ( key, value) . unwrap ( ) ;
286
296
}
287
297
298
+ // FIXME: fst::Map should ideally have a way to shrink the backing buffer without the unwrap dance
288
299
let map = fst:: Map :: new ( {
289
300
let mut buf = builder. into_inner ( ) . unwrap ( ) ;
290
301
buf. shrink_to_fit ( ) ;
@@ -317,61 +328,114 @@ impl SymbolIndex {
317
328
}
318
329
319
330
impl Query {
320
- pub ( crate ) fn search ( self , indices : & [ Arc < SymbolIndex > ] ) -> Vec < FileSymbol > {
331
+ pub ( crate ) fn search < ' sym > (
332
+ self ,
333
+ indices : & ' sym [ Arc < SymbolIndex > ] ,
334
+ cb : impl FnMut ( & ' sym FileSymbol ) ,
335
+ ) {
321
336
let _p = profile:: span ( "symbol_index::Query::search" ) ;
322
337
let mut op = fst:: map:: OpBuilder :: new ( ) ;
323
- for file_symbols in indices. iter ( ) {
324
- let automaton = fst:: automaton:: Subsequence :: new ( & self . lowercased ) ;
325
- op = op. add ( file_symbols. map . search ( automaton) )
338
+ match self . mode {
339
+ SearchMode :: Exact => {
340
+ let automaton = fst:: automaton:: Str :: new ( & self . lowercased ) ;
341
+
342
+ for index in indices. iter ( ) {
343
+ op = op. add ( index. map . search ( & automaton) ) ;
344
+ }
345
+ self . search_maps ( & indices, op. union ( ) , cb)
346
+ }
347
+ SearchMode :: Fuzzy => {
348
+ let automaton = fst:: automaton:: Subsequence :: new ( & self . lowercased ) ;
349
+
350
+ for index in indices. iter ( ) {
351
+ op = op. add ( index. map . search ( & automaton) ) ;
352
+ }
353
+ self . search_maps ( & indices, op. union ( ) , cb)
354
+ }
355
+ SearchMode :: Prefix => {
356
+ let automaton = fst:: automaton:: Str :: new ( & self . lowercased ) . starts_with ( ) ;
357
+
358
+ for index in indices. iter ( ) {
359
+ op = op. add ( index. map . search ( & automaton) ) ;
360
+ }
361
+ self . search_maps ( & indices, op. union ( ) , cb)
362
+ }
326
363
}
327
- let mut stream = op. union ( ) ;
328
- let mut res = Vec :: new ( ) ;
364
+ }
365
+
366
+ fn search_maps < ' sym > (
367
+ & self ,
368
+ indices : & ' sym [ Arc < SymbolIndex > ] ,
369
+ mut stream : fst:: map:: Union < ' _ > ,
370
+ mut cb : impl FnMut ( & ' sym FileSymbol ) ,
371
+ ) {
329
372
while let Some ( ( _, indexed_values) ) = stream. next ( ) {
330
- for indexed_value in indexed_values {
331
- let symbol_index = & indices[ indexed_value . index ] ;
332
- let ( start, end) = SymbolIndex :: map_value_to_range ( indexed_value . value ) ;
373
+ for & IndexedValue { index , value } in indexed_values {
374
+ let symbol_index = & indices[ index] ;
375
+ let ( start, end) = SymbolIndex :: map_value_to_range ( value) ;
333
376
334
377
for symbol in & symbol_index. symbols [ start..end] {
335
- if self . only_types
378
+ let non_type_for_type_only_query = self . only_types
336
379
&& !matches ! (
337
380
symbol. def,
338
381
hir:: ModuleDef :: Adt ( ..)
339
382
| hir:: ModuleDef :: TypeAlias ( ..)
340
383
| hir:: ModuleDef :: BuiltinType ( ..)
341
384
| hir:: ModuleDef :: TraitAlias ( ..)
342
385
| hir:: ModuleDef :: Trait ( ..)
343
- )
344
- {
386
+ ) ;
387
+ if non_type_for_type_only_query || ! self . matches_assoc_mode ( symbol . is_assoc ) {
345
388
continue ;
346
389
}
347
- let skip = match self . mode {
348
- SearchMode :: Fuzzy => {
349
- self . case_sensitive
350
- && self . query . chars ( ) . any ( |c| !symbol. name . contains ( c) )
390
+ // FIXME: Deduplicate this from hir-def
391
+ let matches = match self . mode {
392
+ SearchMode :: Exact if self . case_sensitive => symbol. name == self . query ,
393
+ SearchMode :: Exact => symbol. name . eq_ignore_ascii_case ( & self . query ) ,
394
+ SearchMode :: Prefix => {
395
+ self . query . len ( ) <= symbol. name . len ( ) && {
396
+ let prefix = & symbol. name [ ..self . query . len ( ) as usize ] ;
397
+ if self . case_sensitive {
398
+ prefix == self . query
399
+ } else {
400
+ prefix. eq_ignore_ascii_case ( & self . query )
401
+ }
402
+ }
351
403
}
352
- SearchMode :: Exact => symbol. name != self . query ,
353
- SearchMode :: Prefix if self . case_sensitive => {
354
- !symbol. name . starts_with ( & self . query )
404
+ SearchMode :: Fuzzy => {
405
+ let mut name = & * symbol. name ;
406
+ self . query . chars ( ) . all ( |query_char| {
407
+ let m = if self . case_sensitive {
408
+ name. match_indices ( query_char) . next ( )
409
+ } else {
410
+ name. match_indices ( [
411
+ query_char,
412
+ query_char. to_ascii_uppercase ( ) ,
413
+ ] )
414
+ . next ( )
415
+ } ;
416
+ match m {
417
+ Some ( ( index, _) ) => {
418
+ name = & name[ index + 1 ..] ;
419
+ true
420
+ }
421
+ None => false ,
422
+ }
423
+ } )
355
424
}
356
- SearchMode :: Prefix => symbol
357
- . name
358
- . chars ( )
359
- . zip ( self . lowercased . chars ( ) )
360
- . all ( |( n, q) | n. to_lowercase ( ) . next ( ) == Some ( q) ) ,
361
425
} ;
362
-
363
- if skip {
364
- continue ;
365
- }
366
-
367
- res. push ( symbol. clone ( ) ) ;
368
- if res. len ( ) >= self . limit {
369
- return res;
426
+ if matches {
427
+ cb ( symbol) ;
370
428
}
371
429
}
372
430
}
373
431
}
374
- res
432
+ }
433
+
434
+ fn matches_assoc_mode ( & self , is_trait_assoc_item : bool ) -> bool {
435
+ match ( is_trait_assoc_item, self . assoc_mode ) {
436
+ ( true , AssocSearchMode :: Exclude ) | ( false , AssocSearchMode :: AssocItemsOnly ) => false ,
437
+ _ => true ,
438
+ }
375
439
}
376
440
}
377
441
0 commit comments