aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/completions/unqualified_path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/completions/unqualified_path.rs')
-rw-r--r--crates/completion/src/completions/unqualified_path.rs172
1 files changed, 110 insertions, 62 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 93869f92e..099ffb4d4 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -1,7 +1,7 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use either::Either; 3use either::Either;
4use hir::{Adt, ModuleDef, ScopeDef, Type}; 4use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type};
5use ide_db::helpers::insert_use::ImportScope; 5use ide_db::helpers::insert_use::ImportScope;
6use ide_db::imports_locator; 6use ide_db::imports_locator;
7use syntax::AstNode; 7use syntax::AstNode;
@@ -146,13 +146,9 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
146 .filter(|(mod_path, _)| mod_path.len() > 1) 146 .filter(|(mod_path, _)| mod_path.len() > 1)
147 .collect::<Vec<_>>(); 147 .collect::<Vec<_>>();
148 148
149 let user_input_lowercased = potential_import_name.to_lowercase();
149 all_mod_paths.sort_by_cached_key(|(mod_path, _)| { 150 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
150 if let Some(name) = mod_path.segments.last().map(|name| name.to_string().to_lowercase()) { 151 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
151 if name.contains(&potential_import_name.to_lowercase()) {
152 return 0;
153 }
154 }
155 1
156 }); 152 });
157 153
158 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { 154 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
@@ -165,21 +161,48 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
165 Some(()) 161 Some(())
166} 162}
167 163
164fn compute_fuzzy_completion_order_key(
165 proposed_mod_path: &ModPath,
166 user_input_lowercased: &str,
167) -> usize {
168 mark::hit!(certain_fuzzy_order_test);
169 let proposed_import_name = match proposed_mod_path.segments.last() {
170 Some(name) => name.to_string().to_lowercase(),
171 None => return usize::MAX,
172 };
173 match proposed_import_name.match_indices(user_input_lowercased).next() {
174 Some((first_matching_index, _)) => first_matching_index,
175 None => usize::MAX,
176 }
177}
178
168#[cfg(test)] 179#[cfg(test)]
169mod tests { 180mod tests {
170 use expect_test::{expect, Expect}; 181 use expect_test::{expect, Expect};
171 use test_utils::mark; 182 use test_utils::mark;
172 183
173 use crate::{ 184 use crate::{
174 test_utils::{check_edit, check_edit_with_config, completion_list}, 185 test_utils::{check_edit, check_edit_with_config, completion_list_with_config},
175 CompletionConfig, CompletionKind, 186 CompletionConfig, CompletionKind,
176 }; 187 };
177 188
178 fn check(ra_fixture: &str, expect: Expect) { 189 fn check(ra_fixture: &str, expect: Expect) {
179 let actual = completion_list(ra_fixture, CompletionKind::Reference); 190 check_with_config(CompletionConfig::default(), ra_fixture, expect);
191 }
192
193 fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
194 let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
180 expect.assert_eq(&actual) 195 expect.assert_eq(&actual)
181 } 196 }
182 197
198 fn fuzzy_completion_config() -> CompletionConfig {
199 let mut completion_config = CompletionConfig::default();
200 completion_config
201 .active_resolve_capabilities
202 .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
203 completion_config
204 }
205
183 #[test] 206 #[test]
184 fn self_fulfilling_completion() { 207 fn self_fulfilling_completion() {
185 mark::check!(self_fulfilling_completion); 208 mark::check!(self_fulfilling_completion);
@@ -255,9 +278,9 @@ fn quux(x: i32) {
255} 278}
256"#, 279"#,
257 expect![[r#" 280 expect![[r#"
258 fn quux(…) fn quux(x: i32)
259 bn x i32
260 bn y i32 281 bn y i32
282 bn x i32
283 fn quux(…) fn quux(x: i32)
261 "#]], 284 "#]],
262 ); 285 );
263 } 286 }
@@ -277,8 +300,8 @@ fn quux() {
277} 300}
278"#, 301"#,
279 expect![[r#" 302 expect![[r#"
280 bn a
281 bn b i32 303 bn b i32
304 bn a
282 fn quux() fn quux() 305 fn quux() fn quux()
283 "#]], 306 "#]],
284 ); 307 );
@@ -293,8 +316,8 @@ fn quux() {
293} 316}
294"#, 317"#,
295 expect![[r#" 318 expect![[r#"
296 fn quux() fn quux()
297 bn x 319 bn x
320 fn quux() fn quux()
298 "#]], 321 "#]],
299 ); 322 );
300 } 323 }
@@ -335,9 +358,9 @@ fn main() {
335 check( 358 check(
336 r#"struct S<T> { x: <|>}"#, 359 r#"struct S<T> { x: <|>}"#,
337 expect![[r#" 360 expect![[r#"
338 st S<…>
339 tp Self 361 tp Self
340 tp T 362 tp T
363 st S<…>
341 "#]], 364 "#]],
342 ); 365 );
343 } 366 }
@@ -362,9 +385,9 @@ enum E {}
362fn quux() { <|> } 385fn quux() { <|> }
363"#, 386"#,
364 expect![[r#" 387 expect![[r#"
365 en E
366 st S 388 st S
367 fn quux() fn quux() 389 fn quux() fn quux()
390 en E
368 "#]], 391 "#]],
369 ); 392 );
370 } 393 }
@@ -416,8 +439,8 @@ mod m {
416} 439}
417"#, 440"#,
418 expect![[r#" 441 expect![[r#"
419 st Bar
420 fn quux() fn quux() 442 fn quux() fn quux()
443 st Bar
421 "#]], 444 "#]],
422 ); 445 );
423 } 446 }
@@ -462,8 +485,8 @@ fn foo() {
462 check( 485 check(
463 r#"impl S { fn foo(&self) { <|> } }"#, 486 r#"impl S { fn foo(&self) { <|> } }"#,
464 expect![[r#" 487 expect![[r#"
465 tp Self
466 bn self &{unknown} 488 bn self &{unknown}
489 tp Self
467 "#]], 490 "#]],
468 ); 491 );
469 } 492 }
@@ -482,9 +505,9 @@ use prelude::*;
482mod prelude { struct Option; } 505mod prelude { struct Option; }
483"#, 506"#,
484 expect![[r#" 507 expect![[r#"
485 st Option
486 fn foo() fn foo() 508 fn foo() fn foo()
487 md std 509 md std
510 st Option
488 "#]], 511 "#]],
489 ); 512 );
490 } 513 }
@@ -509,10 +532,10 @@ use prelude::*;
509mod prelude { struct String; } 532mod prelude { struct String; }
510"#, 533"#,
511 expect![[r#" 534 expect![[r#"
512 st String
513 md core
514 fn foo() fn foo() 535 fn foo() fn foo()
515 md std 536 md std
537 md core
538 st String
516 "#]], 539 "#]],
517 ); 540 );
518 } 541 }
@@ -538,13 +561,13 @@ mod m2 {
538fn main() { let v = <|> } 561fn main() { let v = <|> }
539"#, 562"#,
540 expect![[r##" 563 expect![[r##"
541 ma bar!(…) macro_rules! bar 564 md m1
542 ma baz!(…) #[macro_export] 565 ma baz!(…) #[macro_export]
543 macro_rules! baz 566 macro_rules! baz
544 ma foo!(…) macro_rules! foo
545 md m1
546 md m2
547 fn main() fn main() 567 fn main() fn main()
568 md m2
569 ma bar!(…) macro_rules! bar
570 ma foo!(…) macro_rules! foo
548 "##]], 571 "##]],
549 ); 572 );
550 } 573 }
@@ -557,8 +580,8 @@ macro_rules! foo { () => {} }
557fn foo() { <|> } 580fn foo() { <|> }
558"#, 581"#,
559 expect![[r#" 582 expect![[r#"
560 ma foo!(…) macro_rules! foo
561 fn foo() fn foo() 583 fn foo() fn foo()
584 ma foo!(…) macro_rules! foo
562 "#]], 585 "#]],
563 ); 586 );
564 } 587 }
@@ -571,8 +594,8 @@ macro_rules! foo { () => {} }
571fn main() { let x: <|> } 594fn main() { let x: <|> }
572"#, 595"#,
573 expect![[r#" 596 expect![[r#"
574 ma foo!(…) macro_rules! foo
575 fn main() fn main() 597 fn main() fn main()
598 ma foo!(…) macro_rules! foo
576 "#]], 599 "#]],
577 ); 600 );
578 } 601 }
@@ -585,8 +608,8 @@ macro_rules! foo { () => {} }
585fn main() { <|> } 608fn main() { <|> }
586"#, 609"#,
587 expect![[r#" 610 expect![[r#"
588 ma foo!(…) macro_rules! foo
589 fn main() fn main() 611 fn main() fn main()
612 ma foo!(…) macro_rules! foo
590 "#]], 613 "#]],
591 ); 614 );
592 } 615 }
@@ -618,10 +641,10 @@ fn quux(x: i32) {
618} 641}
619"#, 642"#,
620 expect![[r#" 643 expect![[r#"
621 ma m!(…) macro_rules! m
622 fn quux(…) fn quux(x: i32)
623 bn x i32
624 bn y i32 644 bn y i32
645 bn x i32
646 fn quux(…) fn quux(x: i32)
647 ma m!(…) macro_rules! m
625 "#]], 648 "#]],
626 ); 649 );
627 } 650 }
@@ -637,10 +660,10 @@ fn quux(x: i32) {
637} 660}
638", 661",
639 expect![[r#" 662 expect![[r#"
640 ma m!(…) macro_rules! m
641 fn quux(…) fn quux(x: i32)
642 bn x i32
643 bn y i32 663 bn y i32
664 bn x i32
665 fn quux(…) fn quux(x: i32)
666 ma m!(…) macro_rules! m
644 "#]], 667 "#]],
645 ); 668 );
646 } 669 }
@@ -656,10 +679,10 @@ fn quux(x: i32) {
656} 679}
657"#, 680"#,
658 expect![[r#" 681 expect![[r#"
659 ma m!(…) macro_rules! m
660 fn quux(…) fn quux(x: i32)
661 bn x i32
662 bn y i32 682 bn y i32
683 bn x i32
684 fn quux(…) fn quux(x: i32)
685 ma m!(…) macro_rules! m
663 "#]], 686 "#]],
664 ); 687 );
665 } 688 }
@@ -673,8 +696,8 @@ use spam::Quux;
673fn main() { <|> } 696fn main() { <|> }
674"#, 697"#,
675 expect![[r#" 698 expect![[r#"
676 ?? Quux
677 fn main() fn main() 699 fn main() fn main()
700 ?? Quux
678 "#]], 701 "#]],
679 ); 702 );
680 } 703 }
@@ -690,10 +713,10 @@ fn main() {
690} 713}
691"#, 714"#,
692 expect![[r#" 715 expect![[r#"
693 en Foo
694 ev Foo::Bar () 716 ev Foo::Bar ()
695 ev Foo::Baz () 717 ev Foo::Baz ()
696 ev Foo::Quux () 718 ev Foo::Quux ()
719 en Foo
697 "#]], 720 "#]],
698 ) 721 )
699 } 722 }
@@ -710,10 +733,10 @@ fn main() {
710} 733}
711"#, 734"#,
712 expect![[r#" 735 expect![[r#"
713 en Foo
714 ev Foo::Bar () 736 ev Foo::Bar ()
715 ev Foo::Baz () 737 ev Foo::Baz ()
716 ev Foo::Quux () 738 ev Foo::Quux ()
739 en Foo
717 "#]], 740 "#]],
718 ) 741 )
719 } 742 }
@@ -726,10 +749,10 @@ enum Foo { Bar, Baz, Quux }
726fn main() { let foo: Foo = Q<|> } 749fn main() { let foo: Foo = Q<|> }
727"#, 750"#,
728 expect![[r#" 751 expect![[r#"
729 en Foo
730 ev Foo::Bar () 752 ev Foo::Bar ()
731 ev Foo::Baz () 753 ev Foo::Baz ()
732 ev Foo::Quux () 754 ev Foo::Quux ()
755 en Foo
733 fn main() fn main() 756 fn main() fn main()
734 "#]], 757 "#]],
735 ) 758 )
@@ -743,9 +766,9 @@ mod m { pub enum E { V } }
743fn f() -> m::E { V<|> } 766fn f() -> m::E { V<|> }
744"#, 767"#,
745 expect![[r#" 768 expect![[r#"
746 fn f() fn f() -> m::E
747 md m
748 ev m::E::V () 769 ev m::E::V ()
770 md m
771 fn f() fn f() -> m::E
749 "#]], 772 "#]],
750 ) 773 )
751 } 774 }
@@ -772,22 +795,17 @@ struct MyStruct {}
772impl My<|> 795impl My<|>
773"#, 796"#,
774 expect![[r#" 797 expect![[r#"
775 st MyStruct
776 tt MyTrait
777 tp Self 798 tp Self
799 tt MyTrait
800 st MyStruct
778 "#]], 801 "#]],
779 ) 802 )
780 } 803 }
781 804
782 #[test] 805 #[test]
783 fn function_fuzzy_completion() { 806 fn function_fuzzy_completion() {
784 let mut completion_config = CompletionConfig::default();
785 completion_config
786 .active_resolve_capabilities
787 .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
788
789 check_edit_with_config( 807 check_edit_with_config(
790 completion_config, 808 fuzzy_completion_config(),
791 "stdin", 809 "stdin",
792 r#" 810 r#"
793//- /lib.rs crate:dep 811//- /lib.rs crate:dep
@@ -812,13 +830,8 @@ fn main() {
812 830
813 #[test] 831 #[test]
814 fn macro_fuzzy_completion() { 832 fn macro_fuzzy_completion() {
815 let mut completion_config = CompletionConfig::default();
816 completion_config
817 .active_resolve_capabilities
818 .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
819
820 check_edit_with_config( 833 check_edit_with_config(
821 completion_config, 834 fuzzy_completion_config(),
822 "macro_with_curlies!", 835 "macro_with_curlies!",
823 r#" 836 r#"
824//- /lib.rs crate:dep 837//- /lib.rs crate:dep
@@ -845,13 +858,8 @@ fn main() {
845 858
846 #[test] 859 #[test]
847 fn struct_fuzzy_completion() { 860 fn struct_fuzzy_completion() {
848 let mut completion_config = CompletionConfig::default();
849 completion_config
850 .active_resolve_capabilities
851 .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
852
853 check_edit_with_config( 861 check_edit_with_config(
854 completion_config, 862 fuzzy_completion_config(),
855 "ThirdStruct", 863 "ThirdStruct",
856 r#" 864 r#"
857//- /lib.rs crate:dep 865//- /lib.rs crate:dep
@@ -877,4 +885,44 @@ fn main() {
877"#, 885"#,
878 ); 886 );
879 } 887 }
888
889 #[test]
890 fn fuzzy_completions_come_in_specific_order() {
891 mark::check!(certain_fuzzy_order_test);
892 check_with_config(
893 fuzzy_completion_config(),
894 r#"
895//- /lib.rs crate:dep
896pub struct FirstStruct;
897pub mod some_module {
898 // already imported, omitted
899 pub struct SecondStruct;
900 // does not contain all letters from the query, omitted
901 pub struct UnrelatedOne;
902 // contains all letters from the query, but not in sequence, displayed last
903 pub struct ThiiiiiirdStruct;
904 // contains all letters from the query, but not in the beginning, displayed second
905 pub struct AfterThirdStruct;
906 // contains all letters from the query in the begginning, displayed first
907 pub struct ThirdStruct;
908}
909
910//- /main.rs crate:main deps:dep
911use dep::{FirstStruct, some_module::SecondStruct};
912
913fn main() {
914 hir<|>
915}
916"#,
917 expect![[r#"
918 fn main() fn main()
919 st SecondStruct
920 st FirstStruct
921 md dep
922 st dep::some_module::ThirdStruct
923 st dep::some_module::AfterThirdStruct
924 st dep::some_module::ThiiiiiirdStruct
925 "#]],
926 );
927 }
880} 928}