]> git.lizzy.rs Git - rust.git/commitdiff
Disable the completion for no corresponding client resolve capabilities
authorKirill Bulatov <mail4score@gmail.com>
Mon, 7 Dec 2020 22:46:56 +0000 (00:46 +0200)
committerKirill Bulatov <mail4score@gmail.com>
Mon, 7 Dec 2020 23:07:20 +0000 (01:07 +0200)
12 files changed:
crates/completion/src/completions/unqualified_path.rs
crates/completion/src/config.rs
crates/completion/src/item.rs
crates/completion/src/lib.rs
crates/completion/src/render.rs
crates/completion/src/render/enum_variant.rs
crates/completion/src/render/function.rs
crates/completion/src/render/macro_.rs
crates/completion/src/test_utils.rs
crates/ide_db/src/imports_locator.rs
crates/rust-analyzer/src/config.rs
editors/code/package.json

index 1482df8fb698ceee3dfa299c29095a557334ac1b..2a315cb864a89992e5e23e93b1082fb52f14f7a4 100644 (file)
@@ -44,7 +44,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
         acc.add_resolution(ctx, name.to_string(), &res)
     });
 
-    if ctx.config.enable_experimental_completions {
+    if !ctx.config.disable_fuzzy_autoimports && ctx.config.resolve_additional_edits_lazily() {
         fuzzy_completion(acc, ctx).unwrap_or_default()
     }
 }
@@ -99,6 +99,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
 //
 // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only
 // (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers.
+// It also avoids searching for any imports for inputs with their length less that 3 symbols.
 //
 // .Merge Behaviour
 //
@@ -107,53 +108,53 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
 //
 // .LSP and performance implications
 //
-// LSP 3.16 provides the way to defer the computation of some completion data, including the import edits for this feature.
-// If the LSP client supports the `additionalTextEdits` (case sensitive) resolve client capability, rust-analyzer computes
-// the completion edits only when a corresponding completion item is selected.
+// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
+// (case sensitive) resolve client capability in its client capabilities.
+// This way the server is able to defer the costly computations, doing them for a selected completion item only.
 // For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
-// which might be slow.
+// which might be slow ergo the feature is automatically disabled.
 //
 // .Feature toggle
 //
-// The feature can be turned off in the settings with the `rust-analyzer.completion.enableExperimental` flag.
+// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.disableFuzzyAutoimports` flag.
 fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
     let _p = profile::span("fuzzy_completion");
+    let potential_import_name = ctx.token.to_string();
+
+    if potential_import_name.len() < 3 {
+        return None;
+    }
+
     let current_module = ctx.scope.module()?;
     let anchor = ctx.name_ref_syntax.as_ref()?;
     let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
 
