20
20
//! file in the current workspace, and run a query against the union of all
21
21
//! those FSTs.
22
22
use std:: {
23
- cmp:: Ordering ,
24
23
hash:: { Hash , Hasher } ,
25
24
sync:: Arc ,
26
25
mem,
@@ -137,13 +136,32 @@ impl Hash for SymbolIndex {
137
136
138
137
impl SymbolIndex {
139
138
fn new ( mut symbols : Vec < FileSymbol > ) -> SymbolIndex {
140
- fn cmp ( s1 : & FileSymbol , s2 : & FileSymbol ) -> Ordering {
141
- unicase:: Ascii :: new ( s1. name . as_str ( ) ) . cmp ( & unicase :: Ascii :: new ( s2 . name . as_str ( ) ) )
139
+ fn cmp_key < ' a > ( s1 : & ' a FileSymbol ) -> impl Ord + ' a {
140
+ unicase:: Ascii :: new ( s1. name . as_str ( ) )
142
141
}
143
- symbols. par_sort_by ( cmp) ;
144
- symbols. dedup_by ( |s1, s2| cmp ( s1, s2) == Ordering :: Equal ) ;
145
- let names = symbols. iter ( ) . map ( |it| it. name . as_str ( ) . to_lowercase ( ) ) ;
146
- let map = fst:: Map :: from_iter ( names. zip ( 0u64 ..) ) . unwrap ( ) ;
142
+
143
+ symbols. par_sort_by ( |s1, s2| cmp_key ( s1) . cmp ( & cmp_key ( s2) ) ) ;
144
+
145
+ let mut builder = fst:: MapBuilder :: memory ( ) ;
146
+
147
+ let mut last_batch_start = 0 ;
148
+
149
+ for idx in 0 ..symbols. len ( ) {
150
+ if symbols. get ( last_batch_start) . map ( cmp_key) == symbols. get ( idx + 1 ) . map ( cmp_key) {
151
+ continue ;
152
+ }
153
+
154
+ let start = last_batch_start;
155
+ let end = idx + 1 ;
156
+ last_batch_start = end;
157
+
158
+ let key = symbols[ start] . name . as_str ( ) . to_lowercase ( ) ;
159
+ let value = SymbolIndex :: range_to_map_value ( start, end) ;
160
+
161
+ builder. insert ( key, value) . unwrap ( ) ;
162
+ }
163
+
164
+ let map = fst:: Map :: from_bytes ( builder. into_inner ( ) . unwrap ( ) ) . unwrap ( ) ;
147
165
SymbolIndex { symbols, map }
148
166
}
149
167
@@ -163,6 +181,19 @@ impl SymbolIndex {
163
181
. collect :: < Vec < _ > > ( ) ;
164
182
SymbolIndex :: new ( symbols)
165
183
}
184
+
185
+ fn range_to_map_value ( start : usize , end : usize ) -> u64 {
186
+ debug_assert ! [ start <= ( std:: u32 :: MAX as usize ) ] ;
187
+ debug_assert ! [ end <= ( std:: u32 :: MAX as usize ) ] ;
188
+
189
+ ( ( start as u64 ) << 32 ) | end as u64
190
+ }
191
+
192
+ fn map_value_to_range ( value : u64 ) -> ( usize , usize ) {
193
+ let end = value as u32 as usize ;
194
+ let start = ( value >> 32 ) as usize ;
195
+ ( start, end)
196
+ }
166
197
}
167
198
168
199
impl Query {
@@ -179,17 +210,18 @@ impl Query {
179
210
break ;
180
211
}
181
212
for indexed_value in indexed_values {
182
- let file_symbols = & indices[ indexed_value. index ] ;
183
- let idx = indexed_value. value as usize ;
184
-
185
- let symbol = & file_symbols. symbols [ idx] ;
186
- if self . only_types && !is_type ( symbol. ptr . kind ( ) ) {
187
- continue ;
188
- }
189
- if self . exact && symbol. name != self . query {
190
- continue ;
213
+ let symbol_index = & indices[ indexed_value. index ] ;
214
+ let ( start, end) = SymbolIndex :: map_value_to_range ( indexed_value. value ) ;
215
+
216
+ for symbol in & symbol_index. symbols [ start..end] {
217
+ if self . only_types && !is_type ( symbol. ptr . kind ( ) ) {
218
+ continue ;
219
+ }
220
+ if self . exact && symbol. name != self . query {
221
+ continue ;
222
+ }
223
+ res. push ( symbol. clone ( ) ) ;
191
224
}
192
- res. push ( symbol. clone ( ) ) ;
193
225
}
194
226
}
195
227
res
@@ -273,7 +305,10 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
273
305
274
306
#[ cfg( test) ]
275
307
mod tests {
276
- use ra_syntax:: SmolStr ;
308
+ use ra_syntax:: {
309
+ SmolStr ,
310
+ SyntaxKind :: { FN_DEF , STRUCT_DEF }
311
+ } ;
277
312
use crate :: {
278
313
display:: NavigationTarget ,
279
314
mock_analysis:: single_file,
@@ -323,6 +358,23 @@ mod foo {
323
358
assert_eq ! ( s. container_name( ) , Some ( & SmolStr :: new( "foo" ) ) ) ;
324
359
}
325
360
361
+ #[ test]
362
+ fn test_world_symbols_are_case_sensitive ( ) {
363
+ let code = r#"
364
+ fn foo() {}
365
+
366
+ struct Foo;
367
+ "# ;
368
+
369
+ let symbols = get_symbols_matching ( code, "Foo" ) ;
370
+
371
+ let fn_match = symbols. iter ( ) . find ( |s| s. name ( ) == "foo" ) . map ( |s| s. kind ( ) ) ;
372
+ let struct_match = symbols. iter ( ) . find ( |s| s. name ( ) == "Foo" ) . map ( |s| s. kind ( ) ) ;
373
+
374
+ assert_eq ! ( fn_match, Some ( FN_DEF ) ) ;
375
+ assert_eq ! ( struct_match, Some ( STRUCT_DEF ) ) ;
376
+ }
377
+
326
378
fn get_symbols_matching ( text : & str , query : & str ) -> Vec < NavigationTarget > {
327
379
let ( analysis, _) = single_file ( text) ;
328
380
analysis. symbol_search ( Query :: new ( query. into ( ) ) ) . unwrap ( )
0 commit comments