diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-12-08 13:10:28 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-08 13:10:28 +0000 |
commit | 4d4f11925f793c45560c45c088d4b3139c2c171c (patch) | |
tree | f8c5e3c14a0bb55d4b435b8389bccf305975d39a /crates/completion/src/completions | |
parent | 021e97ea03cf67ad7785ab39580e04bc69506b8c (diff) | |
parent | bf24cb3e8db94a84fb4a24c407797ab6ff5ee109 (diff) |
Merge #6706
6706: Move import text edit calculation into a completion resolve request r=matklad a=SomeoneToIgnore
Part of https://github.com/rust-analyzer/rust-analyzer/issues/6612 (presumably fixing it)
Part of https://github.com/rust-analyzer/rust-analyzer/issues/6366 (does not cover all possible resolve capabilities we can do)
Closes https://github.com/rust-analyzer/rust-analyzer/issues/6594
Further improves imports on completion performance by deferring the computations for import inserts.
To use the new mode, you have to have the experimental completions enabled and use the LSP 3.16-compliant client that reports `additionalTextEdits` in its `CompletionItemCapabilityResolveSupport` field in the client capabilities.
rust-analyzer VSCode extension does this already hence picks up the changes completely.
Performance implications are descrbed in: https://github.com/rust-analyzer/rust-analyzer/issues/6633#issuecomment-737295182
Co-authored-by: Kirill Bulatov <[email protected]>
Diffstat (limited to 'crates/completion/src/completions')
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 92 |
1 files changed, 78 insertions, 14 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 81691cd7f..4e4e2b36f 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -9,7 +9,7 @@ use test_utils::mark; | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | render::{render_resolution_with_import, RenderContext}, | 11 | render::{render_resolution_with_import, RenderContext}, |
12 | CompletionContext, Completions, | 12 | CompletionContext, Completions, ImportEdit, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 15 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -44,7 +44,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
44 | acc.add_resolution(ctx, name.to_string(), &res) | 44 | acc.add_resolution(ctx, name.to_string(), &res) |
45 | }); | 45 | }); |
46 | 46 | ||
47 | if ctx.config.enable_experimental_completions { | 47 | if ctx.config.enable_autoimport_completions && ctx.config.resolve_additional_edits_lazily() { |
48 | fuzzy_completion(acc, ctx).unwrap_or_default() | 48 | fuzzy_completion(acc, ctx).unwrap_or_default() |
49 | } | 49 | } |
50 | } | 50 | } |
@@ -73,19 +73,64 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
76 | // Feature: Fuzzy Completion and Autoimports | ||
77 | // | ||
78 | // When completing names in the current scope, proposes additional imports from other modules or crates, | ||
79 | // if they can be qualified in the scope and their name contains all symbols from the completion input | ||
80 | // (case-insensitive, in any order or places). | ||
81 | // | ||
82 | // ``` | ||
83 | // fn main() { | ||
84 | // pda<|> | ||
85 | // } | ||
86 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
87 | // ``` | ||
88 | // -> | ||
89 | // ``` | ||
90 | // use std::marker::PhantomData; | ||
91 | // | ||
92 | // fn main() { | ||
93 | // PhantomData | ||
94 | // } | ||
95 | // # pub mod std { pub mod marker { pub struct PhantomData { } } } | ||
96 | // ``` | ||
97 | // | ||
98 | // .Fuzzy search details | ||
99 | // | ||
100 | // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only | ||
101 | // (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers. | ||
102 | // | ||
103 | // .Merge Behaviour | ||
104 | // | ||
105 | // It is possible to configure how use-trees are merged with the `importMergeBehaviour` setting. | ||
106 | // Mimics the corresponding behaviour of the `Auto Import` feature. | ||
107 | // | ||
108 | // .LSP and performance implications | ||
109 | // | ||
110 | // The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` | ||
111 | // (case sensitive) resolve client capability in its client capabilities. | ||
112 | // This way the server is able to defer the costly computations, doing them for a selected completion item only. | ||
113 | // For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, | ||
114 | // which might be slow ergo the feature is automatically disabled. | ||
115 | // | ||
116 | // .Feature toggle | ||
117 | // | ||
118 | // The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. | ||
119 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | ||
120 | // capability enabled. | ||
76 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 121 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
77 | let _p = profile::span("fuzzy_completion"); | 122 | let _p = profile::span("fuzzy_completion"); |
123 | let potential_import_name = ctx.token.to_string(); | ||
124 | |||
78 | let current_module = ctx.scope.module()?; | 125 | let current_module = ctx.scope.module()?; |
79 | let anchor = ctx.name_ref_syntax.as_ref()?; | 126 | let anchor = ctx.name_ref_syntax.as_ref()?; |
80 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | 127 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; |
81 | 128 | ||
82 | let potential_import_name = ctx.token.to_string(); | ||
83 | |||
84 | let possible_imports = imports_locator::find_similar_imports( | 129 | let possible_imports = imports_locator::find_similar_imports( |
85 | &ctx.sema, | 130 | &ctx.sema, |
86 | ctx.krate?, | 131 | ctx.krate?, |
132 | Some(100), | ||
87 | &potential_import_name, | 133 | &potential_import_name, |
88 | 50, | ||
89 | true, | 134 | true, |
90 | ) | 135 | ) |
91 | .filter_map(|import_candidate| { | 136 | .filter_map(|import_candidate| { |
@@ -99,13 +144,14 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
99 | }) | 144 | }) |
100 | }) | 145 | }) |
101 | .filter(|(mod_path, _)| mod_path.len() > 1) | 146 | .filter(|(mod_path, _)| mod_path.len() > 1) |
102 | .take(20) | ||
103 | .filter_map(|(import_path, definition)| { | 147 | .filter_map(|(import_path, definition)| { |
104 | render_resolution_with_import( | 148 | render_resolution_with_import( |
105 | RenderContext::new(ctx), | 149 | RenderContext::new(ctx), |
106 | import_path.clone(), | 150 | ImportEdit { |
107 | import_scope.clone(), | 151 | import_path: import_path.clone(), |
108 | ctx.config.merge, | 152 | import_scope: import_scope.clone(), |
153 | merge_behaviour: ctx.config.merge, | ||
154 | }, | ||
109 | &definition, | 155 | &definition, |
110 | ) | 156 | ) |
111 | }); | 157 | }); |
@@ -120,8 +166,8 @@ mod tests { | |||
120 | use test_utils::mark; | 166 | use test_utils::mark; |
121 | 167 | ||
122 | use crate::{ | 168 | use crate::{ |
123 | test_utils::{check_edit, completion_list}, | 169 | test_utils::{check_edit, check_edit_with_config, completion_list}, |
124 | CompletionKind, | 170 | CompletionConfig, CompletionKind, |
125 | }; | 171 | }; |
126 | 172 | ||
127 | fn check(ra_fixture: &str, expect: Expect) { | 173 | fn check(ra_fixture: &str, expect: Expect) { |
@@ -730,7 +776,13 @@ impl My<|> | |||
730 | 776 | ||
731 | #[test] | 777 | #[test] |
732 | fn function_fuzzy_completion() { | 778 | fn function_fuzzy_completion() { |
733 | check_edit( | 779 | let mut completion_config = CompletionConfig::default(); |
780 | completion_config | ||
781 | .active_resolve_capabilities | ||
782 | .insert(crate::CompletionResolveCapability::AdditionalTextEdits); | ||
783 | |||
784 | check_edit_with_config( | ||
785 | completion_config, | ||
734 | "stdin", | 786 | "stdin", |
735 | r#" | 787 | r#" |
736 | //- /lib.rs crate:dep | 788 | //- /lib.rs crate:dep |
@@ -755,7 +807,13 @@ fn main() { | |||
755 | 807 | ||
756 | #[test] | 808 | #[test] |
757 | fn macro_fuzzy_completion() { | 809 | fn macro_fuzzy_completion() { |
758 | check_edit( | 810 | let mut completion_config = CompletionConfig::default(); |
811 | completion_config | ||
812 | .active_resolve_capabilities | ||
813 | .insert(crate::CompletionResolveCapability::AdditionalTextEdits); | ||
814 | |||
815 | check_edit_with_config( | ||
816 | completion_config, | ||
759 | "macro_with_curlies!", | 817 | "macro_with_curlies!", |
760 | r#" | 818 | r#" |
761 | //- /lib.rs crate:dep | 819 | //- /lib.rs crate:dep |
@@ -782,7 +840,13 @@ fn main() { | |||
782 | 840 | ||
783 | #[test] | 841 | #[test] |
784 | fn struct_fuzzy_completion() { | 842 | fn struct_fuzzy_completion() { |
785 | check_edit( | 843 | let mut completion_config = CompletionConfig::default(); |
844 | completion_config | ||
845 | .active_resolve_capabilities | ||
846 | .insert(crate::CompletionResolveCapability::AdditionalTextEdits); | ||
847 | |||
848 | check_edit_with_config( | ||
849 | completion_config, | ||
786 | "ThirdStruct", | 850 | "ThirdStruct", |
787 | r#" | 851 | r#" |
788 | //- /lib.rs crate:dep | 852 | //- /lib.rs crate:dep |