Skip to content

Commit 0d40ff5

Browse files
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 #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]>
2 parents 09412d8 + b17d99c commit 0d40ff5

File tree

6 files changed

+93
-28
lines changed

6 files changed

+93
-28
lines changed

crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ pub(crate) fn replace_derive_with_manual_impl(
7272
items_locator::AssocItemSearch::Exclude,
7373
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
7474
)
75-
.into_iter()
7675
.filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) {
7776
ModuleDef::Trait(trait_) => Some(trait_),
7877
_ => None,

crates/ide_completion/src/completions/flyimport.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Feature: completion with imports-on-the-fly
22
//!
33
//! 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
5-
//! (case-insensitive, in any order or places).
4+
//! if they can be qualified in the scope and their name contains all symbols from the completion input.
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.
68
//!
79
//! ```
810
//! fn main() {
@@ -942,7 +944,7 @@ mod foo {
942944
}
943945
944946
fn main() {
945-
bar::Ass$0
947+
bar::ASS$0
946948
}"#,
947949
expect![[]],
948950
)
@@ -979,4 +981,57 @@ fn main() {
979981
expect![[]],
980982
)
981983
}
984+
985+
#[test]
986+
fn case_matters() {
987+
check(
988+
r#"
989+
mod foo {
990+
pub const TEST_CONST: usize = 3;
991+
pub fn test_function() -> i32 {
992+
4
993+
}
994+
}
995+
996+
fn main() {
997+
TE$0
998+
}"#,
999+
expect![[r#"
1000+
ct foo::TEST_CONST
1001+
"#]],
1002+
);
1003+
1004+
check(
1005+
r#"
1006+
mod foo {
1007+
pub const TEST_CONST: usize = 3;
1008+
pub fn test_function() -> i32 {
1009+
4
1010+
}
1011+
}
1012+
1013+
fn 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#"
1024+
mod foo {
1025+
pub const TEST_CONST: usize = 3;
1026+
pub fn test_function() -> i32 {
1027+
4
1028+
}
1029+
}
1030+
1031+
fn main() {
1032+
Te$0
1033+
}"#,
1034+
expect![[]],
1035+
);
1036+
}
9821037
}

crates/ide_completion/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ pub fn resolve_completion_edits(
161161
items_locator::AssocItemSearch::Include,
162162
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
163163
)
164-
.into_iter()
165164
.filter_map(|candidate| {
166165
current_module
167166
.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)

crates/ide_db/src/helpers/import_assets.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,6 @@ fn path_applicable_imports(
267267
AssocItemSearch::Exclude,
268268
Some(DEFAULT_QUERY_SEARCH_LIMIT),
269269
)
270-
.into_iter()
271270
.filter_map(|item| {
272271
let mod_path = mod_path(item)?;
273272
Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
@@ -285,7 +284,6 @@ fn path_applicable_imports(
285284
AssocItemSearch::Include,
286285
Some(DEFAULT_QUERY_SEARCH_LIMIT),
287286
)
288-
.into_iter()
289287
.filter_map(|item| {
290288
import_for_item(
291289
sema.db,
@@ -430,7 +428,6 @@ fn trait_applicable_items(
430428
AssocItemSearch::AssocItemsOnly,
431429
Some(DEFAULT_QUERY_SEARCH_LIMIT),
432430
)
433-
.into_iter()
434431
.filter_map(|input| item_as_assoc(db, input))
435432
.filter_map(|assoc| {
436433
let assoc_item_trait = assoc.containing_trait(db)?;

crates/ide_db/src/items_locator.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use crate::{
1515
symbol_index::{self, FileSymbol},
1616
RootDatabase,
1717
};
18-
use rustc_hash::FxHashSet;
1918

2019
/// A value to use, when uncertain which limit to pick.
2120
pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40;
@@ -32,16 +31,16 @@ pub enum AssocItemSearch {
3231
}
3332

3433
/// Searches for importable items with the given name in the crate and its dependencies.
35-
pub fn items_with_name(
36-
sema: &Semantics<'_, RootDatabase>,
34+
pub fn items_with_name<'a>(
35+
sema: &'a Semantics<'_, RootDatabase>,
3736
krate: Crate,
3837
name: NameToImport,
3938
assoc_item_search: AssocItemSearch,
4039
limit: Option<usize>,
41-
) -> FxHashSet<ItemInNs> {
40+
) -> impl Iterator<Item = ItemInNs> + 'a {
4241
let _p = profile::span("items_with_name").detail(|| {
4342
format!(
44-
"Name: {} ({:?}), crate: {:?}, limit: {:?}",
43+
"Name: {}, crate: {:?}, assoc items: {:?}, limit: {:?}",
4544
name.text(),
4645
assoc_item_search,
4746
krate.display_name(sema.db).map(|name| name.to_string()),
@@ -62,6 +61,8 @@ pub fn items_with_name(
6261
(local_query, external_query)
6362
}
6463
NameToImport::Fuzzy(fuzzy_search_string) => {
64+
let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone());
65+
6566
let mut external_query = import_map::Query::new(fuzzy_search_string.clone())
6667
.search_mode(import_map::SearchMode::Fuzzy)
6768
.name_only();
@@ -75,7 +76,12 @@ pub fn items_with_name(
7576
}
7677
}
7778

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)
7985
}
8086
};
8187

@@ -87,13 +93,13 @@ pub fn items_with_name(
8793
find_items(sema, krate, assoc_item_search, local_query, external_query)
8894
}
8995

90-
fn find_items(
91-
sema: &Semantics<'_, RootDatabase>,
96+
fn find_items<'a>(
97+
sema: &'a Semantics<'_, RootDatabase>,
9298
krate: Crate,
9399
assoc_item_search: AssocItemSearch,
94100
local_query: symbol_index::Query,
95101
external_query: import_map::Query,
96-
) -> FxHashSet<ItemInNs> {
102+
) -> impl Iterator<Item = ItemInNs> + 'a {
97103
let _p = profile::span("find_items");
98104
let db = sema.db;
99105

@@ -108,21 +114,18 @@ fn find_items(
108114
// Query the local crate using the symbol index.
109115
let local_results = symbol_index::crate_symbols(db, krate.into(), local_query)
110116
.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))
112118
.filter_map(|name_definition_to_import| match name_definition_to_import {
113119
Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)),
114120
Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)),
115121
_ => None,
116122
});
117123

118-
external_importables
119-
.chain(local_results)
120-
.filter(move |&item| match assoc_item_search {
121-
AssocItemSearch::Include => true,
122-
AssocItemSearch::Exclude => !is_assoc_item(item, sema.db),
123-
AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db),
124-
})
125-
.collect()
124+
external_importables.chain(local_results).filter(move |&item| match assoc_item_search {
125+
AssocItemSearch::Include => true,
126+
AssocItemSearch::Exclude => !is_assoc_item(item, sema.db),
127+
AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db),
128+
})
126129
}
127130

128131
fn get_name_definition(

crates/ide_db/src/symbol_index.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub struct Query {
5252
only_types: bool,
5353
libs: bool,
5454
exact: bool,
55+
case_sensitive: bool,
5556
limit: usize,
5657
}
5758

@@ -64,6 +65,7 @@ impl Query {
6465
only_types: false,
6566
libs: false,
6667
exact: false,
68+
case_sensitive: false,
6769
limit: usize::max_value(),
6870
}
6971
}
@@ -80,6 +82,10 @@ impl Query {
8082
self.exact = true;
8183
}
8284

85+
pub fn case_sensitive(&mut self) {
86+
self.case_sensitive = true;
87+
}
88+
8389
pub fn limit(&mut self, limit: usize) {
8490
self.limit = limit
8591
}
@@ -326,8 +332,14 @@ impl Query {
326332
if self.only_types && !symbol.kind.is_type() {
327333
continue;
328334
}
329-
if self.exact && symbol.name != self.query {
330-
continue;
335+
if self.exact {
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+
}
331343
}
332344

333345
res.push(symbol.clone());

0 commit comments

Comments
 (0)