diff options
author | Kirill Bulatov <[email protected]> | 2020-11-24 00:26:16 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-11-24 00:28:45 +0000 |
commit | 4baac238a8343d7c5ced58603bf122c66cbf8c82 (patch) | |
tree | eb898d8429aafb3b19e356089bed57994fbbe015 | |
parent | 036ea6317c7e0a48acafcdcf8ece3a4816fa4036 (diff) |
Improve autoimports on completion speed
* Ignore modules eaferly
* Do less completion string rendering
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 54 | ||||
-rw-r--r-- | crates/completion/src/render.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/import_map.rs | 82 | ||||
-rw-r--r-- | crates/ide_db/src/imports_locator.rs | 9 |
4 files changed, 114 insertions, 32 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 86c143b63..f452c98e4 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -79,32 +79,34 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
79 | 79 | ||
80 | let potential_import_name = ctx.token.to_string(); | 80 | let potential_import_name = ctx.token.to_string(); |
81 | 81 | ||
82 | let possible_imports = | 82 | let possible_imports = imports_locator::find_similar_imports( |
83 | imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, 400) | 83 | &ctx.sema, |
84 | .filter_map(|import_candidate| match import_candidate { | 84 | ctx.krate?, |
85 | // when completing outside the use declaration, modules are pretty useless | 85 | &potential_import_name, |
86 | // and tend to bloat the completion suggestions a lot | 86 | 50, |
87 | Either::Left(ModuleDef::Module(_)) => None, | 87 | true, |
88 | Either::Left(module_def) => Some(( | 88 | ) |
89 | current_module.find_use_path(ctx.db, module_def)?, | 89 | .filter_map(|import_candidate| { |
90 | ScopeDef::ModuleDef(module_def), | 90 | Some(match import_candidate { |
91 | )), | 91 | Either::Left(module_def) => { |
92 | Either::Right(macro_def) => Some(( | 92 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) |
93 | current_module.find_use_path(ctx.db, macro_def)?, | 93 | } |
94 | ScopeDef::MacroDef(macro_def), | 94 | Either::Right(macro_def) => { |
95 | )), | 95 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) |
96 | }) | 96 | } |
97 | .filter(|(mod_path, _)| mod_path.len() > 1) | 97 | }) |
98 | .filter_map(|(import_path, definition)| { | 98 | }) |
99 | render_resolution_with_import( | 99 | .filter(|(mod_path, _)| mod_path.len() > 1) |
100 | RenderContext::new(ctx), | 100 | .take(20) |
101 | import_path.clone(), | 101 | .filter_map(|(import_path, definition)| { |
102 | import_scope.clone(), | 102 | render_resolution_with_import( |
103 | ctx.config.merge, | 103 | RenderContext::new(ctx), |
104 | &definition, | 104 | import_path.clone(), |
105 | ) | 105 | import_scope.clone(), |
106 | }) | 106 | ctx.config.merge, |
107 | .take(20); | 107 | &definition, |
108 | ) | ||
109 | }); | ||
108 | 110 | ||
109 | acc.add_all(possible_imports); | 111 | acc.add_all(possible_imports); |
110 | Some(()) | 112 | Some(()) |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index e892d4de8..bce02f577 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -150,6 +150,7 @@ impl<'a> Render<'a> { | |||
150 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | 150 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, |
151 | resolution: &ScopeDef, | 151 | resolution: &ScopeDef, |
152 | ) -> Option<CompletionItem> { | 152 | ) -> Option<CompletionItem> { |
153 | let _p = profile::span("render_resolution"); | ||
153 | use hir::ModuleDef::*; | 154 | use hir::ModuleDef::*; |
154 | 155 | ||
155 | let completion_kind = match resolution { | 156 | let completion_kind = match resolution { |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 1e24f29a8..c0f108848 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -7,7 +7,7 @@ use fst::{self, Streamer}; | |||
7 | use hir_expand::name::Name; | 7 | use hir_expand::name::Name; |
8 | use indexmap::{map::Entry, IndexMap}; | 8 | use indexmap::{map::Entry, IndexMap}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use rustc_hash::{FxHashMap, FxHasher}; | 10 | use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; |
11 | use smallvec::SmallVec; | 11 | use smallvec::SmallVec; |
12 | use syntax::SmolStr; | 12 | use syntax::SmolStr; |
13 | 13 | ||
@@ -225,6 +225,19 @@ fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) | |||
225 | lhs_str.cmp(&rhs_str) | 225 | lhs_str.cmp(&rhs_str) |
226 | } | 226 | } |
227 | 227 | ||
228 | #[derive(Debug, Eq, PartialEq, Hash)] | ||
229 | pub enum ImportKind { | ||
230 | Module, | ||
231 | Function, | ||
232 | Adt, | ||
233 | EnumVariant, | ||
234 | Const, | ||
235 | Static, | ||
236 | Trait, | ||
237 | TypeAlias, | ||
238 | BuiltinType, | ||
239 | } | ||
240 | |||
228 | #[derive(Debug)] | 241 | #[derive(Debug)] |
229 | pub struct Query { | 242 | pub struct Query { |
230 | query: String, | 243 | query: String, |
@@ -232,6 +245,7 @@ pub struct Query { | |||
232 | anchor_end: bool, | 245 | anchor_end: bool, |
233 | case_sensitive: bool, | 246 | case_sensitive: bool, |
234 | limit: usize, | 247 | limit: usize, |
248 | exclude_import_kinds: FxHashSet<ImportKind>, | ||
235 | } | 249 | } |
236 | 250 | ||
237 | impl Query { | 251 | impl Query { |
@@ -242,6 +256,7 @@ impl Query { | |||
242 | anchor_end: false, | 256 | anchor_end: false, |
243 | case_sensitive: false, | 257 | case_sensitive: false, |
244 | limit: usize::max_value(), | 258 | limit: usize::max_value(), |
259 | exclude_import_kinds: FxHashSet::default(), | ||
245 | } | 260 | } |
246 | } | 261 | } |
247 | 262 | ||
@@ -260,6 +275,12 @@ impl Query { | |||
260 | pub fn case_sensitive(self) -> Self { | 275 | pub fn case_sensitive(self) -> Self { |
261 | Self { case_sensitive: true, ..self } | 276 | Self { case_sensitive: true, ..self } |
262 | } | 277 | } |
278 | |||
279 | /// Do not include imports of the specified kind in the search results. | ||
280 | pub fn exclude_import_kind(mut self, import_kind: ImportKind) -> Self { | ||
281 | self.exclude_import_kinds.insert(import_kind); | ||
282 | self | ||
283 | } | ||
263 | } | 284 | } |
264 | 285 | ||
265 | /// Searches dependencies of `krate` for an importable path matching `query`. | 286 | /// Searches dependencies of `krate` for an importable path matching `query`. |
@@ -303,10 +324,17 @@ pub fn search_dependencies<'a>( | |||
303 | 324 | ||
304 | // Add the items from this `ModPath` group. Those are all subsequent items in | 325 | // Add the items from this `ModPath` group. Those are all subsequent items in |
305 | // `importables` whose paths match `path`. | 326 | // `importables` whose paths match `path`. |
306 | let iter = importables.iter().copied().take_while(|item| { | 327 | let iter = importables |
307 | let item_path = &import_map.map[item].path; | 328 | .iter() |
308 | fst_path(item_path) == fst_path(path) | 329 | .copied() |
309 | }); | 330 | .take_while(|item| { |
331 | let item_path = &import_map.map[item].path; | ||
332 | fst_path(item_path) == fst_path(path) | ||
333 | }) | ||
334 | .filter(|&item| match item_import_kind(item) { | ||
335 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), | ||
336 | None => true, | ||
337 | }); | ||
310 | 338 | ||
311 | if query.case_sensitive { | 339 | if query.case_sensitive { |
312 | // FIXME: This does not do a subsequence match. | 340 | // FIXME: This does not do a subsequence match. |
@@ -341,6 +369,20 @@ pub fn search_dependencies<'a>( | |||
341 | res | 369 | res |
342 | } | 370 | } |
343 | 371 | ||
372 | fn item_import_kind(item: ItemInNs) -> Option<ImportKind> { | ||
373 | Some(match item.as_module_def_id()? { | ||
374 | ModuleDefId::ModuleId(_) => ImportKind::Module, | ||
375 | ModuleDefId::FunctionId(_) => ImportKind::Function, | ||
376 | ModuleDefId::AdtId(_) => ImportKind::Adt, | ||
377 | ModuleDefId::EnumVariantId(_) => ImportKind::EnumVariant, | ||
378 | ModuleDefId::ConstId(_) => ImportKind::Const, | ||
379 | ModuleDefId::StaticId(_) => ImportKind::Static, | ||
380 | ModuleDefId::TraitId(_) => ImportKind::Trait, | ||
381 | ModuleDefId::TypeAliasId(_) => ImportKind::TypeAlias, | ||
382 | ModuleDefId::BuiltinType(_) => ImportKind::BuiltinType, | ||
383 | }) | ||
384 | } | ||
385 | |||
344 | #[cfg(test)] | 386 | #[cfg(test)] |
345 | mod tests { | 387 | mod tests { |
346 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; | 388 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; |
@@ -758,4 +800,34 @@ mod tests { | |||
758 | "#]], | 800 | "#]], |
759 | ); | 801 | ); |
760 | } | 802 | } |
803 | |||
804 | #[test] | ||
805 | fn search_exclusions() { | ||
806 | let ra_fixture = r#" | ||
807 | //- /main.rs crate:main deps:dep | ||
808 | //- /dep.rs crate:dep | ||
809 | |||
810 | pub struct fmt; | ||
811 | pub struct FMT; | ||
812 | "#; | ||
813 | |||
814 | check_search( | ||
815 | ra_fixture, | ||
816 | "main", | ||
817 | Query::new("FMT"), | ||
818 | expect![[r#" | ||
819 | dep::fmt (t) | ||
820 | dep::fmt (v) | ||
821 | dep::FMT (t) | ||
822 | dep::FMT (v) | ||
823 | "#]], | ||
824 | ); | ||
825 | |||
826 | check_search( | ||
827 | ra_fixture, | ||
828 | "main", | ||
829 | Query::new("FMT").exclude_import_kind(ImportKind::Adt), | ||
830 | expect![[r#""#]], | ||
831 | ); | ||
832 | } | ||
761 | } | 833 | } |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index 9d8ea7368..09046d3c3 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -36,8 +36,15 @@ pub fn find_similar_imports<'a>( | |||
36 | krate: Crate, | 36 | krate: Crate, |
37 | name_to_import: &str, | 37 | name_to_import: &str, |
38 | limit: usize, | 38 | limit: usize, |
39 | ignore_modules: bool, | ||
39 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 40 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
40 | let _p = profile::span("find_similar_imports"); | 41 | let _p = profile::span("find_similar_imports"); |
42 | |||
43 | let mut external_query = import_map::Query::new(name_to_import).limit(limit); | ||
44 | if ignore_modules { | ||
45 | external_query = external_query.exclude_import_kind(import_map::ImportKind::Module); | ||
46 | } | ||
47 | |||
41 | find_imports( | 48 | find_imports( |
42 | sema, | 49 | sema, |
43 | krate, | 50 | krate, |
@@ -46,7 +53,7 @@ pub fn find_similar_imports<'a>( | |||
46 | local_query.limit(limit); | 53 | local_query.limit(limit); |
47 | local_query | 54 | local_query |
48 | }, | 55 | }, |
49 | import_map::Query::new(name_to_import).limit(limit), | 56 | external_query, |
50 | ) | 57 | ) |
51 | } | 58 | } |
52 | 59 | ||