aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-21 09:51:06 +0000
committerGitHub <[email protected]>2021-03-21 09:51:06 +0000
commit0d40ff5e623b3670ce3e0e324ecbab3e5197aaeb (patch)
treeb376f04aa3bd91eb13007e1a334327a45e45753c
parent09412d85fc3137d6ada3b27170e14c287f1a1191 (diff)
parentb17d99c0706674c7549aca4670f915aa0b0e2f4e (diff)
Merge #8131
8131: Do smart case fuzzy search during flyimports r=SomeoneToIgnore a=SomeoneToIgnore For now, last actionable part of https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/autoimport.20weirdness Should help https://github.com/rust-analyzer/rust-analyzer/issues/7902 Now during the flyimport completion, if the input is searched case-sensitively, if the input contains any non-lowercase letters; otherwise the lookup done as before, case-insensitively. Co-authored-by: Kirill Bulatov <[email protected]>
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs1
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs61
-rw-r--r--crates/ide_completion/src/lib.rs1
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs3
-rw-r--r--crates/ide_db/src/items_locator.rs39
-rw-r--r--crates/ide_db/src/symbol_index.rs16
6 files changed, 93 insertions, 28 deletions
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index 2608b56da..4f0ef52ca 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -72,7 +72,6 @@ pub(crate) fn replace_derive_with_manual_impl(
72 items_locator::AssocItemSearch::Exclude, 72 items_locator::AssocItemSearch::Exclude,
73 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT), 73 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
74 ) 74 )
75 .into_iter()
76 .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) { 75 .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
77 ModuleDef::Trait(trait_) => Some(trait_), 76 ModuleDef::Trait(trait_) => Some(trait_),
78 _ => None, 77 _ => None,
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index eb2cba631..1ad017198 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,8 +1,10 @@
1//! Feature: completion with imports-on-the-fly 1//! Feature: completion with imports-on-the-fly
2//! 2//!
3//! When completing names in the current scope, proposes additional imports from other modules or crates, 3//! When completing names in the current scope, proposes additional imports from other modules or crates,
4//! if they can be qualified in the scope and their name contains all symbols from the completion input 4//! if they can be qualified in the scope and their name contains all symbols from the completion input.
5//! (case-insensitive, in any order or places). 5//!
6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively.
6//! 8//!
7//! ``` 9//! ```
8//! fn main() { 10//! fn main() {
@@ -942,7 +944,7 @@ mod foo {
942} 944}
943 945
944fn main() { 946fn main() {
945 bar::Ass$0 947 bar::ASS$0
946}"#, 948}"#,
947 expect![[]], 949 expect![[]],
948 ) 950 )
@@ -979,4 +981,57 @@ fn main() {
979 expect![[]], 981 expect![[]],
980 ) 982 )
981 } 983 }
984
985 #[test]
986 fn case_matters() {
987 check(
988 r#"
989mod foo {
990 pub const TEST_CONST: usize = 3;
991 pub fn test_function() -> i32 {
992 4
993 }
994}
995
996fn main() {
997 TE$0
998}"#,
999 expect![[r#"
1000 ct foo::TEST_CONST
1001 "#]],
1002 );
1003
1004 check(
1005 r#"
1006mod foo {
1007 pub const TEST_CONST: usize = 3;
1008 pub fn test_function() -> i32 {
1009 4
1010 }
1011}
1012
1013fn main() {
1014 te$0
1015}"#,
1016 expect![[r#"
1017 ct foo::TEST_CONST
1018 fn test_function() (foo::test_function) fn() -> i32
1019 "#]],
1020 );
1021
1022 check(
1023 r#"
1024mod foo {
1025 pub const TEST_CONST: usize = 3;
1026 pub fn test_function() -> i32 {
1027 4
1028 }
1029}
1030
1031fn main() {
1032 Te$0
1033}"#,
1034 expect![[]],
1035 );
1036 }
982} 1037}
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 87cddb98e..5ac1cb48d 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -161,7 +161,6 @@ pub fn resolve_completion_edits(
161 items_locator::AssocItemSearch::Include, 161 items_locator::AssocItemSearch::Include,
162 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT), 162 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
163 ) 163 )
164 .into_iter()
165 .filter_map(|candidate| { 164 .filter_map(|candidate| {
166 current_module 165 current_module
167 .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) 166 .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 0da7a1a9d..1881c746f 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -267,7 +267,6 @@ fn path_applicable_imports(
267 AssocItemSearch::Exclude, 267 AssocItemSearch::Exclude,
268 Some(DEFAULT_QUERY_SEARCH_LIMIT), 268 Some(DEFAULT_QUERY_SEARCH_LIMIT),
269 ) 269 )
270 .into_iter()
271 .filter_map(|item| { 270 .filter_map(|item| {
272 let mod_path = mod_path(item)?; 271 let mod_path = mod_path(item)?;
273 Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path))) 272 Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
@@ -285,7 +284,6 @@ fn path_applicable_imports(
285 AssocItemSearch::Include, 284 AssocItemSearch::Include,
286 Some(DEFAULT_QUERY_SEARCH_LIMIT), 285 Some(DEFAULT_QUERY_SEARCH_LIMIT),
287 ) 286 )
288 .into_iter()
289 .filter_map(|item| { 287 .filter_map(|item| {
290 import_for_item( 288 import_for_item(
291 sema.db, 289 sema.db,
@@ -430,7 +428,6 @@ fn trait_applicable_items(
430 AssocItemSearch::AssocItemsOnly, 428 AssocItemSearch::AssocItemsOnly,
431 Some(DEFAULT_QUERY_SEARCH_LIMIT), 429 Some(DEFAULT_QUERY_SEARCH_LIMIT),
432 ) 430 )
433 .into_iter()
434 .filter_map(|input| item_as_assoc(db, input)) 431 .filter_map(|input| item_as_assoc(db, input))
435 .filter_map(|assoc| { 432 .filter_map(|assoc| {
436 let assoc_item_trait = assoc.containing_trait(db)?; 433 let assoc_item_trait = assoc.containing_trait(db)?;
diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs
index 518cddd74..ef796b6f7 100644
--- a/crates/ide_db/src/items_locator.rs
+++ b/crates/ide_db/src/items_locator.rs
@@ -15,7 +15,6 @@ use crate::{
15 symbol_index::{self, FileSymbol}, 15 symbol_index::{self, FileSymbol},
16 RootDatabase, 16 RootDatabase,
17}; 17};
18use rustc_hash::FxHashSet;
19 18
20/// A value to use, when uncertain which limit to pick. 19/// A value to use, when uncertain which limit to pick.
21pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; 20pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40;
@@ -32,16 +31,16 @@ pub enum AssocItemSearch {
32} 31}
33 32
34/// Searches for importable items with the given name in the crate and its dependencies. 33/// Searches for importable items with the given name in the crate and its dependencies.
35pub fn items_with_name( 34pub fn items_with_name<'a>(
36 sema: &Semantics<'_, RootDatabase>, 35 sema: &'a Semantics<'_, RootDatabase>,
37 krate: Crate, 36 krate: Crate,
38 name: NameToImport, 37 name: NameToImport,
39 assoc_item_search: AssocItemSearch, 38 assoc_item_search: AssocItemSearch,
40 limit: Option<usize>, 39 limit: Option<usize>,
41) -> FxHashSet<ItemInNs> { 40) -> impl Iterator<Item = ItemInNs> + 'a {
42 let _p = profile::span("items_with_name").detail(|| { 41 let _p = profile::span("items_with_name").detail(|| {
43 format!( 42 format!(
44 "Name: {} ({:?}), crate: {:?}, limit: {:?}", 43 "Name: {}, crate: {:?}, assoc items: {:?}, limit: {:?}",
45 name.text(), 44 name.text(),
46 assoc_item_search, 45 assoc_item_search,
47 krate.display_name(sema.db).map(|name| name.to_string()), 46 krate.display_name(sema.db).map(|name| name.to_string()),
@@ -62,6 +61,8 @@ pub fn items_with_name(
62 (local_query, external_query) 61 (local_query, external_query)
63 } 62 }
64 NameToImport::Fuzzy(fuzzy_search_string) => { 63 NameToImport::Fuzzy(fuzzy_search_string) => {
64 let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone());
65
65 let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) 66 let mut external_query = import_map::Query::new(fuzzy_search_string.clone())
66 .search_mode(import_map::SearchMode::Fuzzy) 67 .search_mode(import_map::SearchMode::Fuzzy)
67 .name_only(); 68 .name_only();
@@ -75,7 +76,12 @@ pub fn items_with_name(
75 } 76 }
76 } 77 }
77 78
78 (symbol_index::Query::new(fuzzy_search_string), external_query) 79 if fuzzy_search_string.to_lowercase() != fuzzy_search_string {
80 local_query.case_sensitive();
81 external_query = external_query.case_sensitive();
82 }
83
84 (local_query, external_query)
79 } 85 }
80 }; 86 };
81 87
@@ -87,13 +93,13 @@ pub fn items_with_name(
87 find_items(sema, krate, assoc_item_search, local_query, external_query) 93 find_items(sema, krate, assoc_item_search, local_query, external_query)
88} 94}
89 95
90fn find_items( 96fn find_items<'a>(
91 sema: &Semantics<'_, RootDatabase>, 97 sema: &'a Semantics<'_, RootDatabase>,
92 krate: Crate, 98 krate: Crate,
93 assoc_item_search: AssocItemSearch, 99 assoc_item_search: AssocItemSearch,
94 local_query: symbol_index::Query, 100 local_query: symbol_index::Query,
95 external_query: import_map::Query, 101 external_query: import_map::Query,
96) -> FxHashSet<ItemInNs> { 102) -> impl Iterator<Item = ItemInNs> + 'a {
97 let _p = profile::span("find_items"); 103 let _p = profile::span("find_items");
98 let db = sema.db; 104 let db = sema.db;
99 105
@@ -108,21 +114,18 @@ fn find_items(
108 // Query the local crate using the symbol index. 114 // Query the local crate using the symbol index.
109 let local_results = symbol_index::crate_symbols(db, krate.into(), local_query) 115 let local_results = symbol_index::crate_symbols(db, krate.into(), local_query)
110 .into_iter() 116 .into_iter()
111 .filter_map(|local_candidate| get_name_definition(sema, &local_candidate)) 117 .filter_map(move |local_candidate| get_name_definition(sema, &local_candidate))
112 .filter_map(|name_definition_to_import| match name_definition_to_import { 118 .filter_map(|name_definition_to_import| match name_definition_to_import {
113 Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)), 119 Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)),
114 Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), 120 Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)),
115 _ => None, 121 _ => None,
116 }); 122 });
117 123
118 external_importables 124 external_importables.chain(local_results).filter(move |&item| match assoc_item_search {
119 .chain(local_results) 125 AssocItemSearch::Include => true,
120 .filter(move |&item| match assoc_item_search { 126 AssocItemSearch::Exclude => !is_assoc_item(item, sema.db),
121 AssocItemSearch::Include => true, 127 AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db),
122 AssocItemSearch::Exclude => !is_assoc_item(item, sema.db), 128 })
123 AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db),
124 })
125 .collect()
126} 129}
127 130
128fn get_name_definition( 131fn get_name_definition(
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 9ed9568ce..35e382b5c 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -52,6 +52,7 @@ pub struct Query {
52 only_types: bool, 52 only_types: bool,
53 libs: bool, 53 libs: bool,
54 exact: bool, 54 exact: bool,
55 case_sensitive: bool,
55 limit: usize, 56 limit: usize,
56} 57}
57 58
@@ -64,6 +65,7 @@ impl Query {
64 only_types: false, 65 only_types: false,
65 libs: false, 66 libs: false,
66 exact: false, 67 exact: false,
68 case_sensitive: false,
67 limit: usize::max_value(), 69 limit: usize::max_value(),
68 } 70 }
69 } 71 }
@@ -80,6 +82,10 @@ impl Query {
80 self.exact = true; 82 self.exact = true;
81 } 83 }
82 84
85 pub fn case_sensitive(&mut self) {
86 self.case_sensitive = true;
87 }
88
83 pub fn limit(&mut self, limit: usize) { 89 pub fn limit(&mut self, limit: usize) {
84 self.limit = limit 90 self.limit = limit
85 } 91 }
@@ -326,8 +332,14 @@ impl Query {
326 if self.only_types && !symbol.kind.is_type() { 332 if self.only_types && !symbol.kind.is_type() {
327 continue; 333 continue;
328 } 334 }
329 if self.exact && symbol.name != self.query { 335 if self.exact {
330 continue; 336 if symbol.name != self.query {
337 continue;
338 }
339 } else if self.case_sensitive {
340 if self.query.chars().any(|c| !symbol.name.contains(c)) {
341 continue;
342 }
331 } 343 }
332 344
333 res.push(symbol.clone()); 345 res.push(symbol.clone());