diff options
| -rw-r--r-- | crates/assists/src/handlers/extract_variable.rs | 2 | ||||
| -rw-r--r-- | crates/assists/src/handlers/replace_derive_with_manual_impl.rs | 31 | ||||
| -rw-r--r-- | crates/assists/src/utils/import_assets.rs | 37 | ||||
| -rw-r--r-- | crates/completion/src/completions/postfix.rs | 2 | ||||
| -rw-r--r-- | crates/completion/src/completions/postfix/format_like.rs | 13 | ||||
| -rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 15 | ||||
| -rw-r--r-- | crates/completion/src/lib.rs | 2 | ||||
| -rw-r--r-- | crates/hir_def/src/import_map.rs | 222 | ||||
| -rw-r--r-- | crates/hir_def/src/nameres.rs | 2 | ||||
| -rw-r--r-- | crates/ide/src/lib.rs | 2 | ||||
| -rw-r--r-- | crates/ide_db/src/imports_locator.rs | 23 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 2 |
12 files changed, 251 insertions, 102 deletions
diff --git a/crates/assists/src/handlers/extract_variable.rs b/crates/assists/src/handlers/extract_variable.rs index d2ae137cd..9957012fe 100644 --- a/crates/assists/src/handlers/extract_variable.rs +++ b/crates/assists/src/handlers/extract_variable.rs | |||
| @@ -91,7 +91,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
| 91 | // extra newlines in the indent block | 91 | // extra newlines in the indent block |
| 92 | let text = indent.text(); | 92 | let text = indent.text(); |
| 93 | if text.starts_with('\n') { | 93 | if text.starts_with('\n') { |
| 94 | buf.push_str("\n"); | 94 | buf.push('\n'); |
| 95 | buf.push_str(text.trim_start_matches('\n')); | 95 | buf.push_str(text.trim_start_matches('\n')); |
| 96 | } else { | 96 | } else { |
| 97 | buf.push_str(text); | 97 | buf.push_str(text); |
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index 4d6a1956b..cb7a5c104 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
| @@ -62,21 +62,22 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
| 62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
| 63 | let current_crate = current_module.krate(); | 63 | let current_crate = current_module.krate(); |
| 64 | 64 | ||
| 65 | let found_traits = | 65 | let found_traits = imports_locator::find_exact_imports( |
| 66 | imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text()) | 66 | &ctx.sema, |
| 67 | .filter_map( | 67 | current_crate, |
| 68 | |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { | 68 | trait_token.text().to_string(), |
| 69 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), | 69 | ) |
| 70 | _ => None, | 70 | .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { |
| 71 | }, | 71 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), |
| 72 | ) | 72 | _ => None, |
| 73 | .flat_map(|trait_| { | 73 | }) |
| 74 | current_module | 74 | .flat_map(|trait_| { |
| 75 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) | 75 | current_module |
| 76 | .as_ref() | 76 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) |
| 77 | .map(mod_path_to_ast) | 77 | .as_ref() |
| 78 | .zip(Some(trait_)) | 78 | .map(mod_path_to_ast) |
| 79 | }); | 79 | .zip(Some(trait_)) |
| 80 | }); | ||
| 80 | 81 | ||
| 81 | let mut no_traits_found = true; | 82 | let mut no_traits_found = true; |
| 82 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { | 83 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { |
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs index ff5c0e78e..4ce82c1ba 100644 --- a/crates/assists/src/utils/import_assets.rs +++ b/crates/assists/src/utils/import_assets.rs | |||
| @@ -179,25 +179,24 @@ impl ImportAssets { | |||
| 179 | } | 179 | } |
| 180 | }; | 180 | }; |
| 181 | 181 | ||
| 182 | let mut res = | 182 | let mut res = imports_locator::find_exact_imports( |
| 183 | imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query()) | 183 | sema, |
| 184 | .filter_map(filter) | 184 | current_crate, |
| 185 | .filter_map(|candidate| { | 185 | self.get_search_query().to_string(), |
| 186 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); | 186 | ) |
| 187 | if let Some(prefix_kind) = prefixed { | 187 | .filter_map(filter) |
| 188 | self.module_with_name_to_import.find_use_path_prefixed( | 188 | .filter_map(|candidate| { |
| 189 | db, | 189 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); |
| 190 | item, | 190 | if let Some(prefix_kind) = prefixed { |
| 191 | prefix_kind, | 191 | self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind) |
| 192 | ) | 192 | } else { |
| 193 | } else { | 193 | self.module_with_name_to_import.find_use_path(db, item) |
| 194 | self.module_with_name_to_import.find_use_path(db, item) | 194 | } |
| 195 | } | 195 | .map(|path| (path, item)) |
| 196 | .map(|path| (path, item)) | 196 | }) |
| 197 | }) | 197 | .filter(|(use_path, _)| use_path.len() > 1) |
| 198 | .filter(|(use_path, _)| use_path.len() > 1) | 198 | .take(20) |
| 199 | .take(20) | 199 | .collect::<Vec<_>>(); |
| 200 | .collect::<Vec<_>>(); | ||
| 201 | res.sort_by_key(|(path, _)| path.clone()); | 200 | res.sort_by_key(|(path, _)| path.clone()); |
| 202 | res | 201 | res |
| 203 | } | 202 | } |
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs index d6db82a93..3883d6d21 100644 --- a/crates/completion/src/completions/postfix.rs +++ b/crates/completion/src/completions/postfix.rs | |||
| @@ -502,7 +502,7 @@ fn main() { | |||
| 502 | #[test] | 502 | #[test] |
| 503 | fn postfix_completion_for_format_like_strings() { | 503 | fn postfix_completion_for_format_like_strings() { |
| 504 | check_edit( | 504 | check_edit( |
| 505 | "fmt", | 505 | "format", |
| 506 | r#"fn main() { "{some_var:?}".<|> }"#, | 506 | r#"fn main() { "{some_var:?}".<|> }"#, |
| 507 | r#"fn main() { format!("{:?}", some_var) }"#, | 507 | r#"fn main() { format!("{:?}", some_var) }"#, |
| 508 | ); | 508 | ); |
diff --git a/crates/completion/src/completions/postfix/format_like.rs b/crates/completion/src/completions/postfix/format_like.rs index 88ba86acb..def4b13fb 100644 --- a/crates/completion/src/completions/postfix/format_like.rs +++ b/crates/completion/src/completions/postfix/format_like.rs | |||
| @@ -22,7 +22,7 @@ use syntax::ast::{self, AstToken}; | |||
| 22 | 22 | ||
| 23 | /// Mapping ("postfix completion item" => "macro to use") | 23 | /// Mapping ("postfix completion item" => "macro to use") |
| 24 | static KINDS: &[(&str, &str)] = &[ | 24 | static KINDS: &[(&str, &str)] = &[ |
| 25 | ("fmt", "format!"), | 25 | ("format", "format!"), |
| 26 | ("panic", "panic!"), | 26 | ("panic", "panic!"), |
| 27 | ("println", "println!"), | 27 | ("println", "println!"), |
| 28 | ("eprintln", "eprintln!"), | 28 | ("eprintln", "eprintln!"), |
| @@ -108,7 +108,8 @@ impl FormatStrParser { | |||
| 108 | // "{MyStruct { val_a: 0, val_b: 1 }}". | 108 | // "{MyStruct { val_a: 0, val_b: 1 }}". |
| 109 | let mut inexpr_open_count = 0; | 109 | let mut inexpr_open_count = 0; |
| 110 | 110 | ||
| 111 | for chr in self.input.chars() { | 111 | let mut chars = self.input.chars().peekable(); |
| 112 | while let Some(chr) = chars.next() { | ||
| 112 | match (self.state, chr) { | 113 | match (self.state, chr) { |
| 113 | (State::NotExpr, '{') => { | 114 | (State::NotExpr, '{') => { |
| 114 | self.output.push(chr); | 115 | self.output.push(chr); |
| @@ -157,6 +158,11 @@ impl FormatStrParser { | |||
| 157 | inexpr_open_count -= 1; | 158 | inexpr_open_count -= 1; |
| 158 | } | 159 | } |
| 159 | } | 160 | } |
| 161 | (State::Expr, ':') if chars.peek().copied() == Some(':') => { | ||
| 162 | // path seperator | ||
| 163 | current_expr.push_str("::"); | ||
| 164 | chars.next(); | ||
| 165 | } | ||
| 160 | (State::Expr, ':') => { | 166 | (State::Expr, ':') => { |
| 161 | if inexpr_open_count == 0 { | 167 | if inexpr_open_count == 0 { |
| 162 | // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" | 168 | // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" |
| @@ -249,6 +255,9 @@ mod tests { | |||
| 249 | expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], | 255 | expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]], |
| 250 | ), | 256 | ), |
| 251 | ("{ 2 + 2 }", expect![["{}; 2 + 2"]]), | 257 | ("{ 2 + 2 }", expect![["{}; 2 + 2"]]), |
| 258 | ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]), | ||
| 259 | ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]), | ||
| 260 | ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]), | ||
| 252 | ]; | 261 | ]; |
| 253 | 262 | ||
| 254 | for (input, output) in test_vector { | 263 | for (input, output) in test_vector { |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index d09849752..81a6d00e2 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
| @@ -101,8 +101,9 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
| 101 | // | 101 | // |
| 102 | // .Fuzzy search details | 102 | // .Fuzzy search details |
| 103 | // | 103 | // |
| 104 | // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only | 104 | // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only |
| 105 | // (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers. | 105 | // (i.e. in `HashMap` in the `std::collections::HashMap` path). |
| 106 | // For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. | ||
| 106 | // | 107 | // |
| 107 | // .Merge Behavior | 108 | // .Merge Behavior |
| 108 | // | 109 | // |
| @@ -126,15 +127,20 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
| 126 | let _p = profile::span("fuzzy_completion"); | 127 | let _p = profile::span("fuzzy_completion"); |
| 127 | let potential_import_name = ctx.token.to_string(); | 128 | let potential_import_name = ctx.token.to_string(); |
| 128 | 129 | ||
| 130 | if potential_import_name.len() < 2 { | ||
| 131 | return None; | ||
| 132 | } | ||
| 133 | |||
| 129 | let current_module = ctx.scope.module()?; | 134 | let current_module = ctx.scope.module()?; |
| 130 | let anchor = ctx.name_ref_syntax.as_ref()?; | 135 | let anchor = ctx.name_ref_syntax.as_ref()?; |
| 131 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | 136 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; |
| 132 | 137 | ||
| 138 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
| 133 | let mut all_mod_paths = imports_locator::find_similar_imports( | 139 | let mut all_mod_paths = imports_locator::find_similar_imports( |
| 134 | &ctx.sema, | 140 | &ctx.sema, |
| 135 | ctx.krate?, | 141 | ctx.krate?, |
| 136 | Some(100), | 142 | Some(40), |
| 137 | &potential_import_name, | 143 | potential_import_name, |
| 138 | true, | 144 | true, |
| 139 | ) | 145 | ) |
| 140 | .filter_map(|import_candidate| { | 146 | .filter_map(|import_candidate| { |
| @@ -150,7 +156,6 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
| 150 | .filter(|(mod_path, _)| mod_path.len() > 1) | 156 | .filter(|(mod_path, _)| mod_path.len() > 1) |
| 151 | .collect::<Vec<_>>(); | 157 | .collect::<Vec<_>>(); |
| 152 | 158 | ||
| 153 | let user_input_lowercased = potential_import_name.to_lowercase(); | ||
| 154 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { | 159 | all_mod_paths.sort_by_cached_key(|(mod_path, _)| { |
| 155 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) | 160 | compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) |
| 156 | }); | 161 | }); |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index 8e27bb153..c57d05bbe 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
| @@ -137,7 +137,7 @@ pub fn resolve_completion_edits( | |||
| 137 | config: &CompletionConfig, | 137 | config: &CompletionConfig, |
| 138 | position: FilePosition, | 138 | position: FilePosition, |
| 139 | full_import_path: &str, | 139 | full_import_path: &str, |
| 140 | imported_name: &str, | 140 | imported_name: String, |
| 141 | ) -> Option<Vec<TextEdit>> { | 141 | ) -> Option<Vec<TextEdit>> { |
| 142 | let ctx = CompletionContext::new(db, position, config)?; | 142 | let ctx = CompletionContext::new(db, position, config)?; |
| 143 | let anchor = ctx.name_ref_syntax.as_ref()?; | 143 | let anchor = ctx.name_ref_syntax.as_ref()?; |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index c0f108848..c4dc894df 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
| @@ -238,32 +238,53 @@ pub enum ImportKind { | |||
| 238 | BuiltinType, | 238 | BuiltinType, |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | /// A way to match import map contents against the search query. | ||
| 242 | #[derive(Debug)] | ||
| 243 | pub enum SearchMode { | ||
| 244 | /// Import map entry should strictly match the query string. | ||
| 245 | Equals, | ||
| 246 | /// Import map entry should contain the query string. | ||
| 247 | Contains, | ||
| 248 | /// Import map entry should contain all letters from the query string, | ||
| 249 | /// in the same order, but not necessary adjacent. | ||
| 250 | Fuzzy, | ||
| 251 | } | ||
| 252 | |||
| 241 | #[derive(Debug)] | 253 | #[derive(Debug)] |
| 242 | pub struct Query { | 254 | pub struct Query { |
| 243 | query: String, | 255 | query: String, |
| 244 | lowercased: String, | 256 | lowercased: String, |
| 245 | anchor_end: bool, | 257 | name_only: bool, |
| 258 | search_mode: SearchMode, | ||
| 246 | case_sensitive: bool, | 259 | case_sensitive: bool, |
| 247 | limit: usize, | 260 | limit: usize, |
| 248 | exclude_import_kinds: FxHashSet<ImportKind>, | 261 | exclude_import_kinds: FxHashSet<ImportKind>, |
| 249 | } | 262 | } |
| 250 | 263 | ||
| 251 | impl Query { | 264 | impl Query { |
| 252 | pub fn new(query: &str) -> Self { | 265 | pub fn new(query: String) -> Self { |
| 266 | let lowercased = query.to_lowercase(); | ||
| 253 | Self { | 267 | Self { |
| 254 | lowercased: query.to_lowercase(), | 268 | query, |
| 255 | query: query.to_string(), | 269 | lowercased, |
| 256 | anchor_end: false, | 270 | name_only: false, |
| 271 | search_mode: SearchMode::Contains, | ||
| 257 | case_sensitive: false, | 272 | case_sensitive: false, |
| 258 | limit: usize::max_value(), | 273 | limit: usize::max_value(), |
| 259 | exclude_import_kinds: FxHashSet::default(), | 274 | exclude_import_kinds: FxHashSet::default(), |
| 260 | } | 275 | } |
| 261 | } | 276 | } |
| 262 | 277 | ||
| 263 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | 278 | /// Matches entries' names only, ignoring the rest of |
| 264 | /// segment. | 279 | /// the qualifier. |
| 265 | pub fn anchor_end(self) -> Self { | 280 | /// Example: for `std::marker::PhantomData`, the name is `PhantomData`. |
| 266 | Self { anchor_end: true, ..self } | 281 | pub fn name_only(self) -> Self { |
| 282 | Self { name_only: true, ..self } | ||
| 283 | } | ||
| 284 | |||
| 285 | /// Specifies the way to search for the entries using the query. | ||
| 286 | pub fn search_mode(self, search_mode: SearchMode) -> Self { | ||
| 287 | Self { search_mode, ..self } | ||
| 267 | } | 288 | } |
| 268 | 289 | ||
| 269 | /// Limits the returned number of items to `limit`. | 290 | /// Limits the returned number of items to `limit`. |
| @@ -283,6 +304,40 @@ impl Query { | |||
| 283 | } | 304 | } |
| 284 | } | 305 | } |
| 285 | 306 | ||
| 307 | fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { | ||
| 308 | let mut input = if query.name_only { | ||
| 309 | input_path.segments.last().unwrap().to_string() | ||
| 310 | } else { | ||
| 311 | input_path.to_string() | ||
| 312 | }; | ||
| 313 | if enforce_lowercase || !query.case_sensitive { | ||
| 314 | input.make_ascii_lowercase(); | ||
| 315 | } | ||
| 316 | |||
| 317 | let query_string = | ||
| 318 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; | ||
| 319 | |||
| 320 | match query.search_mode { | ||
| 321 | SearchMode::Equals => &input == query_string, | ||
| 322 | SearchMode::Contains => input.contains(query_string), | ||
| 323 | SearchMode::Fuzzy => { | ||
| 324 | let mut unchecked_query_chars = query_string.chars(); | ||
| 325 | let mut mismatching_query_char = unchecked_query_chars.next(); | ||
| 326 | |||
| 327 | for input_char in input.chars() { | ||
| 328 | match mismatching_query_char { | ||
| 329 | None => return true, | ||
| 330 | Some(matching_query_char) if matching_query_char == input_char => { | ||
| 331 | mismatching_query_char = unchecked_query_chars.next(); | ||
| 332 | } | ||
| 333 | _ => (), | ||
| 334 | } | ||
| 335 | } | ||
| 336 | mismatching_query_char.is_none() | ||
| 337 | } | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 286 | /// Searches dependencies of `krate` for an importable path matching `query`. | 341 | /// Searches dependencies of `krate` for an importable path matching `query`. |
| 287 | /// | 342 | /// |
| 288 | /// This returns a list of items that could be imported from dependencies of `krate`. | 343 | /// This returns a list of items that could be imported from dependencies of `krate`. |
| @@ -312,39 +367,29 @@ pub fn search_dependencies<'a>( | |||
| 312 | let importables = &import_map.importables[indexed_value.value as usize..]; | 367 | let importables = &import_map.importables[indexed_value.value as usize..]; |
| 313 | 368 | ||
| 314 | // Path shared by the importable items in this group. | 369 | // Path shared by the importable items in this group. |
| 315 | let path = &import_map.map[&importables[0]].path; | 370 | let common_importables_path = &import_map.map[&importables[0]].path; |
| 316 | 371 | if !contains_query(&query, common_importables_path, true) { | |
| 317 | if query.anchor_end { | 372 | continue; |
| 318 | // Last segment must match query. | ||
| 319 | let last = path.segments.last().unwrap().to_string(); | ||
| 320 | if last.to_lowercase() != query.lowercased { | ||
| 321 | continue; | ||
| 322 | } | ||
| 323 | } | 373 | } |
| 324 | 374 | ||
| 375 | let common_importables_path_fst = fst_path(common_importables_path); | ||
| 325 | // Add the items from this `ModPath` group. Those are all subsequent items in | 376 | // Add the items from this `ModPath` group. Those are all subsequent items in |
| 326 | // `importables` whose paths match `path`. | 377 | // `importables` whose paths match `path`. |
| 327 | let iter = importables | 378 | let iter = importables |
| 328 | .iter() | 379 | .iter() |
| 329 | .copied() | 380 | .copied() |
| 330 | .take_while(|item| { | 381 | .take_while(|item| { |
| 331 | let item_path = &import_map.map[item].path; | 382 | common_importables_path_fst == fst_path(&import_map.map[item].path) |
| 332 | fst_path(item_path) == fst_path(path) | ||
| 333 | }) | 383 | }) |
| 334 | .filter(|&item| match item_import_kind(item) { | 384 | .filter(|&item| match item_import_kind(item) { |
| 335 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), | 385 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), |
| 336 | None => true, | 386 | None => true, |
| 387 | }) | ||
| 388 | .filter(|item| { | ||
| 389 | !query.case_sensitive // we've already checked the common importables path case-insensitively | ||
| 390 | || contains_query(&query, &import_map.map[item].path, false) | ||
| 337 | }); | 391 | }); |
| 338 | 392 | res.extend(iter); | |
| 339 | if query.case_sensitive { | ||
| 340 | // FIXME: This does not do a subsequence match. | ||
| 341 | res.extend(iter.filter(|item| { | ||
| 342 | let item_path = &import_map.map[item].path; | ||
| 343 | item_path.to_string().contains(&query.query) | ||
| 344 | })); | ||
| 345 | } else { | ||
| 346 | res.extend(iter); | ||
| 347 | } | ||
| 348 | 393 | ||
| 349 | if res.len() >= query.limit { | 394 | if res.len() >= query.limit { |
| 350 | res.truncate(query.limit); | 395 | res.truncate(query.limit); |
| @@ -388,7 +433,7 @@ mod tests { | |||
| 388 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; | 433 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; |
| 389 | use expect_test::{expect, Expect}; | 434 | use expect_test::{expect, Expect}; |
| 390 | 435 | ||
| 391 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; | 436 | use crate::{data::FunctionData, test_db::TestDB, AssocContainerId, Lookup}; |
| 392 | 437 | ||
| 393 | use super::*; | 438 | use super::*; |
| 394 | 439 | ||
| @@ -407,14 +452,31 @@ mod tests { | |||
| 407 | .into_iter() | 452 | .into_iter() |
| 408 | .filter_map(|item| { | 453 | .filter_map(|item| { |
| 409 | let mark = match item { | 454 | let mark = match item { |
| 455 | ItemInNs::Types(ModuleDefId::FunctionId(_)) | ||
| 456 | | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", | ||
| 410 | ItemInNs::Types(_) => "t", | 457 | ItemInNs::Types(_) => "t", |
| 411 | ItemInNs::Values(_) => "v", | 458 | ItemInNs::Values(_) => "v", |
| 412 | ItemInNs::Macros(_) => "m", | 459 | ItemInNs::Macros(_) => "m", |
| 413 | }; | 460 | }; |
| 414 | let item = assoc_to_trait(&db, item); | ||
| 415 | item.krate(db.upcast()).map(|krate| { | 461 | item.krate(db.upcast()).map(|krate| { |
| 416 | let map = db.import_map(krate); | 462 | let map = db.import_map(krate); |
| 417 | let path = map.path_of(item).unwrap(); | 463 | |
| 464 | let path = match assoc_to_trait(&db, item) { | ||
| 465 | Some(trait_) => { | ||
| 466 | let mut full_path = map.path_of(trait_).unwrap().to_string(); | ||
| 467 | if let ItemInNs::Types(ModuleDefId::FunctionId(function_id)) | ||
| 468 | | ItemInNs::Values(ModuleDefId::FunctionId(function_id)) = item | ||
| 469 | { | ||
| 470 | full_path += &format!( | ||
| 471 | "::{}", | ||
| 472 | FunctionData::fn_data_query(&db, function_id).name | ||
| 473 | ); | ||
| 474 | } | ||
| 475 | full_path | ||
| 476 | } | ||
| 477 | None => map.path_of(item).unwrap().to_string(), | ||
| 478 | }; | ||
| 479 | |||
| 418 | format!( | 480 | format!( |
| 419 | "{}::{} ({})\n", | 481 | "{}::{} ({})\n", |
| 420 | crate_graph[krate].display_name.as_ref().unwrap(), | 482 | crate_graph[krate].display_name.as_ref().unwrap(), |
| @@ -427,15 +489,15 @@ mod tests { | |||
| 427 | expect.assert_eq(&actual) | 489 | expect.assert_eq(&actual) |
| 428 | } | 490 | } |
| 429 | 491 | ||
| 430 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs { | 492 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> { |
| 431 | let assoc: AssocItemId = match item { | 493 | let assoc: AssocItemId = match item { |
| 432 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { | 494 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { |
| 433 | ModuleDefId::TypeAliasId(it) => it.into(), | 495 | ModuleDefId::TypeAliasId(it) => it.into(), |
| 434 | ModuleDefId::FunctionId(it) => it.into(), | 496 | ModuleDefId::FunctionId(it) => it.into(), |
| 435 | ModuleDefId::ConstId(it) => it.into(), | 497 | ModuleDefId::ConstId(it) => it.into(), |
| 436 | _ => return item, | 498 | _ => return None, |
| 437 | }, | 499 | }, |
| 438 | _ => return item, | 500 | _ => return None, |
| 439 | }; | 501 | }; |
| 440 | 502 | ||
| 441 | let container = match assoc { | 503 | let container = match assoc { |
| @@ -445,8 +507,8 @@ mod tests { | |||
| 445 | }; | 507 | }; |
| 446 | 508 | ||
| 447 | match container { | 509 | match container { |
| 448 | AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()), | 510 | AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())), |
| 449 | _ => item, | 511 | _ => None, |
| 450 | } | 512 | } |
| 451 | } | 513 | } |
| 452 | 514 | ||
| @@ -685,7 +747,7 @@ mod tests { | |||
| 685 | } | 747 | } |
| 686 | 748 | ||
| 687 | #[test] | 749 | #[test] |
| 688 | fn search() { | 750 | fn search_mode() { |
| 689 | let ra_fixture = r#" | 751 | let ra_fixture = r#" |
| 690 | //- /main.rs crate:main deps:dep | 752 | //- /main.rs crate:main deps:dep |
| 691 | //- /dep.rs crate:dep deps:tdep | 753 | //- /dep.rs crate:dep deps:tdep |
| @@ -713,28 +775,96 @@ mod tests { | |||
| 713 | check_search( | 775 | check_search( |
| 714 | ra_fixture, | 776 | ra_fixture, |
| 715 | "main", | 777 | "main", |
| 716 | Query::new("fmt"), | 778 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), |
| 717 | expect![[r#" | 779 | expect![[r#" |
| 718 | dep::fmt (t) | 780 | dep::fmt (t) |
| 719 | dep::Fmt (t) | 781 | dep::Fmt (t) |
| 720 | dep::Fmt (v) | 782 | dep::Fmt (v) |
| 721 | dep::Fmt (m) | 783 | dep::Fmt (m) |
| 722 | dep::fmt::Display (t) | 784 | dep::fmt::Display (t) |
| 723 | dep::format (v) | 785 | dep::format (f) |
| 786 | dep::fmt::Display::fmt (f) | ||
| 787 | "#]], | ||
| 788 | ); | ||
| 789 | |||
| 790 | check_search( | ||
| 791 | ra_fixture, | ||
| 792 | "main", | ||
| 793 | Query::new("fmt".to_string()).search_mode(SearchMode::Equals), | ||
| 794 | expect![[r#" | ||
| 795 | dep::fmt (t) | ||
| 796 | dep::Fmt (t) | ||
| 797 | dep::Fmt (v) | ||
| 798 | dep::Fmt (m) | ||
| 799 | dep::fmt::Display::fmt (f) | ||
| 800 | "#]], | ||
| 801 | ); | ||
| 802 | |||
| 803 | check_search( | ||
| 804 | ra_fixture, | ||
| 805 | "main", | ||
| 806 | Query::new("fmt".to_string()).search_mode(SearchMode::Contains), | ||
| 807 | expect![[r#" | ||
| 808 | dep::fmt (t) | ||
| 809 | dep::Fmt (t) | ||
| 810 | dep::Fmt (v) | ||
| 811 | dep::Fmt (m) | ||
| 724 | dep::fmt::Display (t) | 812 | dep::fmt::Display (t) |
| 813 | dep::fmt::Display::fmt (f) | ||
| 725 | "#]], | 814 | "#]], |
| 726 | ); | 815 | ); |
| 816 | } | ||
| 817 | |||
| 818 | #[test] | ||
| 819 | fn name_only() { | ||
| 820 | let ra_fixture = r#" | ||
| 821 | //- /main.rs crate:main deps:dep | ||
| 822 | //- /dep.rs crate:dep deps:tdep | ||
| 823 | use tdep::fmt as fmt_dep; | ||
| 824 | pub mod fmt { | ||
| 825 | pub trait Display { | ||
| 826 | fn fmt(); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | #[macro_export] | ||
| 830 | macro_rules! Fmt { | ||
| 831 | () => {}; | ||
| 832 | } | ||
| 833 | pub struct Fmt; | ||
| 834 | |||
| 835 | pub fn format() {} | ||
| 836 | pub fn no() {} | ||
| 837 | |||
| 838 | //- /tdep.rs crate:tdep | ||
| 839 | pub mod fmt { | ||
| 840 | pub struct NotImportableFromMain; | ||
| 841 | } | ||
| 842 | "#; | ||
| 727 | 843 | ||
| 728 | check_search( | 844 | check_search( |
| 729 | ra_fixture, | 845 | ra_fixture, |
| 730 | "main", | 846 | "main", |
| 731 | Query::new("fmt").anchor_end(), | 847 | Query::new("fmt".to_string()), |
| 732 | expect![[r#" | 848 | expect![[r#" |
| 733 | dep::fmt (t) | 849 | dep::fmt (t) |
| 734 | dep::Fmt (t) | 850 | dep::Fmt (t) |
| 735 | dep::Fmt (v) | 851 | dep::Fmt (v) |
| 736 | dep::Fmt (m) | 852 | dep::Fmt (m) |
| 737 | dep::fmt::Display (t) | 853 | dep::fmt::Display (t) |
| 854 | dep::fmt::Display::fmt (f) | ||
| 855 | "#]], | ||
| 856 | ); | ||
| 857 | |||
| 858 | check_search( | ||
| 859 | ra_fixture, | ||
| 860 | "main", | ||
| 861 | Query::new("fmt".to_string()).name_only(), | ||
| 862 | expect![[r#" | ||
| 863 | dep::fmt (t) | ||
| 864 | dep::Fmt (t) | ||
| 865 | dep::Fmt (v) | ||
| 866 | dep::Fmt (m) | ||
| 867 | dep::fmt::Display::fmt (f) | ||
| 738 | "#]], | 868 | "#]], |
| 739 | ); | 869 | ); |
| 740 | } | 870 | } |
| @@ -752,7 +882,7 @@ mod tests { | |||
| 752 | check_search( | 882 | check_search( |
| 753 | ra_fixture, | 883 | ra_fixture, |
| 754 | "main", | 884 | "main", |
| 755 | Query::new("FMT"), | 885 | Query::new("FMT".to_string()), |
| 756 | expect![[r#" | 886 | expect![[r#" |
| 757 | dep::fmt (t) | 887 | dep::fmt (t) |
| 758 | dep::fmt (v) | 888 | dep::fmt (v) |
| @@ -764,7 +894,7 @@ mod tests { | |||
| 764 | check_search( | 894 | check_search( |
| 765 | ra_fixture, | 895 | ra_fixture, |
| 766 | "main", | 896 | "main", |
| 767 | Query::new("FMT").case_sensitive(), | 897 | Query::new("FMT".to_string()).case_sensitive(), |
| 768 | expect![[r#" | 898 | expect![[r#" |
| 769 | dep::FMT (t) | 899 | dep::FMT (t) |
| 770 | dep::FMT (v) | 900 | dep::FMT (v) |
| @@ -793,7 +923,7 @@ mod tests { | |||
| 793 | pub fn no() {} | 923 | pub fn no() {} |
| 794 | "#, | 924 | "#, |
| 795 | "main", | 925 | "main", |
| 796 | Query::new("").limit(2), | 926 | Query::new("".to_string()).limit(2), |
| 797 | expect![[r#" | 927 | expect![[r#" |
| 798 | dep::fmt (t) | 928 | dep::fmt (t) |
| 799 | dep::Fmt (t) | 929 | dep::Fmt (t) |
| @@ -814,7 +944,7 @@ mod tests { | |||
| 814 | check_search( | 944 | check_search( |
| 815 | ra_fixture, | 945 | ra_fixture, |
| 816 | "main", | 946 | "main", |
| 817 | Query::new("FMT"), | 947 | Query::new("FMT".to_string()), |
| 818 | expect![[r#" | 948 | expect![[r#" |
| 819 | dep::fmt (t) | 949 | dep::fmt (t) |
| 820 | dep::fmt (v) | 950 | dep::fmt (v) |
| @@ -826,7 +956,7 @@ mod tests { | |||
| 826 | check_search( | 956 | check_search( |
| 827 | ra_fixture, | 957 | ra_fixture, |
| 828 | "main", | 958 | "main", |
| 829 | Query::new("FMT").exclude_import_kind(ImportKind::Adt), | 959 | Query::new("FMT".to_string()).exclude_import_kind(ImportKind::Adt), |
| 830 | expect![[r#""#]], | 960 | expect![[r#""#]], |
| 831 | ); | 961 | ); |
| 832 | } | 962 | } |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index ffd0381d4..9bf358775 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
| @@ -249,7 +249,7 @@ impl CrateDefMap { | |||
| 249 | buf.push_str(" _"); | 249 | buf.push_str(" _"); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | buf.push_str("\n"); | 252 | buf.push('\n'); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | for (name, child) in map.modules[module].children.iter() { | 255 | for (name, child) in map.modules[module].children.iter() { |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 41eb139d1..b3331f03f 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
| @@ -475,7 +475,7 @@ impl Analysis { | |||
| 475 | config: &CompletionConfig, | 475 | config: &CompletionConfig, |
| 476 | position: FilePosition, | 476 | position: FilePosition, |
| 477 | full_import_path: &str, | 477 | full_import_path: &str, |
| 478 | imported_name: &str, | 478 | imported_name: String, |
| 479 | ) -> Cancelable<Vec<TextEdit>> { | 479 | ) -> Cancelable<Vec<TextEdit>> { |
| 480 | Ok(self | 480 | Ok(self |
| 481 | .with_db(|db| { | 481 | .with_db(|db| { |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index b2980a5d6..0f4c2ca47 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
| @@ -15,19 +15,23 @@ use rustc_hash::FxHashSet; | |||
| 15 | pub fn find_exact_imports<'a>( | 15 | pub fn find_exact_imports<'a>( |
| 16 | sema: &Semantics<'a, RootDatabase>, | 16 | sema: &Semantics<'a, RootDatabase>, |
| 17 | krate: Crate, | 17 | krate: Crate, |
| 18 | name_to_import: &str, | 18 | name_to_import: String, |
| 19 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 19 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
| 20 | let _p = profile::span("find_exact_imports"); | 20 | let _p = profile::span("find_exact_imports"); |
| 21 | find_imports( | 21 | find_imports( |
| 22 | sema, | 22 | sema, |
| 23 | krate, | 23 | krate, |
| 24 | { | 24 | { |
| 25 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | 25 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); |
| 26 | local_query.exact(); | 26 | local_query.exact(); |
| 27 | local_query.limit(40); | 27 | local_query.limit(40); |
| 28 | local_query | 28 | local_query |
| 29 | }, | 29 | }, |
| 30 | import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40), | 30 | import_map::Query::new(name_to_import) |
| 31 | .limit(40) | ||
| 32 | .name_only() | ||
| 33 | .search_mode(import_map::SearchMode::Equals) | ||
| 34 | .case_sensitive(), | ||
| 31 | ) | 35 | ) |
| 32 | } | 36 | } |
| 33 | 37 | ||
| @@ -35,17 +39,18 @@ pub fn find_similar_imports<'a>( | |||
| 35 | sema: &Semantics<'a, RootDatabase>, | 39 | sema: &Semantics<'a, RootDatabase>, |
| 36 | krate: Crate, | 40 | krate: Crate, |
| 37 | limit: Option<usize>, | 41 | limit: Option<usize>, |
| 38 | name_to_import: &str, | 42 | fuzzy_search_string: String, |
| 39 | ignore_modules: bool, | 43 | name_only: bool, |
| 40 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 44 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
| 41 | let _p = profile::span("find_similar_imports"); | 45 | let _p = profile::span("find_similar_imports"); |
| 42 | 46 | ||
| 43 | let mut external_query = import_map::Query::new(name_to_import); | 47 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) |
| 44 | if ignore_modules { | 48 | .search_mode(import_map::SearchMode::Fuzzy); |
| 45 | external_query = external_query.exclude_import_kind(import_map::ImportKind::Module); | 49 | if name_only { |
| 50 | external_query = external_query.name_only(); | ||
| 46 | } | 51 | } |
| 47 | 52 | ||
| 48 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | 53 | let mut local_query = symbol_index::Query::new(fuzzy_search_string); |
| 49 | 54 | ||
| 50 | if let Some(limit) = limit { | 55 | if let Some(limit) = limit { |
| 51 | local_query.limit(limit); | 56 | local_query.limit(limit); |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 374fb5302..23f323f55 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
| @@ -681,7 +681,7 @@ pub(crate) fn handle_completion_resolve( | |||
| 681 | &snap.config.completion, | 681 | &snap.config.completion, |
| 682 | FilePosition { file_id, offset }, | 682 | FilePosition { file_id, offset }, |
| 683 | &resolve_data.full_import_path, | 683 | &resolve_data.full_import_path, |
| 684 | &resolve_data.imported_name, | 684 | resolve_data.imported_name, |
| 685 | )? | 685 | )? |
| 686 | .into_iter() | 686 | .into_iter() |
| 687 | .flat_map(|edit| { | 687 | .flat_map(|edit| { |
