From ee99620754cdcfbab28a2c067dfa31087376d6c3 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sat, 14 Nov 2020 01:26:31 +0200 Subject: [PATCH] Move autoimport completion into the unqialified_path module --- crates/completion/Cargo.toml | 1 - crates/completion/src/completions.rs | 1 - crates/completion/src/completions/magic.rs | 151 ------------------ .../src/completions/unqualified_path.rs | 141 +++++++++++++++- crates/completion/src/lib.rs | 1 - 5 files changed, 139 insertions(+), 156 deletions(-) delete mode 100644 crates/completion/src/completions/magic.rs diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 799b4a3d54..e7df9d9556 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml @@ -22,7 +22,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" } base_db = { path = "../base_db", version = "0.0.0" } ide_db = { path = "../ide_db", version = "0.0.0" } profile = { path = "../profile", version = "0.0.0" } -assists = { path = "../assists", version = "0.0.0" } test_utils = { path = "../test_utils", version = "0.0.0" } # completions crate should depend only on the top-level `hir` package. if you need diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 4abb101564..75dbb1a23b 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs @@ -13,7 +13,6 @@ pub(crate) mod postfix; pub(crate) mod macro_in_item_position; pub(crate) mod trait_impl; pub(crate) mod mod_; -pub(crate) mod magic; use hir::{ModPath, ScopeDef, Type}; diff --git a/crates/completion/src/completions/magic.rs b/crates/completion/src/completions/magic.rs deleted file mode 100644 index 0c4db01990..0000000000 --- a/crates/completion/src/completions/magic.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! TODO kb move this into the complete_unqualified_path when starts to work properly - -use assists::utils::{insert_use, mod_path_to_ast, ImportScope}; -use either::Either; -use hir::{ModuleDef, ScopeDef}; -use ide_db::imports_locator; -use syntax::{algo, AstNode}; - -use crate::{ - context::CompletionContext, - render::{render_resolution, RenderContext}, -}; - -use super::Completions; - -// TODO kb add a setting toggle for this feature? -pub(crate) fn complete_magic(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { - if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { - return None; - } - let _p = profile::span("complete_magic"); - 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, 400) - .filter_map(|import_candidate| match import_candidate { - // when completing outside the use declaration, modules are pretty useless - // and tend to bloat the completion suggestions a lot - Either::Left(ModuleDef::Module(_)) => None, - Either::Left(module_def) => Some(( - current_module.find_use_path(ctx.db, module_def)?, - ScopeDef::ModuleDef(module_def), - )), - Either::Right(macro_def) => Some(( - current_module.find_use_path(ctx.db, macro_def)?, - ScopeDef::MacroDef(macro_def), - )), - }) - .filter_map(|(mod_path, definition)| { - let mut resolution_with_missing_import = render_resolution( - RenderContext::new(ctx), - mod_path.segments.last()?.to_string(), - &definition, - )?; - - let mut text_edits = - resolution_with_missing_import.text_edit().to_owned().into_builder(); - - let rewriter = - insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge); - let old_ast = rewriter.rewrite_root()?; - algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits); - - resolution_with_missing_import.update_text_edit(text_edits.finish()); - - Some(resolution_with_missing_import) - }); - - acc.add_all(possible_imports); - Some(()) -} - -#[cfg(test)] -mod tests { - use crate::test_utils::check_edit; - - #[test] - fn function_magic_completion() { - check_edit( - "stdin", - r#" -//- /lib.rs crate:dep -pub mod io { - pub fn stdin() {} -}; - -//- /main.rs crate:main deps:dep -fn main() { - stdi<|> -} -"#, - r#" -use dep::io::stdin; - -fn main() { - stdin()$0 -} -"#, - ); - } - - #[test] - fn macro_magic_completion() { - check_edit( - "macro_with_curlies!", - r#" -//- /lib.rs crate:dep -/// Please call me as macro_with_curlies! {} -#[macro_export] -macro_rules! macro_with_curlies { - () => {} -} - -//- /main.rs crate:main deps:dep -fn main() { - curli<|> -} -"#, - r#" -use dep::macro_with_curlies; - -fn main() { - macro_with_curlies! {$0} -} -"#, - ); - } - - #[test] - fn case_insensitive_magic_completion_works() { - 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 -} -"#, - ); - } -} diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 7df58e1da8..ecda37862e 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs @@ -1,10 +1,16 @@ //! Completion of names from the current scope, e.g. locals and imported items. +use assists::utils::{insert_use, mod_path_to_ast, ImportScope}; +use either::Either; use hir::{Adt, ModuleDef, ScopeDef, Type}; -use syntax::AstNode; +use ide_db::imports_locator; +use syntax::{algo, AstNode}; use test_utils::mark; -use crate::{CompletionContext, Completions}; +use crate::{ + render::{render_resolution, RenderContext}, + CompletionContext, Completions, +}; pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { @@ -37,6 +43,56 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC } acc.add_resolution(ctx, name.to_string(), &res) }); + + fuzzy_completion(acc, ctx).unwrap_or_default() +} + +// TODO kb add a setting toggle for this feature? +fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { + let _p = profile::span("fuzzy_completion®"); + 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, 400) + .filter_map(|import_candidate| match import_candidate { + // when completing outside the use declaration, modules are pretty useless + // and tend to bloat the completion suggestions a lot + Either::Left(ModuleDef::Module(_)) => None, + Either::Left(module_def) => Some(( + current_module.find_use_path(ctx.db, module_def)?, + ScopeDef::ModuleDef(module_def), + )), + Either::Right(macro_def) => Some(( + current_module.find_use_path(ctx.db, macro_def)?, + ScopeDef::MacroDef(macro_def), + )), + }) + .filter_map(|(mod_path, definition)| { + let mut resolution_with_missing_import = render_resolution( + RenderContext::new(ctx), + mod_path.segments.last()?.to_string(), + &definition, + )?; + + let mut text_edits = + resolution_with_missing_import.text_edit().to_owned().into_builder(); + + let rewriter = + insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge); + let old_ast = rewriter.rewrite_root()?; + algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits); + + resolution_with_missing_import.update_text_edit(text_edits.finish()); + + Some(resolution_with_missing_import) + }); + + acc.add_all(possible_imports); + Some(()) } fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { @@ -676,4 +732,85 @@ impl My<|> "#]], ) } + + #[test] + fn function_magic_completion() { + check_edit( + "stdin", + r#" +//- /lib.rs crate:dep +pub mod io { + pub fn stdin() {} +}; + +//- /main.rs crate:main deps:dep +fn main() { + stdi<|> +} +"#, + r#" +use dep::io::stdin; + +fn main() { + stdin()$0 +} +"#, + ); + } + + #[test] + fn macro_magic_completion() { + check_edit( + "macro_with_curlies!", + r#" +//- /lib.rs crate:dep +/// Please call me as macro_with_curlies! {} +#[macro_export] +macro_rules! macro_with_curlies { + () => {} +} + +//- /main.rs crate:main deps:dep +fn main() { + curli<|> +} +"#, + r#" +use dep::macro_with_curlies; + +fn main() { + macro_with_curlies! {$0} +} +"#, + ); + } + + #[test] + fn case_insensitive_magic_completion_works() { + 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 +} +"#, + ); + } } diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index 8323af8b28..cb6e0554e9 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs @@ -118,7 +118,6 @@ pub fn completions( completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); completions::trait_impl::complete_trait_impl(&mut acc, &ctx); completions::mod_::complete_mod(&mut acc, &ctx); - completions::magic::complete_magic(&mut acc, &ctx); Some(acc) }