-    let potential_import_name = ctx.token.to_string();
-
-    let possible_imports = imports_locator::find_similar_imports(
-        &ctx.sema,
-        ctx.krate?,
-        &potential_import_name,
-        50,
-        true,
-    )
-    .filter_map(|import_candidate| {
-        Some(match import_candidate {
-            Either::Left(module_def) => {
-                (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
-            }
-            Either::Right(macro_def) => {
-                (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
-            }
-        })
-    })
-    .filter(|(mod_path, _)| mod_path.len() > 1)
-    .take(20)
-    .filter_map(|(import_path, definition)| {
-        render_resolution_with_import(
-            RenderContext::new(ctx),
-            ImportEdit {
-                import_path: import_path.clone(),
-                import_scope: import_scope.clone(),
-                merge_behaviour: ctx.config.merge,
-            },
-            &definition,
-        )
-    });
+    let possible_imports =
+        imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, true)
+            .filter_map(|import_candidate| {
+                Some(match import_candidate {
+                    Either::Left(module_def) => (
+                        current_module.find_use_path(ctx.db, module_def)?,
+                        ScopeDef::ModuleDef(module_def),
+                    ),
+                    Either::Right(macro_def) => (
+                        current_module.find_use_path(ctx.db, macro_def)?,
+                        ScopeDef::MacroDef(macro_def),
+                    ),
+                })
+            })
+            .filter(|(mod_path, _)| mod_path.len() > 1)
+            .filter_map(|(import_path, definition)| {
+                render_resolution_with_import(
+                    RenderContext::new(ctx),
+                    ImportEdit {
+                        import_path: import_path.clone(),
+                        import_scope: import_scope.clone(),
+                        merge_behaviour: ctx.config.merge,
+                    },
+                    &definition,
+                )
+            });
 
     acc.add_all(possible_imports);
     Some(())
@@ -775,7 +776,13 @@ impl My<|>
 
     #[test]
     fn function_fuzzy_completion() {
-        check_edit(
+        let mut completion_config = CompletionConfig::default();
+        completion_config
+            .active_resolve_capabilities
+            .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
+
+        check_edit_with_config(
+            completion_config,
             "stdin",
             r#"
 //- /lib.rs crate:dep
@@ -800,7 +807,13 @@ fn main() {
 
     #[test]
     fn macro_fuzzy_completion() {
-        check_edit(
+        let mut completion_config = CompletionConfig::default();
+        completion_config
+            .active_resolve_capabilities
+            .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
+
+        check_edit_with_config(
+            completion_config,
             "macro_with_curlies!",
             r#"
 //- /lib.rs crate:dep
@@ -827,37 +840,6 @@ fn main() {
 
     #[test]
     fn struct_fuzzy_completion() {
-        check_edit(
-            "ThirdStruct",
-            r#"
-//- /lib.rs crate:dep
-pub struct FirstStruct;
-pub mod some_module {
-    pub struct SecondStruct;
-    pub struct ThirdStruct;
-}
-
-//- /main.rs crate:main deps:dep
-use dep::{FirstStruct, some_module::SecondStruct};
-
-fn main() {
-    this<|>
-}
-"#,
-            r#"
-use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
-
-fn main() {
-    ThirdStruct
-}
-"#,
-        );
-    }
-
-    /// LSP protocol supports separate completion resolve requests to do the heavy computations there.
-    /// This test checks that for a certain resolve capatilities no such operations (autoimport) are done.
-    #[test]
-    fn no_fuzzy_completions_applied_for_certain_resolve_capability() {
         let mut completion_config = CompletionConfig::default();
         completion_config
             .active_resolve_capabilities
@@ -870,22 +852,22 @@ fn no_fuzzy_completions_applied_for_certain_resolve_capability() {
 //- /lib.rs crate:dep
 pub struct FirstStruct;
 pub mod some_module {
-pub struct SecondStruct;
-pub struct ThirdStruct;
+    pub struct SecondStruct;
+    pub struct ThirdStruct;
 }
 
 //- /main.rs crate:main deps:dep
 use dep::{FirstStruct, some_module::SecondStruct};
 
 fn main() {
-this<|>
+    this<|>
 }
 "#,
             r#"
-use dep::{FirstStruct, some_module::SecondStruct};
+use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
 
 fn main() {
-ThirdStruct
+    ThirdStruct
 }
 "#,
         );
index 487c1d0f1427644b7a50f2c4ee9c2a02f20017eb..8082ec9cb001b3defccbefd1ef0603a8d8ebd548 100644 (file)
@@ -10,7 +10,7 @@
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CompletionConfig {
     pub enable_postfix_completions: bool,
-    pub enable_experimental_completions: bool,
+    pub disable_fuzzy_autoimports: bool,
     pub add_call_parenthesis: bool,
     pub add_call_argument_snippets: bool,
     pub snippet_cap: Option<SnippetCap>,
@@ -52,7 +52,7 @@ impl Default for CompletionConfig {
     fn default() -> Self {
         CompletionConfig {
             enable_postfix_completions: true,
-            enable_experimental_completions: true,
+            disable_fuzzy_autoimports: false,
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: Some(SnippetCap { _private: () }),
index 978ea76f993c55ea8133ed02eed8a965e1956dcc..bd94402d75364ed43cf130687c2b742ddf8510eb 100644 (file)
@@ -209,7 +209,6 @@ pub(crate) fn new(
             score: None,
             ref_match: None,
             import_to_add: None,
-            resolve_import_lazily: false,
         }
     }
 
@@ -301,7 +300,6 @@ pub(crate) struct Builder {
     source_range: TextRange,
     completion_kind: CompletionKind,
     import_to_add: Option<ImportEdit>,
-    resolve_import_lazily: bool,
     label: String,
     insert_text: Option<String>,
     insert_text_format: InsertTextFormat,
@@ -339,25 +337,13 @@ pub(crate) fn build(self) -> CompletionItem {
             }
         }
 
-        let mut text_edit = match self.text_edit {
+        let text_edit = match self.text_edit {
             Some(it) => it,
             None => {
                 TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
             }
         };
 
-        let import_to_add = if self.resolve_import_lazily {
-            self.import_to_add
-        } else {
-            match apply_import_eagerly(self.import_to_add.as_ref(), &mut text_edit) {
-                Ok(()) => self.import_to_add,
-                Err(()) => {
-                    log::error!("Failed to apply eager import edit: original edit and import edit intersect");
-                    None
-                }
-            }
-        };
-
         CompletionItem {
             source_range: self.source_range,
             label,
@@ -372,7 +358,7 @@ pub(crate) fn build(self) -> CompletionItem {
             trigger_call_info: self.trigger_call_info.unwrap_or(false),
             score: self.score,
             ref_match: self.ref_match,
-            import_to_add,
+            import_to_add: self.import_to_add,
         }
     }
     pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
@@ -435,13 +421,8 @@ pub(crate) fn trigger_call_info(mut self) -> Builder {
         self.trigger_call_info = Some(true);
         self
     }
-    pub(crate) fn add_import(
-        mut self,
-        import_to_add: Option<ImportEdit>,
-        resolve_import_lazily: bool,
-    ) -> Builder {
+    pub(crate) fn add_import(mut self, import_to_add: Option<ImportEdit>) -> Builder {
         self.import_to_add = import_to_add;
-        self.resolve_import_lazily = resolve_import_lazily;
         self
     }
     pub(crate) fn set_ref_match(
@@ -453,16 +434,6 @@ pub(crate) fn set_ref_match(
     }
 }
 
-fn apply_import_eagerly(
-    import_to_add: Option<&ImportEdit>,
-    original_edit: &mut TextEdit,
-) -> Result<(), ()> {
-    match import_to_add.and_then(|import_edit| import_edit.to_text_edit()) {
-        Some(import_edit) => original_edit.union(import_edit).map_err(|_| ()),
-        None => Ok(()),
-    }
-}
-
 impl<'a> Into<CompletionItem> for Builder {
     fn into(self) -> CompletionItem {
         self.build()
index 066d589af89945ef9004036cacc7463af38e9867..8df9f00fe299c287e013713240ecfac2b7aa9e13 100644 (file)
@@ -73,7 +73,7 @@
 // }
 // ```
 //
-// And experimental completions, enabled with the `rust-analyzer.completion.enableExperimental` setting.
+// And experimental completions, enabled with the `rust-analyzer.completion.disableFuzzyAutoimports` setting.
 // This flag enables or disables:
 //
 // - Auto import: additional completion options with automatic `use` import and options from all project importable items, matched for the input
index 9a43480e1a2c44c6c3f96ffa4ea0bafff9bffaad..b940388df26aabbd40dddbeed4f27092763c7ca4 100644 (file)
@@ -190,10 +190,7 @@ fn render_resolution(
                     local_name,
                 )
                 .kind(CompletionItemKind::UnresolvedReference)
-                .add_import(
-                    import_to_add,
-                    self.ctx.completion.config.resolve_additional_edits_lazily(),
-                )
+                .add_import(import_to_add)
                 .build();
                 return Some(item);
             }
@@ -248,7 +245,7 @@ fn render_resolution(
 
         let item = item
             .kind(kind)
-            .add_import(import_to_add, self.ctx.completion.config.resolve_additional_edits_lazily())
+            .add_import(import_to_add)
             .set_documentation(docs)
             .set_ref_match(ref_match)
             .build();
@@ -449,28 +446,6 @@ fn main() { let _: m::Spam = S<|> }
                         insert: "m",
                         kind: Module,
                     },
-                    CompletionItem {
-                        label: "m::Spam",
-                        source_range: 75..76,
-                        text_edit: TextEdit {
-                            indels: [
-                                Indel {
-                                    insert: "use m::Spam;",
-                                    delete: 0..0,
-                                },
-                                Indel {
-                                    insert: "\n\n",
-                                    delete: 0..0,
-                                },
-                                Indel {
-                                    insert: "Spam",
-                                    delete: 75..76,
-                                },
-                            ],
-                        },
-                        kind: Enum,
-                        lookup: "Spam",
-                    },
                     CompletionItem {
                         label: "m::Spam::Foo",
                         source_range: 75..76,
index e979a090b565164cfd2fa9f04992c622761581a8..8e0fea6c0fc5768e6ee2acfa912371f323c371ea 100644 (file)
@@ -71,7 +71,7 @@ fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
         .kind(CompletionItemKind::EnumVariant)
         .set_documentation(self.variant.docs(self.ctx.db()))
         .set_deprecated(self.ctx.is_deprecated(self.variant))
-        .add_import(import_to_add, self.ctx.completion.config.resolve_additional_edits_lazily())
+        .add_import(import_to_add)
         .detail(self.detail());
 
         if self.variant_kind == StructKind::Tuple {
index dd2c999efbc804274398717d8c3c5185cbfdb29d..d16005249c0cee3b2f22f181fa523cfbb3623303 100644 (file)
@@ -47,7 +47,7 @@ fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
             .set_deprecated(self.ctx.is_deprecated(self.func))
             .detail(self.detail())
             .add_call_parens(self.ctx.completion, self.name, params)
-            .add_import(import_to_add, self.ctx.completion.config.resolve_additional_edits_lazily())
+            .add_import(import_to_add)
             .build()
     }
 
index bdbc642ca0240eff52b038ecdbe17e9d2eacb12a..eb3209bee3dcf8e6a599110763e048dd255bcaa6 100644 (file)
@@ -50,10 +50,7 @@ fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
                 .kind(CompletionItemKind::Macro)
                 .set_documentation(self.docs.clone())
                 .set_deprecated(self.ctx.is_deprecated(self.macro_))
-                .add_import(
-                    import_to_add,
-                    self.ctx.completion.config.resolve_additional_edits_lazily(),
-                )
+                .add_import(import_to_add)
                 .detail(self.detail());
 
         let needs_bang = self.needs_bang();
index 4c1b1a83923ac80d00ce3a431ac2de3d104643e5..25f5f4924cd53ee06768135dad297194ec9994e0 100644 (file)
@@ -96,7 +96,16 @@ pub(crate) fn check_edit_with_config(
         .collect_tuple()
         .unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
     let mut actual = db.file_text(position.file_id).to_string();
-    completion.text_edit().apply(&mut actual);
+
+    let mut combined_edit = completion.text_edit().to_owned();
+    if let Some(import_text_edit) = completion.import_to_add().and_then(|edit| edit.to_text_edit())
+    {
+        combined_edit.union(import_text_edit).expect(
+            "Failed to apply completion resolve changes: change ranges overlap, but should not",
+        )
+    }
+
+    combined_edit.apply(&mut actual);
     assert_eq_text!(&ra_fixture_after, &actual)
 }
 
index 09046d3c36a8dad72bfd1cf3bc7d8cad9d8071c4..31151ce242d1b1a02c72e6fb25209ae4675a0548 100644 (file)
@@ -35,26 +35,16 @@ pub fn find_similar_imports<'a>(
     sema: &Semantics<'a, RootDatabase>,
     krate: Crate,
     name_to_import: &str,
-    limit: usize,
     ignore_modules: bool,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_similar_imports");
 
-    let mut external_query = import_map::Query::new(name_to_import).limit(limit);
+    let mut external_query = import_map::Query::new(name_to_import);
     if ignore_modules {
         external_query = external_query.exclude_import_kind(import_map::ImportKind::Module);
     }
 
-    find_imports(
-        sema,
-        krate,
-        {
-            let mut local_query = symbol_index::Query::new(name_to_import.to_string());
-            local_query.limit(limit);
-            local_query
-        },
-        external_query,
-    )
+    find_imports(sema, krate, symbol_index::Query::new(name_to_import.to_string()), external_query)
 }
 
 fn find_imports<'a>(
index f00605258b88f4fdad9ce16ecdf98283d4c78e89..f46aa2dd4b7ec343a63a614c02b3a7eaf3782412 100644 (file)
@@ -182,7 +182,7 @@ pub fn new(root_path: AbsPathBuf) -> Self {
             },
             completion: CompletionConfig {
                 enable_postfix_completions: true,
-                enable_experimental_completions: true,
+                disable_fuzzy_autoimports: false,
                 add_call_parenthesis: true,
                 add_call_argument_snippets: true,
                 ..CompletionConfig::default()
@@ -305,7 +305,7 @@ pub fn update(&mut self, json: serde_json::Value) {
         };
 
         self.completion.enable_postfix_completions = data.completion_postfix_enable;
-        self.completion.enable_experimental_completions = data.completion_enableExperimental;
+        self.completion.disable_fuzzy_autoimports = data.completion_disableFuzzyAutoimports;
         self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
         self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;
         self.completion.merge = self.assist.insert_use.merge;
@@ -508,7 +508,7 @@ struct ConfigData {
         completion_addCallArgumentSnippets: bool = true,
         completion_addCallParenthesis: bool      = true,
         completion_postfix_enable: bool          = true,
-        completion_enableExperimental: bool      = true,
+        completion_disableFuzzyAutoimports: bool = false,
 
         diagnostics_enable: bool                = true,
         diagnostics_enableExperimental: bool    = true,
index af228f98370435f1e705281e77df5929ea3fb1a0..4b0f41a243dae4458cdaedb2b2bf9d9ac0744b45 100644 (file)
                     "default": true,
                     "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc."
                 },
-                "rust-analyzer.completion.enableExperimental": {
+                "rust-analyzer.completion.disableFuzzyAutoimports": {
                     "type": "boolean",
-                    "default": true,
-                    "markdownDescription": "Display additional completions with potential false positives and performance issues"
+                    "default": false,
+                    "markdownDescription": "Turns off extra completion suggestions that might be too noisy or slow"
                 },
                 "rust-analyzer.callInfo.full": {
                     "type": "boolean",