Skip to content

Commit 156f7d6

Browse files
Merge #6553
6553: Auto imports in completion r=matklad a=SomeoneToIgnore ![completion](https://user-images.githubusercontent.com/2690773/99155339-ae4fb380-26bf-11eb-805a-655b1706ce70.gif) Closes #1062 but does not handle the completion order, since it's a separate task for #4922 , #4922 and maybe something else. 2 quirks in the current implementation: * traits are not auto imported during method completion If I understand the current situation right, we cannot search for traits by a **part** of a method name, we need a full name with correct case to get a trait for it. * VSCode (?) autocompletion is not as rigid as in Intellij Rust as you can notice on the animation. Intellij is able to refresh the completions on every new symbol added, yet VS Code does not query the completions on every symbol for me. With a few debug prints placed in RA, I've observed the following behaviour: after the first set of completion suggestions is received, next symbol input does not trigger a server request, if the completions contain this symbol. When more symbols added, the existing completion suggestions are filtered out until none are left and only then, on the next symbol it queries for completions. It seems like the only alternative to get an updated set of results is to manually retrigger it with Esc and Ctrl + Space. Despite the eerie latter bullet, the completion seems to work pretty fine and fast nontheless, but if you have any ideas on how to make it more smooth, I'll gladly try it out. Co-authored-by: Kirill Bulatov <[email protected]>
2 parents f4b4f17 + 16f0b2f commit 156f7d6

22 files changed

+369
-96
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/assists/src/handlers/auto_import.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
9898

9999
let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range;
100100
let group = import_group_message(import_assets.import_candidate());
101-
let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?;
101+
let scope =
102+
ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?;
102103
for (import, _) in proposed_imports {
103104
acc.add_group(
104105
&group,

crates/assists/src/handlers/extract_struct_from_enum_variant.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ fn insert_import(
143143
if let Some(mut mod_path) = mod_path {
144144
mod_path.segments.pop();
145145
mod_path.segments.push(variant_hir_name.clone());
146-
let scope = ImportScope::find_insert_use_container(scope_node, ctx)?;
147-
146+
let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
148147
*rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge);
149148
}
150149
Some(())

crates/assists/src/handlers/replace_derive_with_manual_impl.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,21 @@ pub(crate) fn replace_derive_with_manual_impl(
6262
let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
6363
let current_crate = current_module.krate();
6464

65-
let found_traits = imports_locator::find_imports(&ctx.sema, current_crate, trait_token.text())
66-
.into_iter()
67-
.filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
68-
either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
69-
_ => None,
70-
})
71-
.flat_map(|trait_| {
72-
current_module
73-
.find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
74-
.as_ref()
75-
.map(mod_path_to_ast)
76-
.zip(Some(trait_))
77-
});
65+
let found_traits =
66+
imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text())
67+
.filter_map(
68+
|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
69+
either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
70+
_ => None,
71+
},
72+
)
73+
.flat_map(|trait_| {
74+
current_module
75+
.find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
76+
.as_ref()
77+
.map(mod_path_to_ast)
78+
.zip(Some(trait_))
79+
});
7880

7981
let mut no_traits_found = true;
8082
for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {

crates/assists/src/handlers/replace_qualified_name_with_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub(crate) fn replace_qualified_name_with_use(
3434
}
3535

3636
let target = path.syntax().text_range();
37-
let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
37+
let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
3838
let syntax = scope.as_syntax_node();
3939
acc.add(
4040
AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),

crates/assists/src/utils.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ use crate::{
2222
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
2323
};
2424

25-
pub use insert_use::MergeBehaviour;
26-
pub(crate) use insert_use::{insert_use, ImportScope};
25+
pub use insert_use::{insert_use, ImportScope, MergeBehaviour};
2726

2827
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
2928
let mut segments = Vec::new();

crates/assists/src/utils/import_assets.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -179,21 +179,25 @@ impl ImportAssets {
179179
}
180180
};
181181

