3
3
use std:: fmt;
4
4
5
5
use hir:: { Documentation , Mutability } ;
6
- use ide_db:: {
7
- helpers:: mod_path_to_ast,
8
- imports:: {
9
- import_assets:: LocatedImport ,
10
- insert_use:: { self , ImportScope , InsertUseConfig } ,
11
- } ,
12
- SnippetCap , SymbolKind ,
13
- } ;
6
+ use ide_db:: { imports:: import_assets:: LocatedImport , SnippetCap , SymbolKind } ;
14
7
use smallvec:: SmallVec ;
15
8
use stdx:: { impl_from, never} ;
16
- use syntax:: { algo , SmolStr , TextRange } ;
9
+ use syntax:: { SmolStr , TextRange } ;
17
10
use text_edit:: TextEdit ;
18
11
19
12
/// `CompletionItem` describes a single completion variant in the editor pop-up.
@@ -73,7 +66,7 @@ pub struct CompletionItem {
73
66
ref_match : Option < Mutability > ,
74
67
75
68
/// The import data to add to completion's edits.
76
- import_to_add : SmallVec < [ ImportEdit ; 1 ] > ,
69
+ import_to_add : SmallVec < [ LocatedImport ; 1 ] > ,
77
70
}
78
71
79
72
// We use custom debug for CompletionItem to make snapshot tests more readable.
@@ -187,7 +180,6 @@ pub enum CompletionRelevancePostfixMatch {
187
180
}
188
181
189
182
impl CompletionRelevance {
190
- const BASE_LINE : u32 = 3 ;
191
183
/// Provides a relevance score. Higher values are more relevant.
192
184
///
193
185
/// The absolute value of the relevance score is not meaningful, for
@@ -197,35 +189,42 @@ impl CompletionRelevance {
197
189
///
198
190
/// See is_relevant if you need to make some judgement about score
199
191
/// in an absolute sense.
200
- pub fn score ( & self ) -> u32 {
201
- let mut score = Self :: BASE_LINE ;
202
-
203
- // score decreases
204
- if self . is_op_method {
205
- score -= 1 ;
206
- }
207
- if self . is_private_editable {
208
- score -= 1 ;
192
+ pub fn score ( self ) -> u32 {
193
+ let mut score = 0 ;
194
+ let CompletionRelevance {
195
+ exact_name_match,
196
+ type_match,
197
+ is_local,
198
+ is_op_method,
199
+ is_private_editable,
200
+ postfix_match,
201
+ } = self ;
202
+
203
+ // lower rank private things
204
+ if !is_private_editable {
205
+ score += 1 ;
209
206
}
210
- if self . postfix_match . is_some ( ) {
211
- score -= 3 ;
207
+ // lower rank trait op methods
208
+ if !is_op_method {
209
+ score += 10 ;
212
210
}
213
-
214
- // score increases
215
- if self . exact_name_match {
216
- score += 1 ;
211
+ if exact_name_match {
212
+ score += 10 ;
217
213
}
218
- score += match self . type_match {
219
- Some ( CompletionRelevanceTypeMatch :: Exact ) => 4 ,
214
+ score += match postfix_match {
215
+ Some ( CompletionRelevancePostfixMatch :: Exact ) => 100 ,
216
+ Some ( CompletionRelevancePostfixMatch :: NonExact ) => 0 ,
217
+ None => 3 ,
218
+ } ;
219
+ score += match type_match {
220
+ Some ( CompletionRelevanceTypeMatch :: Exact ) => 8 ,
220
221
Some ( CompletionRelevanceTypeMatch :: CouldUnify ) => 3 ,
221
222
None => 0 ,
222
223
} ;
223
- if self . is_local {
224
+ // slightly prefer locals
225
+ if is_local {
224
226
score += 1 ;
225
227
}
226
- if self . postfix_match == Some ( CompletionRelevancePostfixMatch :: Exact ) {
227
- score += 100 ;
228
- }
229
228
230
229
score
231
230
}
@@ -234,7 +233,7 @@ impl CompletionRelevance {
234
233
/// some threshold such that we think it is especially likely
235
234
/// to be relevant.
236
235
pub fn is_relevant ( & self ) -> bool {
237
- self . score ( ) > Self :: BASE_LINE
236
+ self . score ( ) > 0
238
237
}
239
238
}
240
239
@@ -374,40 +373,17 @@ impl CompletionItem {
374
373
self . ref_match . map ( |mutability| ( mutability, relevance) )
375
374
}
376
375
377
- pub fn imports_to_add ( & self ) -> & [ ImportEdit ] {
376
+ pub fn imports_to_add ( & self ) -> & [ LocatedImport ] {
378
377
& self . import_to_add
379
378
}
380
379
}
381
380
382
- /// An extra import to add after the completion is applied.
383
- #[ derive( Debug , Clone ) ]
384
- pub struct ImportEdit {
385
- pub import : LocatedImport ,
386
- pub scope : ImportScope ,
387
- }
388
-
389
- impl ImportEdit {
390
- /// Attempts to insert the import to the given scope, producing a text edit.
391
- /// May return no edit in edge cases, such as scope already containing the import.
392
- pub fn to_text_edit ( & self , cfg : InsertUseConfig ) -> Option < TextEdit > {
393
- let _p = profile:: span ( "ImportEdit::to_text_edit" ) ;
394
-
395
- let new_ast = self . scope . clone_for_update ( ) ;
396
- insert_use:: insert_use ( & new_ast, mod_path_to_ast ( & self . import . import_path ) , & cfg) ;
397
- let mut import_insert = TextEdit :: builder ( ) ;
398
- algo:: diff ( self . scope . as_syntax_node ( ) , new_ast. as_syntax_node ( ) )
399
- . into_text_edit ( & mut import_insert) ;
400
-
401
- Some ( import_insert. finish ( ) )
402
- }
403
- }
404
-
405
381
/// A helper to make `CompletionItem`s.
406
382
#[ must_use]
407
383
#[ derive( Clone ) ]
408
384
pub ( crate ) struct Builder {
409
385
source_range : TextRange ,
410
- imports_to_add : SmallVec < [ ImportEdit ; 1 ] > ,
386
+ imports_to_add : SmallVec < [ LocatedImport ; 1 ] > ,
411
387
trait_name : Option < SmolStr > ,
412
388
label : SmolStr ,
413
389
insert_text : Option < String > ,
@@ -433,7 +409,7 @@ impl Builder {
433
409
434
410
if let [ import_edit] = & * self . imports_to_add {
435
411
// snippets can have multiple imports, but normal completions only have up to one
436
- if let Some ( original_path) = import_edit. import . original_path . as_ref ( ) {
412
+ if let Some ( original_path) = import_edit. original_path . as_ref ( ) {
437
413
lookup = lookup. or_else ( || Some ( label. clone ( ) ) ) ;
438
414
label = SmolStr :: from ( format ! ( "{} (use {})" , label, original_path) ) ;
439
415
}
@@ -527,7 +503,7 @@ impl Builder {
527
503
self . trigger_call_info = Some ( true ) ;
528
504
self
529
505
}
530
- pub ( crate ) fn add_import ( & mut self , import_to_add : ImportEdit ) -> & mut Builder {
506
+ pub ( crate ) fn add_import ( & mut self , import_to_add : LocatedImport ) -> & mut Builder {
531
507
self . imports_to_add . push ( import_to_add) ;
532
508
self
533
509
}
@@ -584,55 +560,34 @@ mod tests {
584
560
585
561
#[ test]
586
562
fn relevance_score ( ) {
563
+ use CompletionRelevance as Cr ;
564
+ let default = Cr :: default ( ) ;
587
565
// This test asserts that the relevance score for these items is ascending, and
588
566
// that any items in the same vec have the same score.
589
567
let expected_relevance_order = vec ! [
590
- vec![ CompletionRelevance {
591
- postfix_match: Some ( CompletionRelevancePostfixMatch :: NonExact ) ,
592
- ..CompletionRelevance :: default ( )
593
- } ] ,
594
- vec![ CompletionRelevance {
595
- is_op_method: true ,
596
- is_private_editable: true ,
597
- ..CompletionRelevance :: default ( )
598
- } ] ,
599
- vec![
600
- CompletionRelevance { is_private_editable: true , ..CompletionRelevance :: default ( ) } ,
601
- CompletionRelevance { is_op_method: true , ..CompletionRelevance :: default ( ) } ,
602
- ] ,
603
- vec![ CompletionRelevance :: default ( ) ] ,
604
- vec![
605
- CompletionRelevance { exact_name_match: true , ..CompletionRelevance :: default ( ) } ,
606
- CompletionRelevance { is_local: true , ..CompletionRelevance :: default ( ) } ,
607
- ] ,
608
- vec![ CompletionRelevance {
568
+ vec![ ] ,
569
+ vec![ Cr { is_op_method: true , is_private_editable: true , ..default } ] ,
570
+ vec![ Cr { is_op_method: true , ..default } ] ,
571
+ vec![ Cr { postfix_match: Some ( CompletionRelevancePostfixMatch :: NonExact ) , ..default } ] ,
572
+ vec![ Cr { is_private_editable: true , ..default } ] ,
573
+ vec![ default ] ,
574
+ vec![ Cr { is_local: true , ..default } ] ,
575
+ vec![ Cr { type_match: Some ( CompletionRelevanceTypeMatch :: CouldUnify ) , ..default } ] ,
576
+ vec![ Cr { type_match: Some ( CompletionRelevanceTypeMatch :: Exact ) , ..default } ] ,
577
+ vec![ Cr { exact_name_match: true , ..default } ] ,
578
+ vec![ Cr { exact_name_match: true , is_local: true , ..default } ] ,
579
+ vec![ Cr {
609
580
exact_name_match: true ,
610
- is_local: true ,
611
- ..CompletionRelevance :: default ( )
612
- } ] ,
613
- vec![ CompletionRelevance {
614
- type_match: Some ( CompletionRelevanceTypeMatch :: CouldUnify ) ,
615
- ..CompletionRelevance :: default ( )
616
- } ] ,
617
- vec![ CompletionRelevance {
618
581
type_match: Some ( CompletionRelevanceTypeMatch :: Exact ) ,
619
- ..CompletionRelevance :: default ( )
582
+ ..default
620
583
} ] ,
621
- vec![ CompletionRelevance {
622
- exact_name_match: true ,
623
- type_match: Some ( CompletionRelevanceTypeMatch :: Exact ) ,
624
- ..CompletionRelevance :: default ( )
625
- } ] ,
626
- vec![ CompletionRelevance {
584
+ vec![ Cr {
627
585
exact_name_match: true ,
628
586
type_match: Some ( CompletionRelevanceTypeMatch :: Exact ) ,
629
587
is_local: true ,
630
- ..CompletionRelevance :: default ( )
631
- } ] ,
632
- vec![ CompletionRelevance {
633
- postfix_match: Some ( CompletionRelevancePostfixMatch :: Exact ) ,
634
- ..CompletionRelevance :: default ( )
588
+ ..default
635
589
} ] ,
590
+ vec![ Cr { postfix_match: Some ( CompletionRelevancePostfixMatch :: Exact ) , ..default } ] ,
636
591
] ;
637
592
638
593
check_relevance_score_ordered ( expected_relevance_order) ;
0 commit comments