aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2020-11-24 00:26:16 +0000
committerKirill Bulatov <[email protected]>2020-11-24 00:28:45 +0000
commit4baac238a8343d7c5ced58603bf122c66cbf8c82 (patch)
treeeb898d8429aafb3b19e356089bed57994fbbe015 /crates
parent036ea6317c7e0a48acafcdcf8ece3a4816fa4036 (diff)
Improve autoimports on completion speed
* Ignore modules eaferly * Do less completion string rendering
Diffstat (limited to 'crates')
-rw-r--r--crates/completion/src/completions/unqualified_path.rs54
-rw-r--r--crates/completion/src/render.rs1
-rw-r--r--crates/hir_def/src/import_map.rs82
-rw-r--r--crates/ide_db/src/imports_locator.rs9
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};
7use hir_expand::name::Name; 7use hir_expand::name::Name;
8use indexmap::{map::Entry, IndexMap}; 8use indexmap::{map::Entry, IndexMap};
9use itertools::Itertools; 9use itertools::Itertools;
10use rustc_hash::{FxHashMap, FxHasher}; 10use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
11use smallvec::SmallVec; 11use smallvec::SmallVec;
12use syntax::SmolStr; 12use 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)]
229pub 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)]
229pub struct Query { 242pub 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
237impl Query { 251impl 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
372fn 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)]
345mod tests { 387mod 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