182-
let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query())
183-
.into_iter()
184-
.filter_map(filter)
185-
.filter_map(|candidate| {
186-
let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
187-
if let Some(prefix_kind) = prefixed {
188-
self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind)
189-
} else {
190-
self.module_with_name_to_import.find_use_path(db, item)
191-
}
192-
.map(|path| (path, item))
193-
})
194-
.filter(|(use_path, _)| !use_path.segments.is_empty())
195-
.take(20)
196-
.collect::<Vec<_>>();
182+
let mut res =
183+
imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query())
184+
.filter_map(filter)
185+
.filter_map(|candidate| {
186+
let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
187+
if let Some(prefix_kind) = prefixed {
188+
self.module_with_name_to_import.find_use_path_prefixed(
189+
db,
190+
item,
191+
prefix_kind,
192+
)
193+
} else {
194+
self.module_with_name_to_import.find_use_path(db, item)
195+
}
196+
.map(|path| (path, item))
197+
})
198+
.filter(|(use_path, _)| use_path.len() > 1)
199+
.take(20)
200+
.collect::<Vec<_>>();
197201
res.sort_by_key(|(path, _)| path.clone());
198202
res
199203
}

crates/assists/src/utils/insert_use.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Handle syntactic aspects of inserting a new `use`.
22
use std::{cmp::Ordering, iter::successors};
33

4+
use hir::Semantics;
5+
use ide_db::RootDatabase;
46
use itertools::{EitherOrBoth, Itertools};
57
use syntax::{
68
algo::SyntaxRewriter,
@@ -13,8 +15,8 @@ use syntax::{
1315
};
1416
use test_utils::mark;
1517

16-
#[derive(Debug)]
17-
pub(crate) enum ImportScope {
18+
#[derive(Debug, Clone)]
19+
pub enum ImportScope {
1820
File(ast::SourceFile),
1921
Module(ast::ItemList),
2022
}
@@ -31,14 +33,14 @@ impl ImportScope {
3133
}
3234

3335
/// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
34-
pub(crate) fn find_insert_use_container(
36+
pub fn find_insert_use_container(
3537
position: &SyntaxNode,
36-
ctx: &crate::assist_context::AssistContext,
38+
sema: &Semantics<'_, RootDatabase>,
3739
) -> Option<Self> {
38-
ctx.sema.ancestors_with_macros(position.clone()).find_map(Self::from)
40+
sema.ancestors_with_macros(position.clone()).find_map(Self::from)
3941
}
4042

41-
pub(crate) fn as_syntax_node(&self) -> &SyntaxNode {
43+
pub fn as_syntax_node(&self) -> &SyntaxNode {
4244
match self {
4345
ImportScope::File(file) => file.syntax(),
4446
ImportScope::Module(item_list) => item_list.syntax(),
@@ -88,7 +90,7 @@ fn is_inner_comment(token: SyntaxToken) -> bool {
8890
}
8991

9092
/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
91-
pub(crate) fn insert_use<'a>(
93+
pub fn insert_use<'a>(
9294
scope: &ImportScope,
9395
path: ast::Path,
9496
merge: Option<MergeBehaviour>,

crates/completion/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ doctest = false
1313
itertools = "0.9.0"
1414
log = "0.4.8"
1515
rustc-hash = "1.1.0"
16+
either = "1.6.1"
1617

1718
assists = { path = "../assists", version = "0.0.0" }
1819
stdx = { path = "../stdx", version = "0.0.0" }

crates/completion/src/completions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl Completions {
9090
Some(it) => it,
9191
None => return,
9292
};
93-
if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) {
93+
if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) {
9494
self.add(item);
9595
}
9696
}
@@ -101,7 +101,7 @@ impl Completions {
101101
func: hir::Function,
102102
local_name: Option<String>,
103103
) {
104-
let item = render_fn(RenderContext::new(ctx), local_name, func);
104+
let item = render_fn(RenderContext::new(ctx), None, local_name, func);
105105
self.add(item)
106106
}
107107

@@ -123,7 +123,7 @@ impl Completions {
123123
variant: hir::EnumVariant,
124124
path: ModPath,
125125
) {
126-
let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path));
126+
let item = render_enum_variant(RenderContext::new(ctx), None, None, variant, Some(path));
127127
self.add(item);
128128
}
129129

@@ -133,7 +133,7 @@ impl Completions {
133133
variant: hir::EnumVariant,
134134
local_name: Option<String>,
135135
) {
136-
let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None);
136+
let item = render_enum_variant(RenderContext::new(ctx), None, local_name, variant, None);
137137
self.add(item);
138138
}
139139
}

0 commit comments

Comments
 (0)