aboutsummaryrefslogtreecommitdiff
path: root/crates/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion')
-rw-r--r--crates/completion/src/completions.rs1
-rw-r--r--crates/completion/src/completions/attribute.rs49
-rw-r--r--crates/completion/src/completions/dot.rs48
-rw-r--r--crates/completion/src/completions/flyimport.rs291
-rw-r--r--crates/completion/src/completions/fn_param.rs8
-rw-r--r--crates/completion/src/completions/keyword.rs164
-rw-r--r--crates/completion/src/completions/macro_in_item_position.rs2
-rw-r--r--crates/completion/src/completions/mod_.rs87
-rw-r--r--crates/completion/src/completions/pattern.rs20
-rw-r--r--crates/completion/src/completions/postfix.rs74
-rw-r--r--crates/completion/src/completions/qualified_path.rs73
-rw-r--r--crates/completion/src/completions/record.rs28
-rw-r--r--crates/completion/src/completions/snippet.rs8
-rw-r--r--crates/completion/src/completions/trait_impl.rs76
-rw-r--r--crates/completion/src/completions/unqualified_path.rs356
-rw-r--r--crates/completion/src/config.rs4
-rw-r--r--crates/completion/src/context.rs34
-rw-r--r--crates/completion/src/item.rs8
-rw-r--r--crates/completion/src/lib.rs19
-rw-r--r--crates/completion/src/patterns.rs56
-rw-r--r--crates/completion/src/render.rs61
-rw-r--r--crates/completion/src/render/enum_variant.rs2
-rw-r--r--crates/completion/src/render/function.rs22
-rw-r--r--crates/completion/src/render/macro_.rs8
-rw-r--r--crates/completion/src/test_utils.rs18
25 files changed, 833 insertions, 684 deletions
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index 00c9e76f0..c3ce6e51d 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -13,6 +13,7 @@ pub(crate) mod postfix;
13pub(crate) mod macro_in_item_position; 13pub(crate) mod macro_in_item_position;
14pub(crate) mod trait_impl; 14pub(crate) mod trait_impl;
15pub(crate) mod mod_; 15pub(crate) mod mod_;
16pub(crate) mod flyimport;
16 17
17use hir::{ModPath, ScopeDef, Type}; 18use hir::{ModPath, ScopeDef, Type};
18 19
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index 17276b5a4..e5522980d 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -5,7 +5,7 @@
5 5
6use itertools::Itertools; 6use itertools::Itertools;
7use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
8use syntax::{ast, AstNode, SyntaxKind}; 8use syntax::{ast, AstNode, T};
9 9
10use crate::{ 10use crate::{
11 context::CompletionContext, 11 context::CompletionContext,
@@ -21,19 +21,16 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
21 21
22 let attribute = ctx.attribute_under_caret.as_ref()?; 22 let attribute = ctx.attribute_under_caret.as_ref()?;
23 match (attribute.path(), attribute.token_tree()) { 23 match (attribute.path(), attribute.token_tree()) {
24 (Some(path), Some(token_tree)) if path.to_string() == "derive" => { 24 (Some(path), Some(token_tree)) => {
25 complete_derive(acc, ctx, token_tree) 25 let path = path.syntax().text();
26 } 26 if path == "derive" {
27 (Some(path), Some(token_tree)) if path.to_string() == "feature" => { 27 complete_derive(acc, ctx, token_tree)
28 complete_lint(acc, ctx, token_tree, FEATURES); 28 } else if path == "feature" {
29 } 29 complete_lint(acc, ctx, token_tree, FEATURES)
30 (Some(path), Some(token_tree)) 30 } else if path == "allow" || path == "warn" || path == "deny" || path == "forbid" {
31 if ["allow", "warn", "deny", "forbid"] 31 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
32 .iter() 32 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
33 .any(|lint_level| lint_level == &path.to_string()) => 33 }
34 {
35 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
36 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
37 } 34 }
38 (_, Some(_token_tree)) => {} 35 (_, Some(_token_tree)) => {}
39 _ => complete_attribute_start(acc, ctx, attribute), 36 _ => complete_attribute_start(acc, ctx, attribute),
@@ -54,11 +51,8 @@ fn complete_attribute_start(acc: &mut Completions, ctx: &CompletionContext, attr
54 item = item.lookup_by(lookup); 51 item = item.lookup_by(lookup);
55 } 52 }
56 53
57 match (attr_completion.snippet, ctx.config.snippet_cap) { 54 if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) {
58 (Some(snippet), Some(cap)) => { 55 item = item.insert_snippet(cap, snippet);
59 item = item.insert_snippet(cap, snippet);
60 }
61 _ => {}
62 } 56 }
63 57
64 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner { 58 if attribute.kind() == ast::AttrKind::Inner || !attr_completion.prefer_inner {
@@ -211,8 +205,7 @@ fn complete_lint(
211fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { 205fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> {
212 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { 206 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) {
213 (Some(left_paren), Some(right_paren)) 207 (Some(left_paren), Some(right_paren))
214 if left_paren.kind() == SyntaxKind::L_PAREN 208 if left_paren.kind() == T!['('] && right_paren.kind() == T![')'] =>
215 && right_paren.kind() == SyntaxKind::R_PAREN =>
216 { 209 {
217 let mut input_derives = FxHashSet::default(); 210 let mut input_derives = FxHashSet::default();
218 let mut current_derive = String::new(); 211 let mut current_derive = String::new();
@@ -224,7 +217,7 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin
224 .skip(1) 217 .skip(1)
225 .take_while(|token| token != &right_paren) 218 .take_while(|token| token != &right_paren)
226 { 219 {
227 if SyntaxKind::COMMA == token.kind() { 220 if T![,] == token.kind() {
228 if !current_derive.is_empty() { 221 if !current_derive.is_empty() {
229 input_derives.insert(current_derive); 222 input_derives.insert(current_derive);
230 current_derive = String::new(); 223 current_derive = String::new();
@@ -413,7 +406,7 @@ mod tests {
413 fn empty_derive_completion() { 406 fn empty_derive_completion() {
414 check( 407 check(
415 r#" 408 r#"
416#[derive(<|>)] 409#[derive($0)]
417struct Test {} 410struct Test {}
418 "#, 411 "#,
419 expect![[r#" 412 expect![[r#"
@@ -434,7 +427,7 @@ struct Test {}
434 fn no_completion_for_incorrect_derive() { 427 fn no_completion_for_incorrect_derive() {
435 check( 428 check(
436 r#" 429 r#"
437#[derive{<|>)] 430#[derive{$0)]
438struct Test {} 431struct Test {}
439"#, 432"#,
440 expect![[r#""#]], 433 expect![[r#""#]],
@@ -445,7 +438,7 @@ struct Test {}
445 fn derive_with_input_completion() { 438 fn derive_with_input_completion() {
446 check( 439 check(
447 r#" 440 r#"
448#[derive(serde::Serialize, PartialEq, <|>)] 441#[derive(serde::Serialize, PartialEq, $0)]
449struct Test {} 442struct Test {}
450"#, 443"#,
451 expect![[r#" 444 expect![[r#"
@@ -464,7 +457,7 @@ struct Test {}
464 #[test] 457 #[test]
465 fn test_attribute_completion() { 458 fn test_attribute_completion() {
466 check( 459 check(
467 r#"#[<|>]"#, 460 r#"#[$0]"#,
468 expect![[r#" 461 expect![[r#"
469 at allow(…) 462 at allow(…)
470 at automatically_derived 463 at automatically_derived
@@ -504,13 +497,13 @@ struct Test {}
504 497
505 #[test] 498 #[test]
506 fn test_attribute_completion_inside_nested_attr() { 499 fn test_attribute_completion_inside_nested_attr() {
507 check(r#"#[cfg(<|>)]"#, expect![[]]) 500 check(r#"#[cfg($0)]"#, expect![[]])
508 } 501 }
509 502
510 #[test] 503 #[test]
511 fn test_inner_attribute_completion() { 504 fn test_inner_attribute_completion() {
512 check( 505 check(
513 r"#![<|>]", 506 r"#![$0]",
514 expect![[r#" 507 expect![[r#"
515 at allow(…) 508 at allow(…)
516 at automatically_derived 509 at automatically_derived
diff --git a/crates/completion/src/completions/dot.rs b/crates/completion/src/completions/dot.rs
index 551ef1771..d04eef65a 100644
--- a/crates/completion/src/completions/dot.rs
+++ b/crates/completion/src/completions/dot.rs
@@ -79,7 +79,7 @@ struct S { foo: u32 }
79impl S { 79impl S {
80 fn bar(&self) {} 80 fn bar(&self) {}
81} 81}
82fn foo(s: S) { s.<|> } 82fn foo(s: S) { s.$0 }
83"#, 83"#,
84 expect![[r#" 84 expect![[r#"
85 fd foo u32 85 fd foo u32
@@ -94,7 +94,7 @@ fn foo(s: S) { s.<|> }
94 r#" 94 r#"
95struct S { the_field: (u32,) } 95struct S { the_field: (u32,) }
96impl S { 96impl S {
97 fn foo(self) { self.<|> } 97 fn foo(self) { self.$0 }
98} 98}
99"#, 99"#,
100 expect![[r#" 100 expect![[r#"
@@ -110,7 +110,7 @@ impl S {
110 r#" 110 r#"
111struct A { the_field: (u32, i32) } 111struct A { the_field: (u32, i32) }
112impl A { 112impl A {
113 fn foo(&self) { self.<|> } 113 fn foo(&self) { self.$0 }
114} 114}
115"#, 115"#,
116 expect![[r#" 116 expect![[r#"
@@ -126,7 +126,7 @@ impl A {
126 check( 126 check(
127 r#" 127 r#"
128struct A { the_field: u32 } 128struct A { the_field: u32 }
129fn foo(a: A) { a.<|>() } 129fn foo(a: A) { a.$0() }
130"#, 130"#,
131 expect![[""]], 131 expect![[""]],
132 ); 132 );
@@ -144,7 +144,7 @@ mod inner {
144 pub(crate) super_field: u32, 144 pub(crate) super_field: u32,
145 } 145 }
146} 146}
147fn foo(a: inner::A) { a.<|> } 147fn foo(a: inner::A) { a.$0 }
148"#, 148"#,
149 expect![[r#" 149 expect![[r#"
150 fd pub_field u32 150 fd pub_field u32
@@ -162,7 +162,7 @@ mod m {
162 pub(crate) fn the_method(&self) {} 162 pub(crate) fn the_method(&self) {}
163 } 163 }
164} 164}
165fn foo(a: A) { a.<|> } 165fn foo(a: A) { a.$0 }
166"#, 166"#,
167 expect![[r#" 167 expect![[r#"
168 me the_method() pub(crate) fn the_method(&self) 168 me the_method() pub(crate) fn the_method(&self)
@@ -175,7 +175,7 @@ fn foo(a: A) { a.<|> }
175 check( 175 check(
176 r#" 176 r#"
177union U { field: u8, other: u16 } 177union U { field: u8, other: u16 }
178fn foo(u: U) { u.<|> } 178fn foo(u: U) { u.$0 }
179"#, 179"#,
180 expect![[r#" 180 expect![[r#"
181 fd field u8 181 fd field u8
@@ -195,7 +195,7 @@ impl A<u32> {
195impl A<i32> { 195impl A<i32> {
196 fn the_other_method(&self) {} 196 fn the_other_method(&self) {}
197} 197}
198fn foo(a: A<u32>) { a.<|> } 198fn foo(a: A<u32>) { a.$0 }
199"#, 199"#,
200 expect![[r#" 200 expect![[r#"
201 me the_method() fn the_method(&self) 201 me the_method() fn the_method(&self)
@@ -210,7 +210,7 @@ fn foo(a: A<u32>) { a.<|> }
210struct A {} 210struct A {}
211trait Trait { fn the_method(&self); } 211trait Trait { fn the_method(&self); }
212impl Trait for A {} 212impl Trait for A {}
213fn foo(a: A) { a.<|> } 213fn foo(a: A) { a.$0 }
214"#, 214"#,
215 expect![[r#" 215 expect![[r#"
216 me the_method() fn the_method(&self) 216 me the_method() fn the_method(&self)
@@ -225,7 +225,7 @@ fn foo(a: A) { a.<|> }
225struct A {} 225struct A {}
226trait Trait { fn the_method(&self); } 226trait Trait { fn the_method(&self); }
227impl<T> Trait for T {} 227impl<T> Trait for T {}
228fn foo(a: &A) { a.<|> } 228fn foo(a: &A) { a.$0 }
229", 229",
230 expect![[r#" 230 expect![[r#"
231 me the_method() fn the_method(&self) 231 me the_method() fn the_method(&self)
@@ -243,7 +243,7 @@ mod m {
243} 243}
244use m::Trait; 244use m::Trait;
245impl Trait for A {} 245impl Trait for A {}
246fn foo(a: A) { a.<|> } 246fn foo(a: A) { a.$0 }
247", 247",
248 expect![[r#" 248 expect![[r#"
249 me the_method() fn the_method(&self) 249 me the_method() fn the_method(&self)
@@ -260,7 +260,7 @@ impl A {
260 fn the_method() {} 260 fn the_method() {}
261} 261}
262fn foo(a: A) { 262fn foo(a: A) {
263 a.<|> 263 a.$0
264} 264}
265"#, 265"#,
266 expect![[""]], 266 expect![[""]],
@@ -273,7 +273,7 @@ fn foo(a: A) {
273 r#" 273 r#"
274fn foo() { 274fn foo() {
275 let b = (0, 3.14); 275 let b = (0, 3.14);
276 b.<|> 276 b.$0
277} 277}
278"#, 278"#,
279 expect![[r#" 279 expect![[r#"
@@ -295,7 +295,7 @@ struct T(S);
295impl T { 295impl T {
296 fn foo(&self) { 296 fn foo(&self) {
297 // FIXME: This doesn't work without the trailing `a` as `0.` is a float 297 // FIXME: This doesn't work without the trailing `a` as `0.` is a float
298 self.0.a<|> 298 self.0.a$0
299 } 299 }
300} 300}
301"#, 301"#,
@@ -311,7 +311,7 @@ impl T {
311 r#" 311 r#"
312struct A { the_field: u32 } 312struct A { the_field: u32 }
313const X: u32 = { 313const X: u32 = {
314 A { the_field: 92 }.<|> 314 A { the_field: 92 }.$0
315}; 315};
316"#, 316"#,
317 expect![[r#" 317 expect![[r#"
@@ -327,7 +327,7 @@ const X: u32 = {
327macro_rules! m { ($e:expr) => { $e } } 327macro_rules! m { ($e:expr) => { $e } }
328struct A { the_field: u32 } 328struct A { the_field: u32 }
329fn foo(a: A) { 329fn foo(a: A) {
330 m!(a.x<|>) 330 m!(a.x$0)
331} 331}
332"#, 332"#,
333 expect![[r#" 333 expect![[r#"
@@ -344,7 +344,7 @@ fn foo(a: A) {
344macro_rules! m { ($e:expr) => { $e } } 344macro_rules! m { ($e:expr) => { $e } }
345struct A { the_field: u32 } 345struct A { the_field: u32 }
346fn foo(a: A) { 346fn foo(a: A) {
347 m!(a.<|>) 347 m!(a.$0)
348} 348}
349"#, 349"#,
350 expect![[r#" 350 expect![[r#"
@@ -360,7 +360,7 @@ fn foo(a: A) {
360macro_rules! m { ($e:expr) => { $e } } 360macro_rules! m { ($e:expr) => { $e } }
361struct A { the_field: u32 } 361struct A { the_field: u32 }
362fn foo(a: A) { 362fn foo(a: A) {
363 m!(m!(m!(a.x<|>))) 363 m!(m!(m!(a.x$0)))
364} 364}
365"#, 365"#,
366 expect![[r#" 366 expect![[r#"
@@ -373,20 +373,20 @@ fn foo(a: A) {
373 fn macro_expansion_resilient() { 373 fn macro_expansion_resilient() {
374 check( 374 check(
375 r#" 375 r#"
376macro_rules! dbg { 376macro_rules! d {
377 () => {}; 377 () => {};
378 ($val:expr) => { 378 ($val:expr) => {
379 match $val { tmp => { tmp } } 379 match $val { tmp => { tmp } }
380 }; 380 };
381 // Trailing comma with single argument is ignored 381 // Trailing comma with single argument is ignored
382 ($val:expr,) => { $crate::dbg!($val) }; 382 ($val:expr,) => { $crate::d!($val) };
383 ($($val:expr),+ $(,)?) => { 383 ($($val:expr),+ $(,)?) => {
384 ($($crate::dbg!($val)),+,) 384 ($($crate::d!($val)),+,)
385 }; 385 };
386} 386}
387struct A { the_field: u32 } 387struct A { the_field: u32 }
388fn foo(a: A) { 388fn foo(a: A) {
389 dbg!(a.<|>) 389 d!(a.$0)
390} 390}
391"#, 391"#,
392 expect![[r#" 392 expect![[r#"
@@ -405,7 +405,7 @@ impl<T> HashSet<T> {
405} 405}
406fn foo() { 406fn foo() {
407 let s: HashSet<_>; 407 let s: HashSet<_>;
408 s.<|> 408 s.$0
409} 409}
410"#, 410"#,
411 expect![[r#" 411 expect![[r#"
@@ -421,7 +421,7 @@ fn foo() {
421struct S; 421struct S;
422impl S { fn foo(&self) {} } 422impl S { fn foo(&self) {} }
423macro_rules! make_s { () => { S }; } 423macro_rules! make_s { () => { S }; }
424fn main() { make_s!().f<|>; } 424fn main() { make_s!().f$0; }
425"#, 425"#,
426 expect![[r#" 426 expect![[r#"
427 me foo() fn foo(&self) 427 me foo() fn foo(&self)
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs
new file mode 100644
index 000000000..222809638
--- /dev/null
+++ b/crates/completion/src/completions/flyimport.rs
@@ -0,0 +1,291 @@
1//! Feature: completion with imports-on-the-fly
2//!
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
5//! (case-insensitive, in any order or places).
6//!
7//! ```
8//! fn main() {
9//! pda$0
10//! }
11//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
12//! ```
13//! ->
14//! ```
15//! use std::marker::PhantomData;
16//!
17//! fn main() {
18//! PhantomData
19//! }
20//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
21//! ```
22//!
23//! .Fuzzy search details
24//!
25//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
26//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
27//! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
28//!
29//! .Import configuration
30//!
31//! It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
32//! Mimics the corresponding behavior of the `Auto Import` feature.
33//!
34//! .LSP and performance implications
35//!
36//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
37//! (case sensitive) resolve client capability in its client capabilities.
38//! This way the server is able to defer the costly computations, doing them for a selected completion item only.
39//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
40//! which might be slow ergo the feature is automatically disabled.
41//!
42//! .Feature toggle
43//!
44//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
45//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
46//! capability enabled.
47
48use either::Either;
49use hir::{ModPath, ScopeDef};
50use ide_db::{helpers::insert_use::ImportScope, imports_locator};
51use syntax::AstNode;
52use test_utils::mark;
53
54use crate::{
55 context::CompletionContext,
56 render::{render_resolution_with_import, RenderContext},
57 ImportEdit,
58};
59
60use super::Completions;
61
62pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
63 if !ctx.config.enable_autoimport_completions {
64 return None;
65 }
66 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() {
67 return None;
68 }
69 let potential_import_name = ctx.token.to_string();
70 if potential_import_name.len() < 2 {
71 return None;
72 }
73 let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
74
75 let current_module = ctx.scope.module()?;
76 let anchor = ctx.name_ref_syntax.as_ref()?;
77 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
78
79 let user_input_lowercased = potential_import_name.to_lowercase();
80 let mut all_mod_paths = imports_locator::find_similar_imports(
81 &ctx.sema,
82 ctx.krate?,
83 Some(40),
84 potential_import_name,
85 true,
86 true,
87 )
88 .filter_map(|import_candidate| {
89 Some(match import_candidate {
90 Either::Left(module_def) => {
91 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
92 }
93 Either::Right(macro_def) => {
94 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
95 }
96 })
97 })
98 .filter(|(mod_path, _)| mod_path.len() > 1)
99 .collect::<Vec<_>>();
100
101 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
102 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
103 });
104
105 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
106 render_resolution_with_import(
107 RenderContext::new(ctx),
108 ImportEdit { import_path, import_scope: import_scope.clone() },
109 &definition,
110 )
111 }));
112 Some(())
113}
114
115fn compute_fuzzy_completion_order_key(
116 proposed_mod_path: &ModPath,
117 user_input_lowercased: &str,
118) -> usize {
119 mark::hit!(certain_fuzzy_order_test);
120 let proposed_import_name = match proposed_mod_path.segments.last() {
121 Some(name) => name.to_string().to_lowercase(),
122 None => return usize::MAX,
123 };
124 match proposed_import_name.match_indices(user_input_lowercased).next() {
125 Some((first_matching_index, _)) => first_matching_index,
126 None => usize::MAX,
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use expect_test::{expect, Expect};
133 use test_utils::mark;
134
135 use crate::{
136 item::CompletionKind,
137 test_utils::{check_edit, completion_list},
138 };
139
140 fn check(ra_fixture: &str, expect: Expect) {
141 let actual = completion_list(ra_fixture, CompletionKind::Magic);
142 expect.assert_eq(&actual);
143 }
144
145 #[test]
146 fn function_fuzzy_completion() {
147 check_edit(
148 "stdin",
149 r#"
150//- /lib.rs crate:dep
151pub mod io {
152 pub fn stdin() {}
153};
154
155//- /main.rs crate:main deps:dep
156fn main() {
157 stdi$0
158}
159"#,
160 r#"
161use dep::io::stdin;
162
163fn main() {
164 stdin()$0
165}
166"#,
167 );
168 }
169
170 #[test]
171 fn macro_fuzzy_completion() {
172 check_edit(
173 "macro_with_curlies!",
174 r#"
175//- /lib.rs crate:dep
176/// Please call me as macro_with_curlies! {}
177#[macro_export]
178macro_rules! macro_with_curlies {
179 () => {}
180}
181
182//- /main.rs crate:main deps:dep
183fn main() {
184 curli$0
185}
186"#,
187 r#"
188use dep::macro_with_curlies;
189
190fn main() {
191 macro_with_curlies! {$0}
192}
193"#,
194 );
195 }
196
197 #[test]
198 fn struct_fuzzy_completion() {
199 check_edit(
200 "ThirdStruct",
201 r#"
202//- /lib.rs crate:dep
203pub struct FirstStruct;
204pub mod some_module {
205 pub struct SecondStruct;
206 pub struct ThirdStruct;
207}
208
209//- /main.rs crate:main deps:dep
210use dep::{FirstStruct, some_module::SecondStruct};
211
212fn main() {
213 this$0
214}
215"#,
216 r#"
217use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
218
219fn main() {
220 ThirdStruct
221}
222"#,
223 );
224 }
225
226 #[test]
227 fn fuzzy_completions_come_in_specific_order() {
228 mark::check!(certain_fuzzy_order_test);
229 check(
230 r#"
231//- /lib.rs crate:dep
232pub struct FirstStruct;
233pub mod some_module {
234 // already imported, omitted
235 pub struct SecondStruct;
236 // does not contain all letters from the query, omitted
237 pub struct UnrelatedOne;
238 // contains all letters from the query, but not in sequence, displayed last
239 pub struct ThiiiiiirdStruct;
240 // contains all letters from the query, but not in the beginning, displayed second
241 pub struct AfterThirdStruct;
242 // contains all letters from the query in the begginning, displayed first
243 pub struct ThirdStruct;
244}
245
246//- /main.rs crate:main deps:dep
247use dep::{FirstStruct, some_module::SecondStruct};
248
249fn main() {
250 hir$0
251}
252"#,
253 expect![[r#"
254 st dep::some_module::ThirdStruct
255 st dep::some_module::AfterThirdStruct
256 st dep::some_module::ThiiiiiirdStruct
257 "#]],
258 );
259 }
260
261 #[test]
262 fn does_not_propose_names_in_scope() {
263 check(
264 r#"
265//- /lib.rs crate:dep
266pub mod test_mod {
267 pub trait TestTrait {
268 const SPECIAL_CONST: u8;
269 type HumbleType;
270 fn weird_function();
271 fn random_method(&self);
272 }
273 pub struct TestStruct {}
274 impl TestTrait for TestStruct {
275 const SPECIAL_CONST: u8 = 42;
276 type HumbleType = ();
277 fn weird_function() {}
278 fn random_method(&self) {}
279 }
280}
281
282//- /main.rs crate:main deps:dep
283use dep::test_mod::TestStruct;
284fn main() {
285 TestSt$0
286}
287"#,
288 expect![[r#""#]],
289 );
290 }
291}
diff --git a/crates/completion/src/completions/fn_param.rs b/crates/completion/src/completions/fn_param.rs
index e777a53c1..5505c3559 100644
--- a/crates/completion/src/completions/fn_param.rs
+++ b/crates/completion/src/completions/fn_param.rs
@@ -81,7 +81,7 @@ mod tests {
81 r#" 81 r#"
82fn foo(file_id: FileId) {} 82fn foo(file_id: FileId) {}
83fn bar(file_id: FileId) {} 83fn bar(file_id: FileId) {}
84fn baz(file<|>) {} 84fn baz(file$0) {}
85"#, 85"#,
86 expect![[r#" 86 expect![[r#"
87 bn file_id: FileId 87 bn file_id: FileId
@@ -94,7 +94,7 @@ fn baz(file<|>) {}
94 check( 94 check(
95 r#" 95 r#"
96fn foo(file_id: FileId) {} 96fn foo(file_id: FileId) {}
97fn baz(file<|>, x: i32) {} 97fn baz(file$0, x: i32) {}
98"#, 98"#,
99 expect![[r#" 99 expect![[r#"
100 bn file_id: FileId 100 bn file_id: FileId
@@ -110,7 +110,7 @@ pub(crate) trait SourceRoot {
110 pub fn contains(&self, file_id: FileId) -> bool; 110 pub fn contains(&self, file_id: FileId) -> bool;
111 pub fn module_map(&self) -> &ModuleMap; 111 pub fn module_map(&self) -> &ModuleMap;
112 pub fn lines(&self, file_id: FileId) -> &LineIndex; 112 pub fn lines(&self, file_id: FileId) -> &LineIndex;
113 pub fn syntax(&self, file<|>) 113 pub fn syntax(&self, file$0)
114} 114}
115"#, 115"#,
116 expect![[r#" 116 expect![[r#"
@@ -124,7 +124,7 @@ pub(crate) trait SourceRoot {
124 check( 124 check(
125 r#" 125 r#"
126fn outer(text: String) { 126fn outer(text: String) {
127 fn inner(<|>) 127 fn inner($0)
128} 128}
129"#, 129"#,
130 expect![[r#" 130 expect![[r#"
diff --git a/crates/completion/src/completions/keyword.rs b/crates/completion/src/completions/keyword.rs
index 1859dec70..47e146128 100644
--- a/crates/completion/src/completions/keyword.rs
+++ b/crates/completion/src/completions/keyword.rs
@@ -1,6 +1,6 @@
1//! Completes keywords. 1//! Completes keywords.
2 2
3use syntax::{ast, SyntaxKind}; 3use syntax::SyntaxKind;
4use test_utils::mark; 4use test_utils::mark;
5 5
6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
@@ -86,8 +86,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
86 add_keyword(ctx, acc, "match", "match $0 {}"); 86 add_keyword(ctx, acc, "match", "match $0 {}");
87 add_keyword(ctx, acc, "while", "while $0 {}"); 87 add_keyword(ctx, acc, "while", "while $0 {}");
88 add_keyword(ctx, acc, "loop", "loop {$0}"); 88 add_keyword(ctx, acc, "loop", "loop {$0}");
89 add_keyword(ctx, acc, "if", "if "); 89 add_keyword(ctx, acc, "if", "if $0 {}");
90 add_keyword(ctx, acc, "if let", "if let "); 90 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
91 } 91 }
92 92
93 if ctx.if_is_prev || ctx.block_expr_parent { 93 if ctx.if_is_prev || ctx.block_expr_parent {
@@ -99,7 +99,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
99 add_keyword(ctx, acc, "else if", "else if $0 {}"); 99 add_keyword(ctx, acc, "else if", "else if $0 {}");
100 } 100 }
101 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { 101 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
102 add_keyword(ctx, acc, "mod", "mod $0 {}"); 102 add_keyword(ctx, acc, "mod", "mod $0");
103 } 103 }
104 if ctx.bind_pat_parent || ctx.ref_pat_parent { 104 if ctx.bind_pat_parent || ctx.ref_pat_parent {
105 add_keyword(ctx, acc, "mut", "mut "); 105 add_keyword(ctx, acc, "mut", "mut ");
@@ -143,47 +143,49 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
143 Some(it) => it, 143 Some(it) => it,
144 None => return, 144 None => return,
145 }; 145 };
146 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
147}
148
149fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
150 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
151 .kind(CompletionItemKind::Keyword);
152 146
153 match ctx.config.snippet_cap { 147 add_keyword(
154 Some(cap) => res.insert_snippet(cap, snippet), 148 ctx,
155 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }), 149 acc,
156 } 150 "return",
157 .build() 151 match (ctx.can_be_stmt, fn_def.ret_type().is_some()) {
152 (true, true) => "return $0;",
153 (true, false) => "return;",
154 (false, true) => "return $0",
155 (false, false) => "return",
156 },
157 )
158} 158}
159 159
160fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { 160fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
161 acc.add(keyword(ctx, kw, snippet)); 161 let builder = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
162} 162 .kind(CompletionItemKind::Keyword);
163 163 let builder = match ctx.config.snippet_cap {
164fn complete_return( 164 Some(cap) => {
165 ctx: &CompletionContext, 165 let tmp;
166 fn_def: &ast::Fn, 166 let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
167 can_be_stmt: bool, 167 mark::hit!(let_semi);
168) -> Option<CompletionItem> { 168 tmp = format!("{};", snippet);
169 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) { 169 &tmp
170 (true, true) => "return $0;", 170 } else {
171 (true, false) => "return;", 171 snippet
172 (false, true) => "return $0", 172 };
173 (false, false) => "return", 173 builder.insert_snippet(cap, snippet)
174 }
175 None => builder.insert_text(if snippet.contains('$') { kw } else { snippet }),
174 }; 176 };
175 Some(keyword(ctx, "return", snip)) 177 acc.add(builder.build());
176} 178}
177 179
178#[cfg(test)] 180#[cfg(test)]
179mod tests { 181mod tests {
180 use expect_test::{expect, Expect}; 182 use expect_test::{expect, Expect};
183 use test_utils::mark;
181 184
182 use crate::{ 185 use crate::{
183 test_utils::{check_edit, completion_list}, 186 test_utils::{check_edit, completion_list},
184 CompletionKind, 187 CompletionKind,
185 }; 188 };
186 use test_utils::mark;
187 189
188 fn check(ra_fixture: &str, expect: Expect) { 190 fn check(ra_fixture: &str, expect: Expect) {
189 let actual = completion_list(ra_fixture, CompletionKind::Keyword); 191 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
@@ -193,7 +195,7 @@ mod tests {
193 #[test] 195 #[test]
194 fn test_keywords_in_use_stmt() { 196 fn test_keywords_in_use_stmt() {
195 check( 197 check(
196 r"use <|>", 198 r"use $0",
197 expect![[r#" 199 expect![[r#"
198 kw crate:: 200 kw crate::
199 kw self 201 kw self
@@ -202,7 +204,7 @@ mod tests {
202 ); 204 );
203 205
204 check( 206 check(
205 r"use a::<|>", 207 r"use a::$0",
206 expect![[r#" 208 expect![[r#"
207 kw self 209 kw self
208 kw super:: 210 kw super::
@@ -210,7 +212,7 @@ mod tests {
210 ); 212 );
211 213
212 check( 214 check(
213 r"use a::{b, <|>}", 215 r"use a::{b, $0}",
214 expect![[r#" 216 expect![[r#"
215 kw self 217 kw self
216 kw super:: 218 kw super::
@@ -221,7 +223,7 @@ mod tests {
221 #[test] 223 #[test]
222 fn test_keywords_at_source_file_level() { 224 fn test_keywords_at_source_file_level() {
223 check( 225 check(
224 r"m<|>", 226 r"m$0",
225 expect![[r#" 227 expect![[r#"
226 kw fn 228 kw fn
227 kw use 229 kw use
@@ -245,7 +247,7 @@ mod tests {
245 #[test] 247 #[test]
246 fn test_keywords_in_function() { 248 fn test_keywords_in_function() {
247 check( 249 check(
248 r"fn quux() { <|> }", 250 r"fn quux() { $0 }",
249 expect![[r#" 251 expect![[r#"
250 kw fn 252 kw fn
251 kw use 253 kw use
@@ -271,7 +273,7 @@ mod tests {
271 #[test] 273 #[test]
272 fn test_keywords_inside_block() { 274 fn test_keywords_inside_block() {
273 check( 275 check(
274 r"fn quux() { if true { <|> } }", 276 r"fn quux() { if true { $0 } }",
275 expect![[r#" 277 expect![[r#"
276 kw fn 278 kw fn
277 kw use 279 kw use
@@ -297,7 +299,7 @@ mod tests {
297 #[test] 299 #[test]
298 fn test_keywords_after_if() { 300 fn test_keywords_after_if() {
299 check( 301 check(
300 r#"fn quux() { if true { () } <|> }"#, 302 r#"fn quux() { if true { () } $0 }"#,
301 expect![[r#" 303 expect![[r#"
302 kw fn 304 kw fn
303 kw use 305 kw use
@@ -322,7 +324,7 @@ mod tests {
322 ); 324 );
323 check_edit( 325 check_edit(
324 "else", 326 "else",
325 r#"fn quux() { if true { () } <|> }"#, 327 r#"fn quux() { if true { () } $0 }"#,
326 r#"fn quux() { if true { () } else {$0} }"#, 328 r#"fn quux() { if true { () } else {$0} }"#,
327 ); 329 );
328 } 330 }
@@ -332,7 +334,7 @@ mod tests {
332 check( 334 check(
333 r#" 335 r#"
334fn quux() -> i32 { 336fn quux() -> i32 {
335 match () { () => <|> } 337 match () { () => $0 }
336} 338}
337"#, 339"#,
338 expect![[r#" 340 expect![[r#"
@@ -350,7 +352,7 @@ fn quux() -> i32 {
350 #[test] 352 #[test]
351 fn test_keywords_in_trait_def() { 353 fn test_keywords_in_trait_def() {
352 check( 354 check(
353 r"trait My { <|> }", 355 r"trait My { $0 }",
354 expect![[r#" 356 expect![[r#"
355 kw fn 357 kw fn
356 kw const 358 kw const
@@ -363,7 +365,7 @@ fn quux() -> i32 {
363 #[test] 365 #[test]
364 fn test_keywords_in_impl_def() { 366 fn test_keywords_in_impl_def() {
365 check( 367 check(
366 r"impl My { <|> }", 368 r"impl My { $0 }",
367 expect![[r#" 369 expect![[r#"
368 kw fn 370 kw fn
369 kw const 371 kw const
@@ -378,7 +380,7 @@ fn quux() -> i32 {
378 #[test] 380 #[test]
379 fn test_keywords_in_loop() { 381 fn test_keywords_in_loop() {
380 check( 382 check(
381 r"fn my() { loop { <|> } }", 383 r"fn my() { loop { $0 } }",
382 expect![[r#" 384 expect![[r#"
383 kw fn 385 kw fn
384 kw use 386 kw use
@@ -406,7 +408,7 @@ fn quux() -> i32 {
406 #[test] 408 #[test]
407 fn test_keywords_after_unsafe_in_item_list() { 409 fn test_keywords_after_unsafe_in_item_list() {
408 check( 410 check(
409 r"unsafe <|>", 411 r"unsafe $0",
410 expect![[r#" 412 expect![[r#"
411 kw fn 413 kw fn
412 kw trait 414 kw trait
@@ -418,7 +420,7 @@ fn quux() -> i32 {
418 #[test] 420 #[test]
419 fn test_keywords_after_unsafe_in_block_expr() { 421 fn test_keywords_after_unsafe_in_block_expr() {
420 check( 422 check(
421 r"fn my_fn() { unsafe <|> }", 423 r"fn my_fn() { unsafe $0 }",
422 expect![[r#" 424 expect![[r#"
423 kw fn 425 kw fn
424 kw trait 426 kw trait
@@ -430,19 +432,19 @@ fn quux() -> i32 {
430 #[test] 432 #[test]
431 fn test_mut_in_ref_and_in_fn_parameters_list() { 433 fn test_mut_in_ref_and_in_fn_parameters_list() {
432 check( 434 check(
433 r"fn my_fn(&<|>) {}", 435 r"fn my_fn(&$0) {}",
434 expect![[r#" 436 expect![[r#"
435 kw mut 437 kw mut
436 "#]], 438 "#]],
437 ); 439 );
438 check( 440 check(
439 r"fn my_fn(<|>) {}", 441 r"fn my_fn($0) {}",
440 expect![[r#" 442 expect![[r#"
441 kw mut 443 kw mut
442 "#]], 444 "#]],
443 ); 445 );
444 check( 446 check(
445 r"fn my_fn() { let &<|> }", 447 r"fn my_fn() { let &$0 }",
446 expect![[r#" 448 expect![[r#"
447 kw mut 449 kw mut
448 "#]], 450 "#]],
@@ -452,13 +454,13 @@ fn quux() -> i32 {
452 #[test] 454 #[test]
453 fn test_where_keyword() { 455 fn test_where_keyword() {
454 check( 456 check(
455 r"trait A <|>", 457 r"trait A $0",
456 expect![[r#" 458 expect![[r#"
457 kw where 459 kw where
458 "#]], 460 "#]],
459 ); 461 );
460 check( 462 check(
461 r"impl A <|>", 463 r"impl A $0",
462 expect![[r#" 464 expect![[r#"
463 kw where 465 kw where
464 "#]], 466 "#]],
@@ -471,7 +473,7 @@ fn quux() -> i32 {
471 check( 473 check(
472 r#" 474 r#"
473fn test() { 475fn test() {
474 let x = 2; // A comment<|> 476 let x = 2; // A comment$0
475} 477}
476"#, 478"#,
477 expect![[""]], 479 expect![[""]],
@@ -479,7 +481,7 @@ fn test() {
479 check( 481 check(
480 r#" 482 r#"
481/* 483/*
482Some multi-line comment<|> 484Some multi-line comment$0
483*/ 485*/
484"#, 486"#,
485 expect![[""]], 487 expect![[""]],
@@ -487,7 +489,7 @@ Some multi-line comment<|>
487 check( 489 check(
488 r#" 490 r#"
489/// Some doc comment 491/// Some doc comment
490/// let test<|> = 1 492/// let test$0 = 1
491"#, 493"#,
492 expect![[""]], 494 expect![[""]],
493 ); 495 );
@@ -501,7 +503,7 @@ Some multi-line comment<|>
501use std::future::*; 503use std::future::*;
502struct A {} 504struct A {}
503impl Future for A {} 505impl Future for A {}
504fn foo(a: A) { a.<|> } 506fn foo(a: A) { a.$0 }
505 507
506//- /std/lib.rs crate:std 508//- /std/lib.rs crate:std
507pub mod future { 509pub mod future {
@@ -520,7 +522,7 @@ pub mod future {
520use std::future::*; 522use std::future::*;
521fn foo() { 523fn foo() {
522 let a = async {}; 524 let a = async {};
523 a.<|> 525 a.$0
524} 526}
525 527
526//- /std/lib.rs crate:std 528//- /std/lib.rs crate:std
@@ -540,7 +542,7 @@ pub mod future {
540 #[test] 542 #[test]
541 fn after_let() { 543 fn after_let() {
542 check( 544 check(
543 r#"fn main() { let _ = <|> }"#, 545 r#"fn main() { let _ = $0 }"#,
544 expect![[r#" 546 expect![[r#"
545 kw match 547 kw match
546 kw while 548 kw while
@@ -557,7 +559,7 @@ pub mod future {
557 check( 559 check(
558 r#" 560 r#"
559struct Foo { 561struct Foo {
560 <|> 562 $0
561 pub f: i32, 563 pub f: i32,
562} 564}
563"#, 565"#,
@@ -578,7 +580,7 @@ struct Foo {
578} 580}
579fn foo() { 581fn foo() {
580 Foo { 582 Foo {
581 <|> 583 $0
582 } 584 }
583} 585}
584"#, 586"#,
@@ -595,7 +597,7 @@ struct Foo {
595} 597}
596fn foo() { 598fn foo() {
597 Foo { 599 Foo {
598 f: <|> 600 f: $0
599 } 601 }
600} 602}
601"#, 603"#,
@@ -609,4 +611,50 @@ fn foo() {
609 "#]], 611 "#]],
610 ); 612 );
611 } 613 }
614
615 #[test]
616 fn let_semi() {
617 mark::check!(let_semi);
618 check_edit(
619 "match",
620 r#"
621fn main() { let x = $0 }
622"#,
623 r#"
624fn main() { let x = match $0 {}; }
625"#,
626 );
627
628 check_edit(
629 "if",
630 r#"
631fn main() {
632 let x = $0
633 let y = 92;
634}
635"#,
636 r#"
637fn main() {
638 let x = if $0 {};
639 let y = 92;
640}
641"#,
642 );
643
644 check_edit(
645 "loop",
646 r#"
647fn main() {
648 let x = $0
649 bar();
650}
651"#,
652 r#"
653fn main() {
654 let x = loop {$0};
655 bar();
656}
657"#,
658 );
659 }
612} 660}
diff --git a/crates/completion/src/completions/macro_in_item_position.rs b/crates/completion/src/completions/macro_in_item_position.rs
index 82884a181..2be299ac2 100644
--- a/crates/completion/src/completions/macro_in_item_position.rs
+++ b/crates/completion/src/completions/macro_in_item_position.rs
@@ -31,7 +31,7 @@ mod tests {
31macro_rules! foo { () => {} } 31macro_rules! foo { () => {} }
32fn foo() {} 32fn foo() {}
33 33
34<|> 34$0
35"#, 35"#,
36 expect![[r#" 36 expect![[r#"
37 ma foo!(…) macro_rules! foo 37 ma foo!(…) macro_rules! foo
diff --git a/crates/completion/src/completions/mod_.rs b/crates/completion/src/completions/mod_.rs
index f77864b77..00e951ca9 100644
--- a/crates/completion/src/completions/mod_.rs
+++ b/crates/completion/src/completions/mod_.rs
@@ -1,5 +1,7 @@
1//! Completes mod declarations. 1//! Completes mod declarations.
2 2
3use std::iter;
4
3use hir::{Module, ModuleSource}; 5use hir::{Module, ModuleSource};
4use ide_db::base_db::{SourceDatabaseExt, VfsPath}; 6use ide_db::base_db::{SourceDatabaseExt, VfsPath};
5use ide_db::RootDatabase; 7use ide_db::RootDatabase;
@@ -9,12 +11,11 @@ use crate::{CompletionItem, CompletionItemKind};
9 11
10use crate::{context::CompletionContext, item::CompletionKind, Completions}; 12use crate::{context::CompletionContext, item::CompletionKind, Completions};
11 13
12/// Complete mod declaration, i.e. `mod <|> ;` 14/// Complete mod declaration, i.e. `mod $0 ;`
13pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 15pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
14 let mod_under_caret = match &ctx.mod_declaration_under_caret { 16 let mod_under_caret = match &ctx.mod_declaration_under_caret {
15 Some(mod_under_caret) if mod_under_caret.item_list().is_some() => return None, 17 Some(mod_under_caret) if mod_under_caret.item_list().is_none() => mod_under_caret,
16 Some(mod_under_caret) => mod_under_caret, 18 _ => return None,
17 None => return None,
18 }; 19 };
19 20
20 let _p = profile::span("completion::complete_mod"); 21 let _p = profile::span("completion::complete_mod");
@@ -49,9 +50,13 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
49 .filter_map(|submodule_file| { 50 .filter_map(|submodule_file| {
50 let submodule_path = source_root.path_for_file(&submodule_file)?; 51 let submodule_path = source_root.path_for_file(&submodule_file)?;
51 let directory_with_submodule = submodule_path.parent()?; 52 let directory_with_submodule = submodule_path.parent()?;
52 match submodule_path.name_and_extension()? { 53 let (name, ext) = submodule_path.name_and_extension()?;
53 ("lib", Some("rs")) | ("main", Some("rs")) => None, 54 if ext != Some("rs") {
54 ("mod", Some("rs")) => { 55 return None;
56 }
57 match name {
58 "lib" | "main" => None,
59 "mod" => {
55 if directory_with_submodule.parent()? == directory_to_look_for_submodules { 60 if directory_with_submodule.parent()? == directory_to_look_for_submodules {
56 match directory_with_submodule.name_and_extension()? { 61 match directory_with_submodule.name_and_extension()? {
57 (directory_name, None) => Some(directory_name.to_owned()), 62 (directory_name, None) => Some(directory_name.to_owned()),
@@ -61,9 +66,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
61 None 66 None
62 } 67 }
63 } 68 }
64 (file_name, Some("rs")) 69 file_name if directory_with_submodule == directory_to_look_for_submodules => {
65 if directory_with_submodule == directory_to_look_for_submodules =>
66 {
67 Some(file_name.to_owned()) 70 Some(file_name.to_owned())
68 } 71 }
69 _ => None, 72 _ => None,
@@ -73,7 +76,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
73 .for_each(|submodule_name| { 76 .for_each(|submodule_name| {
74 let mut label = submodule_name; 77 let mut label = submodule_name;
75 if mod_under_caret.semicolon_token().is_none() { 78 if mod_under_caret.semicolon_token().is_none() {
76 label.push(';') 79 label.push(';');
77 } 80 }
78 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) 81 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label)
79 .kind(CompletionItemKind::Module) 82 .kind(CompletionItemKind::Module)
@@ -89,11 +92,13 @@ fn directory_to_look_for_submodules(
89 module_file_path: &VfsPath, 92 module_file_path: &VfsPath,
90) -> Option<VfsPath> { 93) -> Option<VfsPath> {
91 let directory_with_module_path = module_file_path.parent()?; 94 let directory_with_module_path = module_file_path.parent()?;
92 let base_directory = match module_file_path.name_and_extension()? { 95 let (name, ext) = module_file_path.name_and_extension()?;
93 ("mod", Some("rs")) | ("lib", Some("rs")) | ("main", Some("rs")) => { 96 if ext != Some("rs") {
94 Some(directory_with_module_path) 97 return None;
95 } 98 }
96 (regular_rust_file_name, Some("rs")) => { 99 let base_directory = match name {
100 "mod" | "lib" | "main" => Some(directory_with_module_path),
101 regular_rust_file_name => {
97 if matches!( 102 if matches!(
98 ( 103 (
99 directory_with_module_path 104 directory_with_module_path
@@ -110,37 +115,25 @@ fn directory_to_look_for_submodules(
110 directory_with_module_path.join(regular_rust_file_name) 115 directory_with_module_path.join(regular_rust_file_name)
111 } 116 }
112 } 117 }
113 _ => None,
114 }?; 118 }?;
115 119
116 let mut resulting_path = base_directory; 120 module_chain_to_containing_module_file(module, db)
117 for module in module_chain_to_containing_module_file(module, db) { 121 .into_iter()
118 if let Some(name) = module.name(db) { 122 .filter_map(|module| module.name(db))
119 resulting_path = resulting_path.join(&name.to_string())?; 123 .try_fold(base_directory, |path, name| path.join(&name.to_string()))
120 }
121 }
122
123 Some(resulting_path)
124} 124}
125 125
126fn module_chain_to_containing_module_file( 126fn module_chain_to_containing_module_file(
127 current_module: Module, 127 current_module: Module,
128 db: &RootDatabase, 128 db: &RootDatabase,
129) -> Vec<Module> { 129) -> Vec<Module> {
130 let mut path = Vec::new(); 130 let mut path =
131 131 iter::successors(Some(current_module), |current_module| current_module.parent(db))
132 let mut current_module = Some(current_module); 132 .take_while(|current_module| {
133 while let Some(ModuleSource::Module(_)) = 133 matches!(current_module.definition_source(db).value, ModuleSource::Module(_))
134 current_module.map(|module| module.definition_source(db).value) 134 })
135 { 135 .collect::<Vec<_>>();
136 if let Some(module) = current_module { 136 path.reverse();
137 path.insert(0, module);
138 current_module = module.parent(db);
139 } else {
140 current_module = None;
141 }
142 }
143
144 path 137 path
145} 138}
146 139
@@ -159,7 +152,7 @@ mod tests {
159 check( 152 check(
160 r#" 153 r#"
161 //- /lib.rs 154 //- /lib.rs
162 mod <|> 155 mod $0
163 //- /foo.rs 156 //- /foo.rs
164 fn foo() {} 157 fn foo() {}
165 //- /foo/ignored_foo.rs 158 //- /foo/ignored_foo.rs
@@ -181,7 +174,7 @@ mod tests {
181 check( 174 check(
182 r#" 175 r#"
183 //- /lib.rs 176 //- /lib.rs
184 mod <|> { 177 mod $0 {
185 178
186 } 179 }
187 //- /foo.rs 180 //- /foo.rs
@@ -196,7 +189,7 @@ mod tests {
196 check( 189 check(
197 r#" 190 r#"
198 //- /main.rs 191 //- /main.rs
199 mod <|> 192 mod $0
200 //- /foo.rs 193 //- /foo.rs
201 fn foo() {} 194 fn foo() {}
202 //- /foo/ignored_foo.rs 195 //- /foo/ignored_foo.rs
@@ -219,7 +212,7 @@ mod tests {
219 r#" 212 r#"
220 //- /main.rs 213 //- /main.rs
221 mod tests { 214 mod tests {
222 mod <|>; 215 mod $0;
223 } 216 }
224 //- /tests/foo.rs 217 //- /tests/foo.rs
225 fn foo() {} 218 fn foo() {}
@@ -237,7 +230,7 @@ mod tests {
237 //- /lib.rs 230 //- /lib.rs
238 mod foo; 231 mod foo;
239 //- /foo.rs 232 //- /foo.rs
240 mod <|>; 233 mod $0;
241 //- /foo/bar.rs 234 //- /foo/bar.rs
242 fn bar() {} 235 fn bar() {}
243 //- /foo/bar/ignored_bar.rs 236 //- /foo/bar/ignored_bar.rs
@@ -262,7 +255,7 @@ mod tests {
262 mod foo; 255 mod foo;
263 //- /foo.rs 256 //- /foo.rs
264 mod bar { 257 mod bar {
265 mod <|> 258 mod $0
266 } 259 }
267 //- /foo/bar/baz.rs 260 //- /foo/bar/baz.rs
268 fn baz() {} 261 fn baz() {}
@@ -288,7 +281,7 @@ mod tests {
288 // //- /src/bin.rs 281 // //- /src/bin.rs
289 // fn main() {} 282 // fn main() {}
290 // //- /src/bin/foo.rs 283 // //- /src/bin/foo.rs
291 // mod <|> 284 // mod $0
292 // //- /src/bin/bar.rs 285 // //- /src/bin/bar.rs
293 // fn bar() {} 286 // fn bar() {}
294 // //- /src/bin/bar/bar_ignored.rs 287 // //- /src/bin/bar/bar_ignored.rs
@@ -307,7 +300,7 @@ mod tests {
307 //- /src/bin.rs crate:main 300 //- /src/bin.rs crate:main
308 fn main() {} 301 fn main() {}
309 //- /src/bin/foo.rs 302 //- /src/bin/foo.rs
310 mod <|> 303 mod $0
311 //- /src/bin/bar.rs 304 //- /src/bin/bar.rs
312 mod foo; 305 mod foo;
313 fn bar() {} 306 fn bar() {}
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs
index eee31098d..595160ff5 100644
--- a/crates/completion/src/completions/pattern.rs
+++ b/crates/completion/src/completions/pattern.rs
@@ -71,7 +71,7 @@ static FOO: E = E::X;
71struct Bar { f: u32 } 71struct Bar { f: u32 }
72 72
73fn foo() { 73fn foo() {
74 match E::X { <|> } 74 match E::X { $0 }
75} 75}
76"#, 76"#,
77 expect![[r#" 77 expect![[r#"
@@ -92,7 +92,7 @@ macro_rules! m { ($e:expr) => { $e } }
92enum E { X } 92enum E { X }
93 93
94fn foo() { 94fn foo() {
95 m!(match E::X { <|> }) 95 m!(match E::X { $0 })
96} 96}
97"#, 97"#,
98 expect![[r#" 98 expect![[r#"
@@ -115,7 +115,7 @@ static FOO: E = E::X;
115struct Bar { f: u32 } 115struct Bar { f: u32 }
116 116
117fn foo() { 117fn foo() {
118 let <|> 118 let $0
119} 119}
120"#, 120"#,
121 expect![[r#" 121 expect![[r#"
@@ -133,7 +133,7 @@ enum E { X }
133static FOO: E = E::X; 133static FOO: E = E::X;
134struct Bar { f: u32 } 134struct Bar { f: u32 }
135 135
136fn foo(<|>) { 136fn foo($0) {
137} 137}
138"#, 138"#,
139 expect![[r#" 139 expect![[r#"
@@ -149,7 +149,7 @@ fn foo(<|>) {
149struct Bar { f: u32 } 149struct Bar { f: u32 }
150 150
151fn foo() { 151fn foo() {
152 let <|> 152 let $0
153} 153}
154"#, 154"#,
155 expect![[r#" 155 expect![[r#"
@@ -165,7 +165,7 @@ fn foo() {
165struct Foo { bar: String, baz: String } 165struct Foo { bar: String, baz: String }
166struct Bar(String, String); 166struct Bar(String, String);
167struct Baz; 167struct Baz;
168fn outer(<|>) {} 168fn outer($0) {}
169"#, 169"#,
170 expect![[r#" 170 expect![[r#"
171 bn Foo Foo { bar$1, baz$2 }: Foo$0 171 bn Foo Foo { bar$1, baz$2 }: Foo$0
@@ -182,7 +182,7 @@ struct Foo { bar: String, baz: String }
182struct Bar(String, String); 182struct Bar(String, String);
183struct Baz; 183struct Baz;
184fn outer() { 184fn outer() {
185 let <|> 185 let $0
186} 186}
187"#, 187"#,
188 expect![[r#" 188 expect![[r#"
@@ -201,7 +201,7 @@ struct Bar(String, String);
201struct Baz; 201struct Baz;
202fn outer() { 202fn outer() {
203 match () { 203 match () {
204 <|> 204 $0
205 } 205 }
206} 206}
207"#, 207"#,
@@ -225,7 +225,7 @@ use foo::*;
225 225
226fn outer() { 226fn outer() {
227 match () { 227 match () {
228 <|> 228 $0
229 } 229 }
230} 230}
231"#, 231"#,
@@ -244,7 +244,7 @@ fn outer() {
244struct Foo(i32); 244struct Foo(i32);
245fn main() { 245fn main() {
246 match Foo(92) { 246 match Foo(92) {
247 <|>(92) => (), 247 $0(92) => (),
248 } 248 }
249} 249}
250"#, 250"#,
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs
index 4888f518a..9c34ed0b6 100644
--- a/crates/completion/src/completions/postfix.rs
+++ b/crates/completion/src/completions/postfix.rs
@@ -1,4 +1,4 @@
1//! Postfix completions, like `Ok(10).ifl<|>` => `if let Ok() = Ok(10) { <|> }`. 1//! Postfix completions, like `Ok(10).ifl$0` => `if let Ok() = Ok(10) { $0 }`.
2 2
3mod format_like; 3mod format_like;
4 4
@@ -35,11 +35,14 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
35 None => return, 35 None => return,
36 }; 36 };
37 37
38 let ref_removed_ty =
39 std::iter::successors(Some(receiver_ty.clone()), |ty| ty.remove_ref()).last().unwrap();
40
38 let cap = match ctx.config.snippet_cap { 41 let cap = match ctx.config.snippet_cap {
39 Some(it) => it, 42 Some(it) => it,
40 None => return, 43 None => return,
41 }; 44 };
42 let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty); 45 let try_enum = TryEnum::from_ty(&ctx.sema, &ref_removed_ty);
43 if let Some(try_enum) = &try_enum { 46 if let Some(try_enum) = &try_enum {
44 match try_enum { 47 match try_enum {
45 TryEnum::Result => { 48 TryEnum::Result => {
@@ -310,7 +313,7 @@ mod tests {
310 r#" 313 r#"
311fn main() { 314fn main() {
312 let bar = true; 315 let bar = true;
313 bar.<|> 316 bar.$0
314} 317}
315"#, 318"#,
316 expect![[r#" 319 expect![[r#"
@@ -342,7 +345,7 @@ fn foo(elt: bool) -> bool {
342 345
343fn main() { 346fn main() {
344 let bar = true; 347 let bar = true;
345 foo(bar.<|>) 348 foo(bar.$0)
346} 349}
347"#, 350"#,
348 expect![[r#" 351 expect![[r#"
@@ -368,7 +371,7 @@ fn main() {
368 r#" 371 r#"
369fn main() { 372fn main() {
370 let bar: u8 = 12; 373 let bar: u8 = 12;
371 bar.<|> 374 bar.$0
372} 375}
373"#, 376"#,
374 expect![[r#" 377 expect![[r#"
@@ -392,7 +395,7 @@ fn main() {
392 check( 395 check(
393 r#" 396 r#"
394fn main() { 397fn main() {
395 baz.l<|> 398 baz.l$0
396 res 399 res
397} 400}
398"#, 401"#,
@@ -424,7 +427,7 @@ enum Option<T> { Some(T), None }
424 427
425fn main() { 428fn main() {
426 let bar = Option::Some(true); 429 let bar = Option::Some(true);
427 bar.<|> 430 bar.$0
428} 431}
429"#, 432"#,
430 r#" 433 r#"
@@ -449,7 +452,7 @@ enum Result<T, E> { Ok(T), Err(E) }
449 452
450fn main() { 453fn main() {
451 let bar = Result::Ok(true); 454 let bar = Result::Ok(true);
452 bar.<|> 455 bar.$0
453} 456}
454"#, 457"#,
455 r#" 458 r#"
@@ -468,7 +471,7 @@ fn main() {
468 471
469 #[test] 472 #[test]
470 fn postfix_completion_works_for_ambiguous_float_literal() { 473 fn postfix_completion_works_for_ambiguous_float_literal() {
471 check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#) 474 check_edit("refm", r#"fn main() { 42.$0 }"#, r#"fn main() { &mut 42 }"#)
472 } 475 }
473 476
474 #[test] 477 #[test]
@@ -479,7 +482,7 @@ fn main() {
479macro_rules! m { ($e:expr) => { $e } } 482macro_rules! m { ($e:expr) => { $e } }
480fn main() { 483fn main() {
481 let bar: u8 = 12; 484 let bar: u8 = 12;
482 m!(bar.d<|>) 485 m!(bar.d$0)
483} 486}
484"#, 487"#,
485 r#" 488 r#"
@@ -494,55 +497,68 @@ fn main() {
494 497
495 #[test] 498 #[test]
496 fn postfix_completion_for_references() { 499 fn postfix_completion_for_references() {
497 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#); 500 check_edit("dbg", r#"fn main() { &&42.$0 }"#, r#"fn main() { dbg!(&&42) }"#);
498 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#); 501 check_edit("refm", r#"fn main() { &&42.$0 }"#, r#"fn main() { &&&mut 42 }"#);
502 check_edit(
503 "ifl",
504 r#"
505enum Option<T> { Some(T), None }
506
507fn main() {
508 let bar = &Option::Some(true);
509 bar.$0
510}
511"#,
512 r#"
513enum Option<T> { Some(T), None }
514
515fn main() {
516 let bar = &Option::Some(true);
517 if let Some($1) = bar {
518 $0
519}
520}
521"#,
522 )
499 } 523 }
500 524
501 #[test] 525 #[test]
502 fn postfix_completion_for_format_like_strings() { 526 fn postfix_completion_for_format_like_strings() {
503 check_edit( 527 check_edit(
504 "format", 528 "format",
505 r#"fn main() { "{some_var:?}".<|> }"#, 529 r#"fn main() { "{some_var:?}".$0 }"#,
506 r#"fn main() { format!("{:?}", some_var) }"#, 530 r#"fn main() { format!("{:?}", some_var) }"#,
507 ); 531 );
508 check_edit( 532 check_edit(
509 "panic", 533 "panic",
510 r#"fn main() { "Panic with {a}".<|> }"#, 534 r#"fn main() { "Panic with {a}".$0 }"#,
511 r#"fn main() { panic!("Panic with {}", a) }"#, 535 r#"fn main() { panic!("Panic with {}", a) }"#,
512 ); 536 );
513 check_edit( 537 check_edit(
514 "println", 538 "println",
515 r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".<|> }"#, 539 r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"#,
516 r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#, 540 r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"#,
517 ); 541 );
518 check_edit( 542 check_edit(
519 "loge", 543 "loge",
520 r#"fn main() { "{2+2}".<|> }"#, 544 r#"fn main() { "{2+2}".$0 }"#,
521 r#"fn main() { log::error!("{}", 2+2) }"#, 545 r#"fn main() { log::error!("{}", 2+2) }"#,
522 ); 546 );
523 check_edit( 547 check_edit(
524 "logt", 548 "logt",
525 r#"fn main() { "{2+2}".<|> }"#, 549 r#"fn main() { "{2+2}".$0 }"#,
526 r#"fn main() { log::trace!("{}", 2+2) }"#, 550 r#"fn main() { log::trace!("{}", 2+2) }"#,
527 ); 551 );
528 check_edit( 552 check_edit(
529 "logd", 553 "logd",
530 r#"fn main() { "{2+2}".<|> }"#, 554 r#"fn main() { "{2+2}".$0 }"#,
531 r#"fn main() { log::debug!("{}", 2+2) }"#, 555 r#"fn main() { log::debug!("{}", 2+2) }"#,
532 ); 556 );
533 check_edit( 557 check_edit("logi", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::info!("{}", 2+2) }"#);
534 "logi", 558 check_edit("logw", r#"fn main() { "{2+2}".$0 }"#, r#"fn main() { log::warn!("{}", 2+2) }"#);
535 r#"fn main() { "{2+2}".<|> }"#,
536 r#"fn main() { log::info!("{}", 2+2) }"#,
537 );
538 check_edit(
539 "logw",
540 r#"fn main() { "{2+2}".<|> }"#,
541 r#"fn main() { log::warn!("{}", 2+2) }"#,
542 );
543 check_edit( 559 check_edit(
544 "loge", 560 "loge",
545 r#"fn main() { "{2+2}".<|> }"#, 561 r#"fn main() { "{2+2}".$0 }"#,
546 r#"fn main() { log::error!("{}", 2+2) }"#, 562 r#"fn main() { log::error!("{}", 2+2) }"#,
547 ); 563 );
548 } 564 }
diff --git a/crates/completion/src/completions/qualified_path.rs b/crates/completion/src/completions/qualified_path.rs
index 882c4dcbc..33df26761 100644
--- a/crates/completion/src/completions/qualified_path.rs
+++ b/crates/completion/src/completions/qualified_path.rs
@@ -1,4 +1,4 @@
1//! Completion of paths, i.e. `some::prefix::<|>`. 1//! Completion of paths, i.e. `some::prefix::$0`.
2 2
3use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; 3use hir::{Adt, HasVisibility, PathResolution, ScopeDef};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
@@ -38,7 +38,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
38 if let ScopeDef::Unknown = def { 38 if let ScopeDef::Unknown = def {
39 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { 39 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
40 if name_ref.syntax().text() == name.to_string().as_str() { 40 if name_ref.syntax().text() == name.to_string().as_str() {
41 // for `use self::foo<|>`, don't suggest `foo` as a completion 41 // for `use self::foo$0`, don't suggest `foo` as a completion
42 mark::hit!(dont_complete_current_use); 42 mark::hit!(dont_complete_current_use);
43 continue; 43 continue;
44 } 44 }
@@ -173,7 +173,7 @@ mod tests {
173 #[test] 173 #[test]
174 fn dont_complete_current_use() { 174 fn dont_complete_current_use() {
175 mark::check!(dont_complete_current_use); 175 mark::check!(dont_complete_current_use);
176 check(r#"use self::foo<|>;"#, expect![[""]]); 176 check(r#"use self::foo$0;"#, expect![[""]]);
177 } 177 }
178 178
179 #[test] 179 #[test]
@@ -181,7 +181,7 @@ mod tests {
181 check( 181 check(
182 r#" 182 r#"
183mod foo { pub struct S; } 183mod foo { pub struct S; }
184use self::{foo::*, bar<|>}; 184use self::{foo::*, bar$0};
185"#, 185"#,
186 expect![[r#" 186 expect![[r#"
187 st S 187 st S
@@ -192,18 +192,18 @@ use self::{foo::*, bar<|>};
192 192
193 #[test] 193 #[test]
194 fn dont_complete_primitive_in_use() { 194 fn dont_complete_primitive_in_use() {
195 check_builtin(r#"use self::<|>;"#, expect![[""]]); 195 check_builtin(r#"use self::$0;"#, expect![[""]]);
196 } 196 }
197 197
198 #[test] 198 #[test]
199 fn dont_complete_primitive_in_module_scope() { 199 fn dont_complete_primitive_in_module_scope() {
200 check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]); 200 check_builtin(r#"fn foo() { self::$0 }"#, expect![[""]]);
201 } 201 }
202 202
203 #[test] 203 #[test]
204 fn completes_primitives() { 204 fn completes_primitives() {
205 check_builtin( 205 check_builtin(
206 r#"fn main() { let _: <|> = 92; }"#, 206 r#"fn main() { let _: $0 = 92; }"#,
207 expect![[r#" 207 expect![[r#"
208 bt u32 208 bt u32
209 bt bool 209 bt bool
@@ -230,7 +230,7 @@ use self::{foo::*, bar<|>};
230 fn completes_mod_with_same_name_as_function() { 230 fn completes_mod_with_same_name_as_function() {
231 check( 231 check(
232 r#" 232 r#"
233use self::my::<|>; 233use self::my::$0;
234 234
235mod my { pub struct Bar; } 235mod my { pub struct Bar; }
236fn my() {} 236fn my() {}
@@ -245,7 +245,7 @@ fn my() {}
245 fn filters_visibility() { 245 fn filters_visibility() {
246 check( 246 check(
247 r#" 247 r#"
248use self::my::<|>; 248use self::my::$0;
249 249
250mod my { 250mod my {
251 struct Bar; 251 struct Bar;
@@ -264,7 +264,7 @@ mod my {
264 fn completes_use_item_starting_with_self() { 264 fn completes_use_item_starting_with_self() {
265 check( 265 check(
266 r#" 266 r#"
267use self::m::<|>; 267use self::m::$0;
268 268
269mod m { pub struct Bar; } 269mod m { pub struct Bar; }
270"#, 270"#,
@@ -282,7 +282,7 @@ mod m { pub struct Bar; }
282mod foo; 282mod foo;
283struct Spam; 283struct Spam;
284//- /foo.rs 284//- /foo.rs
285use crate::Sp<|> 285use crate::Sp$0
286"#, 286"#,
287 expect![[r#" 287 expect![[r#"
288 md foo 288 md foo
@@ -299,7 +299,7 @@ use crate::Sp<|>
299mod foo; 299mod foo;
300struct Spam; 300struct Spam;
301//- /foo.rs 301//- /foo.rs
302use crate::{Sp<|>}; 302use crate::{Sp$0};
303"#, 303"#,
304 expect![[r#" 304 expect![[r#"
305 md foo 305 md foo
@@ -320,7 +320,7 @@ pub mod bar {
320 } 320 }
321} 321}
322//- /foo.rs 322//- /foo.rs
323use crate::{bar::{baz::Sp<|>}}; 323use crate::{bar::{baz::Sp$0}};
324"#, 324"#,
325 expect![[r#" 325 expect![[r#"
326 st Spam 326 st Spam
@@ -333,7 +333,7 @@ use crate::{bar::{baz::Sp<|>}};
333 check( 333 check(
334 r#" 334 r#"
335enum E { Foo, Bar(i32) } 335enum E { Foo, Bar(i32) }
336fn foo() { let _ = E::<|> } 336fn foo() { let _ = E::$0 }
337"#, 337"#,
338 expect![[r#" 338 expect![[r#"
339 ev Foo () 339 ev Foo ()
@@ -356,7 +356,7 @@ impl S {
356 type T = i32; 356 type T = i32;
357} 357}
358 358
359fn foo() { let _ = S::<|> } 359fn foo() { let _ = S::$0 }
360"#, 360"#,
361 expect![[r#" 361 expect![[r#"
362 fn a() fn a() 362 fn a() fn a()
@@ -384,7 +384,7 @@ mod m {
384 } 384 }
385} 385}
386 386
387fn foo() { let _ = S::<|> } 387fn foo() { let _ = S::$0 }
388"#, 388"#,
389 expect![[r#" 389 expect![[r#"
390 fn public_method() pub(crate) fn public_method() 390 fn public_method() pub(crate) fn public_method()
@@ -401,7 +401,7 @@ fn foo() { let _ = S::<|> }
401enum E {}; 401enum E {};
402impl E { fn m() { } } 402impl E { fn m() { } }
403 403
404fn foo() { let _ = E::<|> } 404fn foo() { let _ = E::$0 }
405 "#, 405 "#,
406 expect![[r#" 406 expect![[r#"
407 fn m() fn m() 407 fn m() fn m()
@@ -416,7 +416,7 @@ fn foo() { let _ = E::<|> }
416union U {}; 416union U {};
417impl U { fn m() { } } 417impl U { fn m() { } }
418 418
419fn foo() { let _ = U::<|> } 419fn foo() { let _ = U::$0 }
420"#, 420"#,
421 expect![[r#" 421 expect![[r#"
422 fn m() fn m() 422 fn m() fn m()
@@ -429,7 +429,7 @@ fn foo() { let _ = U::<|> }
429 check( 429 check(
430 r#" 430 r#"
431//- /main.rs crate:main deps:foo 431//- /main.rs crate:main deps:foo
432use foo::<|>; 432use foo::$0;
433 433
434//- /foo/lib.rs crate:foo 434//- /foo/lib.rs crate:foo
435pub mod bar { pub struct S; } 435pub mod bar { pub struct S; }
@@ -446,7 +446,7 @@ pub mod bar { pub struct S; }
446 r#" 446 r#"
447trait Trait { fn m(); } 447trait Trait { fn m(); }
448 448
449fn foo() { let _ = Trait::<|> } 449fn foo() { let _ = Trait::$0 }
450"#, 450"#,
451 expect![[r#" 451 expect![[r#"
452 fn m() fn m() 452 fn m() fn m()
@@ -463,7 +463,7 @@ trait Trait { fn m(); }
463struct S; 463struct S;
464impl Trait for S {} 464impl Trait for S {}
465 465
466fn foo() { let _ = S::<|> } 466fn foo() { let _ = S::$0 }
467"#, 467"#,
468 expect![[r#" 468 expect![[r#"
469 fn m() fn m() 469 fn m() fn m()
@@ -480,7 +480,7 @@ trait Trait { fn m(); }
480struct S; 480struct S;
481impl Trait for S {} 481impl Trait for S {}
482 482
483fn foo() { let _ = <S as Trait>::<|> } 483fn foo() { let _ = <S as Trait>::$0 }
484"#, 484"#,
485 expect![[r#" 485 expect![[r#"
486 fn m() fn m() 486 fn m() fn m()
@@ -506,7 +506,7 @@ trait Sub: Super {
506 fn submethod(&self) {} 506 fn submethod(&self) {}
507} 507}
508 508
509fn foo<T: Sub>() { T::<|> } 509fn foo<T: Sub>() { T::$0 }
510"#, 510"#,
511 expect![[r#" 511 expect![[r#"
512 ta SubTy type SubTy; 512 ta SubTy type SubTy;
@@ -544,7 +544,7 @@ impl<T> Super for Wrap<T> {}
544impl<T> Sub for Wrap<T> { 544impl<T> Sub for Wrap<T> {
545 fn subfunc() { 545 fn subfunc() {
546 // Should be able to assume `Self: Sub + Super` 546 // Should be able to assume `Self: Sub + Super`
547 Self::<|> 547 Self::$0
548 } 548 }
549} 549}
550"#, 550"#,
@@ -570,7 +570,7 @@ impl S { fn foo() {} }
570type T = S; 570type T = S;
571impl T { fn bar() {} } 571impl T { fn bar() {} }
572 572
573fn main() { T::<|>; } 573fn main() { T::$0; }
574"#, 574"#,
575 expect![[r#" 575 expect![[r#"
576 fn foo() fn foo() 576 fn foo() fn foo()
@@ -586,12 +586,11 @@ fn main() { T::<|>; }
586#[macro_export] 586#[macro_export]
587macro_rules! foo { () => {} } 587macro_rules! foo { () => {} }
588 588
589fn main() { let _ = crate::<|> } 589fn main() { let _ = crate::$0 }
590 "#, 590 "#,
591 expect![[r##" 591 expect![[r##"
592 fn main() fn main() 592 fn main() fn main()
593 ma foo!(…) #[macro_export] 593 ma foo!(…) #[macro_export] macro_rules! foo
594 macro_rules! foo
595 "##]], 594 "##]],
596 ); 595 );
597 } 596 }
@@ -604,7 +603,7 @@ mod a {
604 const A: usize = 0; 603 const A: usize = 0;
605 mod b { 604 mod b {
606 const B: usize = 0; 605 const B: usize = 0;
607 mod c { use super::super::<|> } 606 mod c { use super::super::$0 }
608 } 607 }
609} 608}
610"#, 609"#,
@@ -619,7 +618,7 @@ mod a {
619 fn completes_reexported_items_under_correct_name() { 618 fn completes_reexported_items_under_correct_name() {
620 check( 619 check(
621 r#" 620 r#"
622fn foo() { self::m::<|> } 621fn foo() { self::m::$0 }
623 622
624mod m { 623mod m {
625 pub use super::p::wrong_fn as right_fn; 624 pub use super::p::wrong_fn as right_fn;
@@ -642,7 +641,7 @@ mod p {
642 check_edit( 641 check_edit(
643 "RightType", 642 "RightType",
644 r#" 643 r#"
645fn foo() { self::m::<|> } 644fn foo() { self::m::$0 }
646 645
647mod m { 646mod m {
648 pub use super::p::wrong_fn as right_fn; 647 pub use super::p::wrong_fn as right_fn;
@@ -677,7 +676,7 @@ mod p {
677 check( 676 check(
678 r#" 677 r#"
679macro_rules! m { ($e:expr) => { $e } } 678macro_rules! m { ($e:expr) => { $e } }
680fn main() { m!(self::f<|>); } 679fn main() { m!(self::f$0); }
681fn foo() {} 680fn foo() {}
682"#, 681"#,
683 expect![[r#" 682 expect![[r#"
@@ -691,7 +690,7 @@ fn foo() {}
691 fn function_mod_share_name() { 690 fn function_mod_share_name() {
692 check( 691 check(
693 r#" 692 r#"
694fn foo() { self::m::<|> } 693fn foo() { self::m::$0 }
695 694
696mod m { 695mod m {
697 pub mod z {} 696 pub mod z {}
@@ -716,7 +715,7 @@ impl<K, V> HashMap<K, V, RandomState> {
716 pub fn new() -> HashMap<K, V, RandomState> { } 715 pub fn new() -> HashMap<K, V, RandomState> { }
717} 716}
718fn foo() { 717fn foo() {
719 HashMap::<|> 718 HashMap::$0
720} 719}
721"#, 720"#,
722 expect![[r#" 721 expect![[r#"
@@ -730,7 +729,7 @@ fn foo() {
730 check( 729 check(
731 r#" 730 r#"
732mod foo { pub struct Foo; } 731mod foo { pub struct Foo; }
733#[foo::<|>] 732#[foo::$0]
734fn f() {} 733fn f() {}
735"#, 734"#,
736 expect![[""]], 735 expect![[""]],
@@ -749,7 +748,7 @@ fn foo(
749} 748}
750 749
751fn main() { 750fn main() {
752 fo<|> 751 fo$0
753} 752}
754"#, 753"#,
755 expect![[r#" 754 expect![[r#"
@@ -770,7 +769,7 @@ enum Foo {
770 769
771impl Foo { 770impl Foo {
772 fn foo(self) { 771 fn foo(self) {
773 Self::<|> 772 Self::$0
774 } 773 }
775} 774}
776"#, 775"#,
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs
index e58b9a274..bb6354ded 100644
--- a/crates/completion/src/completions/record.rs
+++ b/crates/completion/src/completions/record.rs
@@ -99,7 +99,7 @@ impl core::default::Default for S {
99fn process(f: S) { 99fn process(f: S) {
100 let other = S { 100 let other = S {
101 foo: 5, 101 foo: 5,
102 .<|> 102 .$0
103 }; 103 };
104} 104}
105"#; 105"#;
@@ -139,7 +139,7 @@ impl core::default::Default for S {
139fn process(f: S) { 139fn process(f: S) {
140 let other = S { 140 let other = S {
141 foo: 5, 141 foo: 5,
142 .<|> 142 .$0
143 }; 143 };
144} 144}
145"#, 145"#,
@@ -173,7 +173,7 @@ struct S { foo: u32, bar: usize }
173fn process(f: S) { 173fn process(f: S) {
174 let other = S { 174 let other = S {
175 foo: 5, 175 foo: 5,
176 .<|> 176 .$0
177 }; 177 };
178} 178}
179"#; 179"#;
@@ -201,7 +201,7 @@ struct S { foo: u32 }
201 201
202fn process(f: S) { 202fn process(f: S) {
203 match f { 203 match f {
204 S { f<|>: 92 } => (), 204 S { f$0: 92 } => (),
205 } 205 }
206} 206}
207"#, 207"#,
@@ -219,7 +219,7 @@ enum E { S { foo: u32, bar: () } }
219 219
220fn process(e: E) { 220fn process(e: E) {
221 match e { 221 match e {
222 E::S { <|> } => (), 222 E::S { $0 } => (),
223 } 223 }
224} 224}
225"#, 225"#,
@@ -239,7 +239,7 @@ struct S { foo: u32 }
239 239
240fn process(f: S) { 240fn process(f: S) {
241 m!(match f { 241 m!(match f {
242 S { f<|>: 92 } => (), 242 S { f$0: 92 } => (),
243 }) 243 })
244} 244}
245", 245",
@@ -263,7 +263,7 @@ fn main() {
263 foo1: 1, foo2: 2, 263 foo1: 1, foo2: 2,
264 bar: 3, baz: 4, 264 bar: 3, baz: 4,
265 }; 265 };
266 if let S { foo1, foo2: a, <|> } = s {} 266 if let S { foo1, foo2: a, $0 } = s {}
267} 267}
268"#, 268"#,
269 expect![[r#" 269 expect![[r#"
@@ -279,7 +279,7 @@ fn main() {
279 r#" 279 r#"
280struct A { the_field: u32 } 280struct A { the_field: u32 }
281fn foo() { 281fn foo() {
282 A { the<|> } 282 A { the$0 }
283} 283}
284"#, 284"#,
285 expect![[r#" 285 expect![[r#"
@@ -294,7 +294,7 @@ fn foo() {
294 r#" 294 r#"
295enum E { A { a: u32 } } 295enum E { A { a: u32 } }
296fn foo() { 296fn foo() {
297 let _ = E::A { <|> } 297 let _ = E::A { $0 }
298} 298}
299"#, 299"#,
300 expect![[r#" 300 expect![[r#"
@@ -311,7 +311,7 @@ struct A { a: u32 }
311struct B { b: u32 } 311struct B { b: u32 }
312 312
313fn foo() { 313fn foo() {
314 let _: A = B { <|> } 314 let _: A = B { $0 }
315} 315}
316"#, 316"#,
317 expect![[r#" 317 expect![[r#"
@@ -327,7 +327,7 @@ fn foo() {
327struct A<T> { a: T } 327struct A<T> { a: T }
328 328
329fn foo() { 329fn foo() {
330 let _: A<u32> = A { <|> } 330 let _: A<u32> = A { $0 }
331} 331}
332"#, 332"#,
333 expect![[r#" 333 expect![[r#"
@@ -343,7 +343,7 @@ fn foo() {
343macro_rules! m { ($e:expr) => { $e } } 343macro_rules! m { ($e:expr) => { $e } }
344struct A { the_field: u32 } 344struct A { the_field: u32 }
345fn foo() { 345fn foo() {
346 m!(A { the<|> }) 346 m!(A { the$0 })
347} 347}
348"#, 348"#,
349 expect![[r#" 349 expect![[r#"
@@ -363,7 +363,7 @@ struct S {
363 363
364fn main() { 364fn main() {
365 let foo1 = 1; 365 let foo1 = 1;
366 let s = S { foo1, foo2: 5, <|> } 366 let s = S { foo1, foo2: 5, $0 }
367} 367}
368"#, 368"#,
369 expect![[r#" 369 expect![[r#"
@@ -381,7 +381,7 @@ struct S { foo1: u32, foo2: u32 }
381 381
382fn main() { 382fn main() {
383 let foo1 = 1; 383 let foo1 = 1;
384 let s = S { foo1, <|> .. loop {} } 384 let s = S { foo1, $0 .. loop {} }
385} 385}
386"#, 386"#,
387 expect![[r#" 387 expect![[r#"
diff --git a/crates/completion/src/completions/snippet.rs b/crates/completion/src/completions/snippet.rs
index b5e704696..df17a15c5 100644
--- a/crates/completion/src/completions/snippet.rs
+++ b/crates/completion/src/completions/snippet.rs
@@ -83,7 +83,7 @@ mod tests {
83 #[test] 83 #[test]
84 fn completes_snippets_in_expressions() { 84 fn completes_snippets_in_expressions() {
85 check( 85 check(
86 r#"fn foo(x: i32) { <|> }"#, 86 r#"fn foo(x: i32) { $0 }"#,
87 expect![[r#" 87 expect![[r#"
88 sn pd 88 sn pd
89 sn ppd 89 sn ppd
@@ -93,8 +93,8 @@ mod tests {
93 93
94 #[test] 94 #[test]
95 fn should_not_complete_snippets_in_path() { 95 fn should_not_complete_snippets_in_path() {
96 check(r#"fn foo(x: i32) { ::foo<|> }"#, expect![[""]]); 96 check(r#"fn foo(x: i32) { ::foo$0 }"#, expect![[""]]);
97 check(r#"fn foo(x: i32) { ::<|> }"#, expect![[""]]); 97 check(r#"fn foo(x: i32) { ::$0 }"#, expect![[""]]);
98 } 98 }
99 99
100 #[test] 100 #[test]
@@ -103,7 +103,7 @@ mod tests {
103 r#" 103 r#"
104#[cfg(test)] 104#[cfg(test)]
105mod tests { 105mod tests {
106 <|> 106 $0
107} 107}
108"#, 108"#,
109 expect![[r#" 109 expect![[r#"
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index 54bb897e9..135ae49dc 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -15,7 +15,7 @@
15//! } 15//! }
16//! 16//!
17//! impl SomeTrait for () { 17//! impl SomeTrait for () {
18//! fn f<|> 18//! fn f$0
19//! } 19//! }
20//! ``` 20//! ```
21//! 21//!
@@ -27,7 +27,7 @@
27//! # } 27//! # }
28//! 28//!
29//! impl SomeTrait for () { 29//! impl SomeTrait for () {
30//! fn foo() {}<|> 30//! fn foo() {}$0
31//! } 31//! }
32//! ``` 32//! ```
33 33
@@ -82,7 +82,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
82 82
83fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { 83fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> {
84 let mut token = ctx.token.clone(); 84 let mut token = ctx.token.clone();
85 // For keywork without name like `impl .. { fn <|> }`, the current position is inside 85 // For keywork without name like `impl .. { fn $0 }`, the current position is inside
86 // the whitespace token, which is outside `FN` syntax node. 86 // the whitespace token, which is outside `FN` syntax node.
87 // We need to follow the previous token in this case. 87 // We need to follow the previous token in this case.
88 if token.kind() == SyntaxKind::WHITESPACE { 88 if token.kind() == SyntaxKind::WHITESPACE {
@@ -90,20 +90,20 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt
90 } 90 }
91 91
92 let impl_item_offset = match token.kind() { 92 let impl_item_offset = match token.kind() {
93 // `impl .. { const <|> }` 93 // `impl .. { const $0 }`
94 // ERROR 0 94 // ERROR 0
95 // CONST_KW <- * 95 // CONST_KW <- *
96 SyntaxKind::CONST_KW => 0, 96 T![const] => 0,
97 // `impl .. { fn/type <|> }` 97 // `impl .. { fn/type $0 }`
98 // FN/TYPE_ALIAS 0 98 // FN/TYPE_ALIAS 0
99 // FN_KW <- * 99 // FN_KW <- *
100 SyntaxKind::FN_KW | SyntaxKind::TYPE_KW => 0, 100 T![fn] | T![type] => 0,
101 // `impl .. { fn/type/const foo<|> }` 101 // `impl .. { fn/type/const foo$0 }`
102 // FN/TYPE_ALIAS/CONST 1 102 // FN/TYPE_ALIAS/CONST 1
103 // NAME 0 103 // NAME 0
104 // IDENT <- * 104 // IDENT <- *
105 SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1, 105 SyntaxKind::IDENT if token.parent().kind() == SyntaxKind::NAME => 1,
106 // `impl .. { foo<|> }` 106 // `impl .. { foo$0 }`
107 // MACRO_CALL 3 107 // MACRO_CALL 3
108 // PATH 2 108 // PATH 2
109 // PATH_SEGMENT 1 109 // PATH_SEGMENT 1
@@ -120,8 +120,8 @@ fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, Synt
120 // <item> 120 // <item>
121 let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?; 121 let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?;
122 let kind = match impl_item.kind() { 122 let kind = match impl_item.kind() {
123 // `impl ... { const <|> fn/type/const }` 123 // `impl ... { const $0 fn/type/const }`
124 _ if token.kind() == SyntaxKind::CONST_KW => ImplCompletionKind::Const, 124 _ if token.kind() == T![const] => ImplCompletionKind::Const,
125 SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const, 125 SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const,
126 SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias, 126 SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias,
127 SyntaxKind::FN => ImplCompletionKind::Fn, 127 SyntaxKind::FN => ImplCompletionKind::Fn,
@@ -267,7 +267,7 @@ trait Test {
267struct T; 267struct T;
268 268
269impl Test for T { 269impl Test for T {
270 t<|> 270 t$0
271} 271}
272"#, 272"#,
273 expect![[" 273 expect![["
@@ -287,7 +287,7 @@ struct T;
287 287
288impl Test for T { 288impl Test for T {
289 fn test() { 289 fn test() {
290 t<|> 290 t$0
291 } 291 }
292} 292}
293", 293",
@@ -301,7 +301,7 @@ struct T;
301 301
302impl Test for T { 302impl Test for T {
303 fn test() { 303 fn test() {
304 fn t<|> 304 fn t$0
305 } 305 }
306} 306}
307", 307",
@@ -315,7 +315,7 @@ struct T;
315 315
316impl Test for T { 316impl Test for T {
317 fn test() { 317 fn test() {
318 fn <|> 318 fn $0
319 } 319 }
320} 320}
321", 321",
@@ -330,7 +330,7 @@ struct T;
330 330
331impl Test for T { 331impl Test for T {
332 fn test() { 332 fn test() {
333 foo.<|> 333 foo.$0
334 } 334 }
335} 335}
336", 336",
@@ -343,7 +343,7 @@ trait Test { fn test(_: i32); fn test2(); }
343struct T; 343struct T;
344 344
345impl Test for T { 345impl Test for T {
346 fn test(t<|>) 346 fn test(t$0)
347} 347}
348", 348",
349 expect![[""]], 349 expect![[""]],
@@ -355,7 +355,7 @@ trait Test { fn test(_: fn()); fn test2(); }
355struct T; 355struct T;
356 356
357impl Test for T { 357impl Test for T {
358 fn test(f: fn <|>) 358 fn test(f: fn $0)
359} 359}
360", 360",
361 expect![[""]], 361 expect![[""]],
@@ -370,7 +370,7 @@ trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); }
370struct T; 370struct T;
371 371
372impl Test for T { 372impl Test for T {
373 const TEST: fn <|> 373 const TEST: fn $0
374} 374}
375", 375",
376 expect![[""]], 376 expect![[""]],
@@ -382,7 +382,7 @@ trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
382struct T; 382struct T;
383 383
384impl Test for T { 384impl Test for T {
385 const TEST: T<|> 385 const TEST: T$0
386} 386}
387", 387",
388 expect![[""]], 388 expect![[""]],
@@ -394,7 +394,7 @@ trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
394struct T; 394struct T;
395 395
396impl Test for T { 396impl Test for T {
397 const TEST: u32 = f<|> 397 const TEST: u32 = f$0
398} 398}
399", 399",
400 expect![[""]], 400 expect![[""]],
@@ -407,7 +407,7 @@ struct T;
407 407
408impl Test for T { 408impl Test for T {
409 const TEST: u32 = { 409 const TEST: u32 = {
410 t<|> 410 t$0
411 }; 411 };
412} 412}
413", 413",
@@ -421,7 +421,7 @@ struct T;
421 421
422impl Test for T { 422impl Test for T {
423 const TEST: u32 = { 423 const TEST: u32 = {
424 fn <|> 424 fn $0
425 }; 425 };
426} 426}
427", 427",
@@ -435,7 +435,7 @@ struct T;
435 435
436impl Test for T { 436impl Test for T {
437 const TEST: u32 = { 437 const TEST: u32 = {
438 fn t<|> 438 fn t$0
439 }; 439 };
440} 440}
441", 441",
@@ -451,7 +451,7 @@ trait Test { type Test; type Test2; fn test(); }
451struct T; 451struct T;
452 452
453impl Test for T { 453impl Test for T {
454 type Test = T<|>; 454 type Test = T$0;
455} 455}
456", 456",
457 expect![[""]], 457 expect![[""]],
@@ -463,7 +463,7 @@ trait Test { type Test; type Test2; fn test(); }
463struct T; 463struct T;
464 464
465impl Test for T { 465impl Test for T {
466 type Test = fn <|>; 466 type Test = fn $0;
467} 467}
468", 468",
469 expect![[""]], 469 expect![[""]],
@@ -481,7 +481,7 @@ trait Test {
481struct T; 481struct T;
482 482
483impl Test for T { 483impl Test for T {
484 t<|> 484 t$0
485} 485}
486"#, 486"#,
487 r#" 487 r#"
@@ -510,7 +510,7 @@ trait Test {
510struct T; 510struct T;
511 511
512impl Test for T { 512impl Test for T {
513 fn t<|> 513 fn t$0
514} 514}
515"#, 515"#,
516 r#" 516 r#"
@@ -540,7 +540,7 @@ struct T;
540 540
541impl Test for T { 541impl Test for T {
542 fn foo() {} 542 fn foo() {}
543 fn f<|> 543 fn f$0
544} 544}
545"#, 545"#,
546 expect![[r#" 546 expect![[r#"
@@ -560,7 +560,7 @@ trait Test {
560struct T; 560struct T;
561 561
562impl Test for T { 562impl Test for T {
563 fn f<|> 563 fn f$0
564} 564}
565"#, 565"#,
566 r#" 566 r#"
@@ -585,7 +585,7 @@ trait Test {
585struct T; 585struct T;
586 586
587impl Test for T { 587impl Test for T {
588 fn f<|> 588 fn f$0
589} 589}
590"#, 590"#,
591 r#" 591 r#"
@@ -614,7 +614,7 @@ trait Test {
614} 614}
615 615
616impl Test for () { 616impl Test for () {
617 type S<|> 617 type S$0
618} 618}
619"#, 619"#,
620 " 620 "
@@ -639,7 +639,7 @@ trait Test {
639} 639}
640 640
641impl Test for () { 641impl Test for () {
642 const S<|> 642 const S$0
643} 643}
644"#, 644"#,
645 " 645 "
@@ -661,7 +661,7 @@ trait Test {
661} 661}
662 662
663impl Test for () { 663impl Test for () {
664 const S<|> 664 const S$0
665} 665}
666"#, 666"#,
667 " 667 "
@@ -724,7 +724,7 @@ impl Test for T {{
724 // Enumerate some possible next siblings. 724 // Enumerate some possible next siblings.
725 for next_sibling in &[ 725 for next_sibling in &[
726 "", 726 "",
727 "fn other_fn() {}", // `const <|> fn` -> `const fn` 727 "fn other_fn() {}", // `const $0 fn` -> `const fn`
728 "type OtherType = i32;", 728 "type OtherType = i32;",
729 "const OTHER_CONST: i32 = 0;", 729 "const OTHER_CONST: i32 = 0;",
730 "async fn other_fn() {}", 730 "async fn other_fn() {}",
@@ -733,9 +733,9 @@ impl Test for T {{
733 "default type OtherType = i32;", 733 "default type OtherType = i32;",
734 "default const OTHER_CONST: i32 = 0;", 734 "default const OTHER_CONST: i32 = 0;",
735 ] { 735 ] {
736 test("bar", "fn <|>", "fn bar() {\n $0\n}", next_sibling); 736 test("bar", "fn $0", "fn bar() {\n $0\n}", next_sibling);
737 test("Foo", "type <|>", "type Foo = ", next_sibling); 737 test("Foo", "type $0", "type Foo = ", next_sibling);
738 test("CONST", "const <|>", "const CONST: u16 = ", next_sibling); 738 test("CONST", "const $0", "const CONST: u16 = ", next_sibling);
739 } 739 }
740 } 740 }
741} 741}
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 2da21b5c2..ac5596ca4 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -2,17 +2,11 @@
2 2
3use std::iter; 3use std::iter;
4 4
5use either::Either; 5use hir::{Adt, ModuleDef, ScopeDef, Type};
6use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type};
7use ide_db::helpers::insert_use::ImportScope;
8use ide_db::imports_locator;
9use syntax::AstNode; 6use syntax::AstNode;
10use test_utils::mark; 7use test_utils::mark;
11 8
12use crate::{ 9use crate::{CompletionContext, Completions};
13 render::{render_resolution_with_import, RenderContext},
14 CompletionContext, Completions, ImportEdit,
15};
16 10
17pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 11pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
18 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 12 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -45,10 +39,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
45 } 39 }
46 acc.add_resolution(ctx, name.to_string(), &res) 40 acc.add_resolution(ctx, name.to_string(), &res)
47 }); 41 });
48
49 if ctx.config.enable_autoimport_completions {
50 fuzzy_completion(acc, ctx);
51 }
52} 42}
53 43
54fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { 44fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
@@ -77,124 +67,13 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
77 } 67 }
78} 68}
79 69
80// Feature: Fuzzy Completion and Autoimports
81//
82// When completing names in the current scope, proposes additional imports from other modules or crates,
83// if they can be qualified in the scope and their name contains all symbols from the completion input
84// (case-insensitive, in any order or places).
85//
86// ```
87// fn main() {
88// pda<|>
89// }
90// # pub mod std { pub mod marker { pub struct PhantomData { } } }
91// ```
92// ->
93// ```
94// use std::marker::PhantomData;
95//
96// fn main() {
97// PhantomData
98// }
99// # pub mod std { pub mod marker { pub struct PhantomData { } } }
100// ```
101//
102// .Fuzzy search details
103//
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).
106// For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
107//
108// .Merge Behavior
109//
110// It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
111// Mimics the corresponding behavior of the `Auto Import` feature.
112//
113// .LSP and performance implications
114//
115// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
116// (case sensitive) resolve client capability in its client capabilities.
117// This way the server is able to defer the costly computations, doing them for a selected completion item only.
118// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
119// which might be slow ergo the feature is automatically disabled.
120//
121// .Feature toggle
122//
123// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
124// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
125// capability enabled.
126fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
127 let potential_import_name = ctx.token.to_string();
128 let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone());
129
130 if potential_import_name.len() < 2 {
131 return None;
132 }
133
134 let current_module = ctx.scope.module()?;
135 let anchor = ctx.name_ref_syntax.as_ref()?;
136 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
137
138 let user_input_lowercased = potential_import_name.to_lowercase();
139 let mut all_mod_paths = imports_locator::find_similar_imports(
140 &ctx.sema,
141 ctx.krate?,
142 Some(40),
143 potential_import_name,
144 true,
145 true,
146 )
147 .filter_map(|import_candidate| {
148 Some(match import_candidate {
149 Either::Left(module_def) => {
150 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
151 }
152 Either::Right(macro_def) => {
153 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
154 }
155 })
156 })
157 .filter(|(mod_path, _)| mod_path.len() > 1)
158 .collect::<Vec<_>>();
159
160 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
161 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
162 });
163
164 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
165 render_resolution_with_import(
166 RenderContext::new(ctx),
167 ImportEdit { import_path, import_scope: import_scope.clone() },
168 &definition,
169 )
170 }));
171 Some(())
172}
173
174fn compute_fuzzy_completion_order_key(
175 proposed_mod_path: &ModPath,
176 user_input_lowercased: &str,
177) -> usize {
178 mark::hit!(certain_fuzzy_order_test);
179 let proposed_import_name = match proposed_mod_path.segments.last() {
180 Some(name) => name.to_string().to_lowercase(),
181 None => return usize::MAX,
182 };
183 match proposed_import_name.match_indices(user_input_lowercased).next() {
184 Some((first_matching_index, _)) => first_matching_index,
185 None => usize::MAX,
186 }
187}
188
189#[cfg(test)] 70#[cfg(test)]
190mod tests { 71mod tests {
191 use expect_test::{expect, Expect}; 72 use expect_test::{expect, Expect};
192 use test_utils::mark; 73 use test_utils::mark;
193 74
194 use crate::{ 75 use crate::{
195 test_utils::{ 76 test_utils::{check_edit, completion_list_with_config, TEST_CONFIG},
196 check_edit, check_edit_with_config, completion_list_with_config, TEST_CONFIG,
197 },
198 CompletionConfig, CompletionKind, 77 CompletionConfig, CompletionKind,
199 }; 78 };
200 79
@@ -212,7 +91,7 @@ mod tests {
212 mark::check!(self_fulfilling_completion); 91 mark::check!(self_fulfilling_completion);
213 check( 92 check(
214 r#" 93 r#"
215use foo<|> 94use foo$0
216use std::collections; 95use std::collections;
217"#, 96"#,
218 expect![[r#" 97 expect![[r#"
@@ -229,7 +108,7 @@ enum Enum { A, B }
229fn quux(x: Option<Enum>) { 108fn quux(x: Option<Enum>) {
230 match x { 109 match x {
231 None => (), 110 None => (),
232 Some(en<|> @ Enum::A) => (), 111 Some(en$0 @ Enum::A) => (),
233 } 112 }
234} 113}
235"#, 114"#,
@@ -245,7 +124,7 @@ enum Enum { A, B }
245fn quux(x: Option<Enum>) { 124fn quux(x: Option<Enum>) {
246 match x { 125 match x {
247 None => (), 126 None => (),
248 Some(ref en<|>) => (), 127 Some(ref en$0) => (),
249 } 128 }
250} 129}
251"#, 130"#,
@@ -261,7 +140,7 @@ enum Enum { A, B }
261fn quux(x: Option<Enum>) { 140fn quux(x: Option<Enum>) {
262 match x { 141 match x {
263 None => (), 142 None => (),
264 Some(En<|>) => (), 143 Some(En$0) => (),
265 } 144 }
266} 145}
267"#, 146"#,
@@ -277,7 +156,7 @@ fn quux(x: Option<Enum>) {
277 r#" 156 r#"
278fn quux(x: i32) { 157fn quux(x: i32) {
279 let y = 92; 158 let y = 92;
280 1 + <|>; 159 1 + $0;
281 let z = (); 160 let z = ();
282} 161}
283"#, 162"#,
@@ -299,7 +178,7 @@ fn quux() {
299 }; 178 };
300 if let Some(a) = bar() { 179 if let Some(a) = bar() {
301 let b = 62; 180 let b = 62;
302 1 + <|> 181 1 + $0
303 } 182 }
304} 183}
305"#, 184"#,
@@ -316,7 +195,7 @@ fn quux() {
316 check( 195 check(
317 r#" 196 r#"
318fn quux() { 197fn quux() {
319 for x in &[1, 2, 3] { <|> } 198 for x in &[1, 2, 3] { $0 }
320} 199}
321"#, 200"#,
322 expect![[r#" 201 expect![[r#"
@@ -334,7 +213,7 @@ fn quux() {
334 r#" 213 r#"
335fn main() { 214fn main() {
336 let wherewolf = 92; 215 let wherewolf = 92;
337 drop(where<|>) 216 drop(where$0)
338} 217}
339"#, 218"#,
340 r#" 219 r#"
@@ -349,7 +228,7 @@ fn main() {
349 #[test] 228 #[test]
350 fn completes_generic_params() { 229 fn completes_generic_params() {
351 check( 230 check(
352 r#"fn quux<T>() { <|> }"#, 231 r#"fn quux<T>() { $0 }"#,
353 expect![[r#" 232 expect![[r#"
354 tp T 233 tp T
355 fn quux() fn quux<T>() 234 fn quux() fn quux<T>()
@@ -360,7 +239,7 @@ fn main() {
360 #[test] 239 #[test]
361 fn completes_generic_params_in_struct() { 240 fn completes_generic_params_in_struct() {
362 check( 241 check(
363 r#"struct S<T> { x: <|>}"#, 242 r#"struct S<T> { x: $0}"#,
364 expect![[r#" 243 expect![[r#"
365 tp Self 244 tp Self
366 tp T 245 tp T
@@ -372,7 +251,7 @@ fn main() {
372 #[test] 251 #[test]
373 fn completes_self_in_enum() { 252 fn completes_self_in_enum() {
374 check( 253 check(
375 r#"enum X { Y(<|>) }"#, 254 r#"enum X { Y($0) }"#,
376 expect![[r#" 255 expect![[r#"
377 tp Self 256 tp Self
378 en X 257 en X
@@ -386,7 +265,7 @@ fn main() {
386 r#" 265 r#"
387struct S; 266struct S;
388enum E {} 267enum E {}
389fn quux() { <|> } 268fn quux() { $0 }
390"#, 269"#,
391 expect![[r#" 270 expect![[r#"
392 st S 271 st S
@@ -403,7 +282,7 @@ fn quux() { <|> }
403 "_alpha", 282 "_alpha",
404 r#" 283 r#"
405fn main() { 284fn main() {
406 _<|> 285 _$0
407} 286}
408fn _alpha() {} 287fn _alpha() {}
409"#, 288"#,
@@ -421,7 +300,7 @@ fn _alpha() {}
421 check( 300 check(
422 r#" 301 r#"
423//- /lib.rs crate:main deps:other_crate 302//- /lib.rs crate:main deps:other_crate
424use <|>; 303use $0;
425 304
426//- /other_crate/lib.rs crate:other_crate 305//- /other_crate/lib.rs crate:other_crate
427// nothing here 306// nothing here
@@ -439,7 +318,7 @@ use <|>;
439struct Foo; 318struct Foo;
440mod m { 319mod m {
441 struct Bar; 320 struct Bar;
442 fn quux() { <|> } 321 fn quux() { $0 }
443} 322}
444"#, 323"#,
445 expect![[r#" 324 expect![[r#"
@@ -454,7 +333,7 @@ mod m {
454 check( 333 check(
455 r#" 334 r#"
456struct Foo; 335struct Foo;
457fn x() -> <|> 336fn x() -> $0
458"#, 337"#,
459 expect![[r#" 338 expect![[r#"
460 st Foo 339 st Foo
@@ -471,7 +350,7 @@ fn foo() {
471 let bar = 92; 350 let bar = 92;
472 { 351 {
473 let bar = 62; 352 let bar = 62;
474 drop(<|>) 353 drop($0)
475 } 354 }
476} 355}
477"#, 356"#,
@@ -487,7 +366,7 @@ fn foo() {
487 #[test] 366 #[test]
488 fn completes_self_in_methods() { 367 fn completes_self_in_methods() {
489 check( 368 check(
490 r#"impl S { fn foo(&self) { <|> } }"#, 369 r#"impl S { fn foo(&self) { $0 } }"#,
491 expect![[r#" 370 expect![[r#"
492 bn self &{unknown} 371 bn self &{unknown}
493 tp Self 372 tp Self
@@ -500,7 +379,7 @@ fn foo() {
500 check( 379 check(
501 r#" 380 r#"
502//- /main.rs crate:main deps:std 381//- /main.rs crate:main deps:std
503fn foo() { let x: <|> } 382fn foo() { let x: $0 }
504 383
505//- /std/lib.rs crate:std 384//- /std/lib.rs crate:std
506#[prelude_import] 385#[prelude_import]
@@ -517,11 +396,41 @@ mod prelude { struct Option; }
517 } 396 }
518 397
519 #[test] 398 #[test]
399 fn completes_prelude_macros() {
400 check(
401 r#"
402//- /main.rs crate:main deps:std
403fn f() {$0}
404
405//- /std/lib.rs crate:std
406#[prelude_import]
407pub use prelude::*;
408
409#[macro_use]
410mod prelude {
411 pub use crate::concat;
412}
413
414mod macros {
415 #[rustc_builtin_macro]
416 #[macro_export]
417 macro_rules! concat { }
418}
419"#,
420 expect![[r##"
421 fn f() fn f()
422 ma concat!(…) #[macro_export] macro_rules! concat
423 md std
424 "##]],
425 );
426 }
427
428 #[test]
520 fn completes_std_prelude_if_core_is_defined() { 429 fn completes_std_prelude_if_core_is_defined() {
521 check( 430 check(
522 r#" 431 r#"
523//- /main.rs crate:main deps:core,std 432//- /main.rs crate:main deps:core,std
524fn foo() { let x: <|> } 433fn foo() { let x: $0 }
525 434
526//- /core/lib.rs crate:core 435//- /core/lib.rs crate:core
527#[prelude_import] 436#[prelude_import]
@@ -562,12 +471,11 @@ mod m2 {
562 macro_rules! baz { () => {} } 471 macro_rules! baz { () => {} }
563} 472}
564 473
565fn main() { let v = <|> } 474fn main() { let v = $0 }
566"#, 475"#,
567 expect![[r##" 476 expect![[r##"
568 md m1 477 md m1
569 ma baz!(…) #[macro_export] 478 ma baz!(…) #[macro_export] macro_rules! baz
570 macro_rules! baz
571 fn main() fn main() 479 fn main() fn main()
572 md m2 480 md m2
573 ma bar!(…) macro_rules! bar 481 ma bar!(…) macro_rules! bar
@@ -581,7 +489,7 @@ fn main() { let v = <|> }
581 check( 489 check(
582 r#" 490 r#"
583macro_rules! foo { () => {} } 491macro_rules! foo { () => {} }
584fn foo() { <|> } 492fn foo() { $0 }
585"#, 493"#,
586 expect![[r#" 494 expect![[r#"
587 fn foo() fn foo() 495 fn foo() fn foo()
@@ -595,7 +503,7 @@ fn foo() { <|> }
595 check( 503 check(
596 r#" 504 r#"
597macro_rules! foo { () => {} } 505macro_rules! foo { () => {} }
598fn main() { let x: <|> } 506fn main() { let x: $0 }
599"#, 507"#,
600 expect![[r#" 508 expect![[r#"
601 fn main() fn main() 509 fn main() fn main()
@@ -609,7 +517,7 @@ fn main() { let x: <|> }
609 check( 517 check(
610 r#" 518 r#"
611macro_rules! foo { () => {} } 519macro_rules! foo { () => {} }
612fn main() { <|> } 520fn main() { $0 }
613"#, 521"#,
614 expect![[r#" 522 expect![[r#"
615 fn main() fn main() 523 fn main() fn main()
@@ -623,7 +531,7 @@ fn main() { <|> }
623 check( 531 check(
624 r#" 532 r#"
625fn main() { 533fn main() {
626 return f<|>; 534 return f$0;
627 fn frobnicate() {} 535 fn frobnicate() {}
628} 536}
629"#, 537"#,
@@ -641,7 +549,7 @@ fn main() {
641macro_rules! m { ($e:expr) => { $e } } 549macro_rules! m { ($e:expr) => { $e } }
642fn quux(x: i32) { 550fn quux(x: i32) {
643 let y = 92; 551 let y = 92;
644 m!(<|>); 552 m!($0);
645} 553}
646"#, 554"#,
647 expect![[r#" 555 expect![[r#"
@@ -660,7 +568,7 @@ fn quux(x: i32) {
660macro_rules! m { ($e:expr) => { $e } } 568macro_rules! m { ($e:expr) => { $e } }
661fn quux(x: i32) { 569fn quux(x: i32) {
662 let y = 92; 570 let y = 92;
663 m!(x<|>); 571 m!(x$0);
664} 572}
665", 573",
666 expect![[r#" 574 expect![[r#"
@@ -679,7 +587,7 @@ fn quux(x: i32) {
679macro_rules! m { ($e:expr) => { $e } } 587macro_rules! m { ($e:expr) => { $e } }
680fn quux(x: i32) { 588fn quux(x: i32) {
681 let y = 92; 589 let y = 92;
682 m!(x<|> 590 m!(x$0
683} 591}
684"#, 592"#,
685 expect![[r#" 593 expect![[r#"
@@ -697,7 +605,7 @@ fn quux(x: i32) {
697 r#" 605 r#"
698use spam::Quux; 606use spam::Quux;
699 607
700fn main() { <|> } 608fn main() { $0 }
701"#, 609"#,
702 expect![[r#" 610 expect![[r#"
703 fn main() fn main() 611 fn main() fn main()
@@ -714,7 +622,7 @@ enum Foo { Bar, Baz, Quux }
714 622
715fn main() { 623fn main() {
716 let foo = Foo::Quux; 624 let foo = Foo::Quux;
717 match foo { Qu<|> } 625 match foo { Qu$0 }
718} 626}
719"#, 627"#,
720 expect![[r#" 628 expect![[r#"
@@ -734,7 +642,7 @@ enum Foo { Bar, Baz, Quux }
734 642
735fn main() { 643fn main() {
736 let foo = Foo::Quux; 644 let foo = Foo::Quux;
737 match &foo { Qu<|> } 645 match &foo { Qu$0 }
738} 646}
739"#, 647"#,
740 expect![[r#" 648 expect![[r#"
@@ -754,7 +662,7 @@ enum Foo { Bar, Baz, Quux }
754 662
755fn main() { 663fn main() {
756 let foo = Foo::Quux; 664 let foo = Foo::Quux;
757 if let Qu<|> = foo { } 665 if let Qu$0 = foo { }
758} 666}
759"#, 667"#,
760 expect![[r#" 668 expect![[r#"
@@ -771,7 +679,7 @@ fn main() {
771 check( 679 check(
772 r#" 680 r#"
773enum Foo { Bar, Baz, Quux } 681enum Foo { Bar, Baz, Quux }
774fn main() { let foo: Foo = Q<|> } 682fn main() { let foo: Foo = Q$0 }
775"#, 683"#,
776 expect![[r#" 684 expect![[r#"
777 ev Foo::Bar () 685 ev Foo::Bar ()
@@ -788,7 +696,7 @@ fn main() { let foo: Foo = Q<|> }
788 check( 696 check(
789 r#" 697 r#"
790mod m { pub enum E { V } } 698mod m { pub enum E { V } }
791fn f() -> m::E { V<|> } 699fn f() -> m::E { V$0 }
792"#, 700"#,
793 expect![[r#" 701 expect![[r#"
794 ev m::E::V () 702 ev m::E::V ()
@@ -803,7 +711,7 @@ fn f() -> m::E { V<|> }
803 check( 711 check(
804 r#" 712 r#"
805struct Foo; 713struct Foo;
806#[<|>] 714#[$0]
807fn f() {} 715fn f() {}
808"#, 716"#,
809 expect![[""]], 717 expect![[""]],
@@ -817,7 +725,7 @@ fn f() {}
817trait MyTrait {} 725trait MyTrait {}
818struct MyStruct {} 726struct MyStruct {}
819 727
820impl My<|> 728impl My$0
821"#, 729"#,
822 expect![[r#" 730 expect![[r#"
823 tp Self 731 tp Self
@@ -826,128 +734,4 @@ impl My<|>
826 "#]], 734 "#]],
827 ) 735 )
828 } 736 }
829
830 #[test]
831 fn function_fuzzy_completion() {
832 check_edit_with_config(
833 TEST_CONFIG,
834 "stdin",
835 r#"
836//- /lib.rs crate:dep
837pub mod io {
838 pub fn stdin() {}
839};
840
841//- /main.rs crate:main deps:dep
842fn main() {
843 stdi<|>
844}
845"#,
846 r#"
847use dep::io::stdin;
848
849fn main() {
850 stdin()$0
851}
852"#,
853 );
854 }
855
856 #[test]
857 fn macro_fuzzy_completion() {
858 check_edit_with_config(
859 TEST_CONFIG,
860 "macro_with_curlies!",
861 r#"
862//- /lib.rs crate:dep
863/// Please call me as macro_with_curlies! {}
864#[macro_export]
865macro_rules! macro_with_curlies {
866 () => {}
867}
868
869//- /main.rs crate:main deps:dep
870fn main() {
871 curli<|>
872}
873"#,
874 r#"
875use dep::macro_with_curlies;
876
877fn main() {
878 macro_with_curlies! {$0}
879}
880"#,
881 );
882 }
883
884 #[test]
885 fn struct_fuzzy_completion() {
886 check_edit_with_config(
887 TEST_CONFIG,
888 "ThirdStruct",
889 r#"
890//- /lib.rs crate:dep
891pub struct FirstStruct;
892pub mod some_module {
893 pub struct SecondStruct;
894 pub struct ThirdStruct;
895}
896
897//- /main.rs crate:main deps:dep
898use dep::{FirstStruct, some_module::SecondStruct};
899
900fn main() {
901 this<|>
902}
903"#,
904 r#"
905use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
906
907fn main() {
908 ThirdStruct
909}
910"#,
911 );
912 }
913
914 #[test]
915 fn fuzzy_completions_come_in_specific_order() {
916 mark::check!(certain_fuzzy_order_test);
917 check_with_config(
918 TEST_CONFIG,
919 r#"
920//- /lib.rs crate:dep
921pub struct FirstStruct;
922pub mod some_module {
923 // already imported, omitted
924 pub struct SecondStruct;
925 // does not contain all letters from the query, omitted
926 pub struct UnrelatedOne;
927 // contains all letters from the query, but not in sequence, displayed last
928 pub struct ThiiiiiirdStruct;
929 // contains all letters from the query, but not in the beginning, displayed second
930 pub struct AfterThirdStruct;
931 // contains all letters from the query in the begginning, displayed first
932 pub struct ThirdStruct;
933}
934
935//- /main.rs crate:main deps:dep
936use dep::{FirstStruct, some_module::SecondStruct};
937
938fn main() {
939 hir<|>
940}
941"#,
942 expect![[r#"
943 fn main() fn main()
944 st SecondStruct
945 st FirstStruct
946 md dep
947 st dep::some_module::ThirdStruct
948 st dep::some_module::AfterThirdStruct
949 st dep::some_module::ThiiiiiirdStruct
950 "#]],
951 );
952 }
953} 737}
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs
index b4439b7d1..58fc700f3 100644
--- a/crates/completion/src/config.rs
+++ b/crates/completion/src/config.rs
@@ -4,7 +4,7 @@
4//! module, and we use to statically check that we only produce snippet 4//! module, and we use to statically check that we only produce snippet
5//! completions if we are allowed to. 5//! completions if we are allowed to.
6 6
7use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; 7use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct CompletionConfig { 10pub struct CompletionConfig {
@@ -13,5 +13,5 @@ pub struct CompletionConfig {
13 pub add_call_parenthesis: bool, 13 pub add_call_parenthesis: bool,
14 pub add_call_argument_snippets: bool, 14 pub add_call_argument_snippets: bool,
15 pub snippet_cap: Option<SnippetCap>, 15 pub snippet_cap: Option<SnippetCap>,
16 pub merge: Option<MergeBehavior>, 16 pub insert_use: InsertUseConfig,
17} 17}
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs
index f979697ab..b1e8eba85 100644
--- a/crates/completion/src/context.rs
+++ b/crates/completion/src/context.rs
@@ -4,10 +4,8 @@ use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
4use ide_db::base_db::{FilePosition, SourceDatabase}; 4use ide_db::base_db::{FilePosition, SourceDatabase};
5use ide_db::{call_info::ActiveParameter, RootDatabase}; 5use ide_db::{call_info::ActiveParameter, RootDatabase};
6use syntax::{ 6use syntax::{
7 algo::{find_covering_element, find_node_at_offset}, 7 algo::find_node_at_offset, ast, match_ast, AstNode, NodeOrToken, SyntaxKind::*, SyntaxNode,
8 ast, match_ast, AstNode, NodeOrToken, 8 SyntaxToken, TextRange, TextSize,
9 SyntaxKind::*,
10 SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 9};
12use test_utils::mark; 10use test_utils::mark;
13use text_edit::Indel; 11use text_edit::Indel;
@@ -63,7 +61,7 @@ pub(crate) struct CompletionContext<'a> {
63 pub(super) is_expr: bool, 61 pub(super) is_expr: bool,
64 /// Something is typed at the "top" level, in module or impl/trait. 62 /// Something is typed at the "top" level, in module or impl/trait.
65 pub(super) is_new_item: bool, 63 pub(super) is_new_item: bool,
66 /// The receiver if this is a field or method access, i.e. writing something.<|> 64 /// The receiver if this is a field or method access, i.e. writing something.$0
67 pub(super) dot_receiver: Option<ast::Expr>, 65 pub(super) dot_receiver: Option<ast::Expr>,
68 pub(super) dot_receiver_is_ambiguous_float_literal: bool, 66 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
69 /// If this is a call (method or function) in particular, i.e. the () are already there. 67 /// If this is a call (method or function) in particular, i.e. the () are already there.
@@ -92,6 +90,7 @@ pub(crate) struct CompletionContext<'a> {
92 pub(super) has_item_list_or_source_file_parent: bool, 90 pub(super) has_item_list_or_source_file_parent: bool,
93 pub(super) for_is_prev2: bool, 91 pub(super) for_is_prev2: bool,
94 pub(super) fn_is_prev: bool, 92 pub(super) fn_is_prev: bool,
93 pub(super) incomplete_let: bool,
95 pub(super) locals: Vec<(String, Local)>, 94 pub(super) locals: Vec<(String, Local)>,
96} 95}
97 96
@@ -132,9 +131,9 @@ impl<'a> CompletionContext<'a> {
132 scope, 131 scope,
133 db, 132 db,
134 config, 133 config,
134 position,
135 original_token, 135 original_token,
136 token, 136 token,
137 position,
138 krate, 137 krate,
139 expected_type: None, 138 expected_type: None,
140 name_ref_syntax: None, 139 name_ref_syntax: None,
@@ -155,30 +154,31 @@ impl<'a> CompletionContext<'a> {
155 is_expr: false, 154 is_expr: false,
156 is_new_item: false, 155 is_new_item: false,
157 dot_receiver: None, 156 dot_receiver: None,
157 dot_receiver_is_ambiguous_float_literal: false,
158 is_call: false, 158 is_call: false,
159 is_pattern_call: false, 159 is_pattern_call: false,
160 is_macro_call: false, 160 is_macro_call: false,
161 is_path_type: false, 161 is_path_type: false,
162 has_type_args: false, 162 has_type_args: false,
163 dot_receiver_is_ambiguous_float_literal: false,
164 attribute_under_caret: None, 163 attribute_under_caret: None,
165 mod_declaration_under_caret: None, 164 mod_declaration_under_caret: None,
166 unsafe_is_prev: false, 165 unsafe_is_prev: false,
167 in_loop_body: false, 166 if_is_prev: false,
168 ref_pat_parent: false,
169 bind_pat_parent: false,
170 block_expr_parent: false, 167 block_expr_parent: false,
168 bind_pat_parent: false,
169 ref_pat_parent: false,
170 in_loop_body: false,
171 has_trait_parent: false, 171 has_trait_parent: false,
172 has_impl_parent: false, 172 has_impl_parent: false,
173 inside_impl_trait_block: false, 173 inside_impl_trait_block: false,
174 has_field_list_parent: false, 174 has_field_list_parent: false,
175 trait_as_prev_sibling: false, 175 trait_as_prev_sibling: false,
176 impl_as_prev_sibling: false, 176 impl_as_prev_sibling: false,
177 if_is_prev: false,
178 is_match_arm: false, 177 is_match_arm: false,
179 has_item_list_or_source_file_parent: false, 178 has_item_list_or_source_file_parent: false,
180 for_is_prev2: false, 179 for_is_prev2: false,
181 fn_is_prev: false, 180 fn_is_prev: false,
181 incomplete_let: false,
182 locals, 182 locals,
183 }; 183 };
184 184
@@ -228,9 +228,9 @@ impl<'a> CompletionContext<'a> {
228 228
229 /// Checks whether completions in that particular case don't make much sense. 229 /// Checks whether completions in that particular case don't make much sense.
230 /// Examples: 230 /// Examples:
231 /// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful. 231 /// - `fn $0` -- we expect function name, it's unlikely that "hint" will be helpful.
232 /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. 232 /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names.
233 /// - `for _ i<|>` -- obviously, it'll be "in" keyword. 233 /// - `for _ i$0` -- obviously, it'll be "in" keyword.
234 pub(crate) fn no_completion_required(&self) -> bool { 234 pub(crate) fn no_completion_required(&self) -> bool {
235 (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2 235 (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2
236 } 236 }
@@ -270,6 +270,10 @@ impl<'a> CompletionContext<'a> {
270 .filter(|module| module.item_list().is_none()); 270 .filter(|module| module.item_list().is_none());
271 self.for_is_prev2 = for_is_prev2(syntax_element.clone()); 271 self.for_is_prev2 = for_is_prev2(syntax_element.clone());
272 self.fn_is_prev = fn_is_prev(syntax_element.clone()); 272 self.fn_is_prev = fn_is_prev(syntax_element.clone());
273 self.incomplete_let =
274 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
275 it.syntax().text_range().end() == syntax_element.text_range().end()
276 });
273 } 277 }
274 278
275 fn fill( 279 fn fill(
@@ -279,7 +283,7 @@ impl<'a> CompletionContext<'a> {
279 offset: TextSize, 283 offset: TextSize,
280 ) { 284 ) {
281 // FIXME: this is wrong in at least two cases: 285 // FIXME: this is wrong in at least two cases:
282 // * when there's no token `foo(<|>)` 286 // * when there's no token `foo($0)`
283 // * when there is a token, but it happens to have type of it's own 287 // * when there is a token, but it happens to have type of it's own
284 self.expected_type = self 288 self.expected_type = self
285 .token 289 .token
@@ -507,7 +511,7 @@ impl<'a> CompletionContext<'a> {
507} 511}
508 512
509fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { 513fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
510 find_covering_element(syntax, range).ancestors().find_map(N::cast) 514 syntax.covering_element(range).ancestors().find_map(N::cast)
511} 515}
512 516
513fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { 517fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 7087fae37..5d91d3a5c 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -7,6 +7,7 @@ use ide_db::helpers::{
7 insert_use::{self, ImportScope, MergeBehavior}, 7 insert_use::{self, ImportScope, MergeBehavior},
8 mod_path_to_ast, SnippetCap, 8 mod_path_to_ast, SnippetCap,
9}; 9};
10use stdx::assert_never;
10use syntax::{algo, TextRange}; 11use syntax::{algo, TextRange};
11use text_edit::TextEdit; 12use text_edit::TextEdit;
12 13
@@ -43,7 +44,7 @@ pub struct CompletionItem {
43 /// Lookup is used to check if completion item indeed can complete current 44 /// Lookup is used to check if completion item indeed can complete current
44 /// ident. 45 /// ident.
45 /// 46 ///
46 /// That is, in `foo.bar<|>` lookup of `abracadabra` will be accepted (it 47 /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
47 /// contains `bar` sub sequence), and `quux` will rejected. 48 /// contains `bar` sub sequence), and `quux` will rejected.
48 lookup: Option<String>, 49 lookup: Option<String>,
49 50
@@ -396,6 +397,11 @@ impl Builder {
396 } 397 }
397 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { 398 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
398 self.detail = detail.map(Into::into); 399 self.detail = detail.map(Into::into);
400 if let Some(detail) = &self.detail {
401 if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) {
402 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
403 }
404 }
399 self 405 self
400 } 406 }
401 #[allow(unused)] 407 #[allow(unused)]
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 3c7d5a46c..ee1b822e7 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -47,8 +47,8 @@ pub use crate::{
47// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` 47// - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result`
48// - `expr.ref` -> `&expr` 48// - `expr.ref` -> `&expr`
49// - `expr.refm` -> `&mut expr` 49// - `expr.refm` -> `&mut expr`
50// - `expr.let` -> `let <|> = expr;` 50// - `expr.let` -> `let $0 = expr;`
51// - `expr.letm` -> `let mut <|> = expr;` 51// - `expr.letm` -> `let mut $0 = expr;`
52// - `expr.not` -> `!expr` 52// - `expr.not` -> `!expr`
53// - `expr.dbg` -> `dbg!(expr)` 53// - `expr.dbg` -> `dbg!(expr)`
54// - `expr.dbgr` -> `dbg!(&expr)` 54// - `expr.dbgr` -> `dbg!(&expr)`
@@ -92,7 +92,7 @@ pub use crate::{
92/// ```no_run 92/// ```no_run
93/// fn f() { 93/// fn f() {
94/// let foo = 92; 94/// let foo = 92;
95/// let _ = bar<|> 95/// let _ = bar$0
96/// } 96/// }
97/// ``` 97/// ```
98/// 98///
@@ -127,6 +127,7 @@ pub fn completions(
127 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); 127 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
128 completions::trait_impl::complete_trait_impl(&mut acc, &ctx); 128 completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
129 completions::mod_::complete_mod(&mut acc, &ctx); 129 completions::mod_::complete_mod(&mut acc, &ctx);
130 completions::flyimport::import_on_the_fly(&mut acc, &ctx);
130 131
131 Some(acc) 132 Some(acc)
132} 133}
@@ -153,7 +154,9 @@ pub fn resolve_completion_edits(
153 }) 154 })
154 .find(|mod_path| mod_path.to_string() == full_import_path)?; 155 .find(|mod_path| mod_path.to_string() == full_import_path)?;
155 156
156 ImportEdit { import_path, import_scope }.to_text_edit(config.merge).map(|edit| vec![edit]) 157 ImportEdit { import_path, import_scope }
158 .to_text_edit(config.insert_use.merge)
159 .map(|edit| vec![edit])
157} 160}
158 161
159#[cfg(test)] 162#[cfg(test)]
@@ -220,7 +223,7 @@ mod tests {
220 223
221 fn foo() { 224 fn foo() {
222 let bar = Bar; 225 let bar = Bar;
223 bar.fo<|>; 226 bar.fo$0;
224 } 227 }
225 "#, 228 "#,
226 DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, 229 DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" },
@@ -246,7 +249,7 @@ mod tests {
246 249
247 fn foo() { 250 fn foo() {
248 let bar = Bar; 251 let bar = Bar;
249 bar.fo<|>; 252 bar.fo$0;
250 } 253 }
251 "#, 254 "#,
252 DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, 255 DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
@@ -259,7 +262,7 @@ mod tests {
259 check_no_completion( 262 check_no_completion(
260 r#" 263 r#"
261 fn foo() { 264 fn foo() {
262 for i i<|> 265 for i i$0
263 } 266 }
264 "#, 267 "#,
265 ); 268 );
@@ -270,7 +273,7 @@ mod tests {
270 fn foo() -> &'static str { "foo" } 273 fn foo() -> &'static str { "foo" }
271 274
272 fn bar() { 275 fn bar() {
273 for c in fo<|> 276 for c in fo$0
274 } 277 }
275 "#, 278 "#,
276 DetailAndDocumentation { 279 DetailAndDocumentation {
diff --git a/crates/completion/src/patterns.rs b/crates/completion/src/patterns.rs
index b0f35f9bf..f3ce91dd1 100644
--- a/crates/completion/src/patterns.rs
+++ b/crates/completion/src/patterns.rs
@@ -5,7 +5,7 @@ use syntax::{
5 ast::{self, LoopBodyOwner}, 5 ast::{self, LoopBodyOwner},
6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, 6 match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
7 SyntaxKind::*, 7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, 8 SyntaxNode, SyntaxToken, T,
9}; 9};
10 10
11#[cfg(test)] 11#[cfg(test)]
@@ -20,7 +20,7 @@ pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
20} 20}
21#[test] 21#[test]
22fn test_has_trait_parent() { 22fn test_has_trait_parent() {
23 check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent); 23 check_pattern_is_applicable(r"trait A { f$0 }", has_trait_parent);
24} 24}
25 25
26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { 26pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
@@ -32,7 +32,7 @@ pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
32} 32}
33#[test] 33#[test]
34fn test_has_impl_parent() { 34fn test_has_impl_parent() {
35 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent); 35 check_pattern_is_applicable(r"impl A { f$0 }", has_impl_parent);
36} 36}
37 37
38pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { 38pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool {
@@ -47,10 +47,10 @@ pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool {
47} 47}
48#[test] 48#[test]
49fn test_inside_impl_trait_block() { 49fn test_inside_impl_trait_block() {
50 check_pattern_is_applicable(r"impl Foo for Bar { f<|> }", inside_impl_trait_block); 50 check_pattern_is_applicable(r"impl Foo for Bar { f$0 }", inside_impl_trait_block);
51 check_pattern_is_applicable(r"impl Foo for Bar { fn f<|> }", inside_impl_trait_block); 51 check_pattern_is_applicable(r"impl Foo for Bar { fn f$0 }", inside_impl_trait_block);
52 check_pattern_is_not_applicable(r"impl A { f<|> }", inside_impl_trait_block); 52 check_pattern_is_not_applicable(r"impl A { f$0 }", inside_impl_trait_block);
53 check_pattern_is_not_applicable(r"impl A { fn f<|> }", inside_impl_trait_block); 53 check_pattern_is_not_applicable(r"impl A { fn f$0 }", inside_impl_trait_block);
54} 54}
55 55
56pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { 56pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
@@ -58,8 +58,8 @@ pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
58} 58}
59#[test] 59#[test]
60fn test_has_field_list_parent() { 60fn test_has_field_list_parent() {
61 check_pattern_is_applicable(r"struct Foo { f<|> }", has_field_list_parent); 61 check_pattern_is_applicable(r"struct Foo { f$0 }", has_field_list_parent);
62 check_pattern_is_applicable(r"struct Foo { f<|> pub f: i32}", has_field_list_parent); 62 check_pattern_is_applicable(r"struct Foo { f$0 pub f: i32}", has_field_list_parent);
63} 63}
64 64
65pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { 65pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
@@ -67,7 +67,7 @@ pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
67} 67}
68#[test] 68#[test]
69fn test_has_block_expr_parent() { 69fn test_has_block_expr_parent() {
70 check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent); 70 check_pattern_is_applicable(r"fn my_fn() { let a = 2; f$0 }", has_block_expr_parent);
71} 71}
72 72
73pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { 73pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
@@ -75,8 +75,8 @@ pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
75} 75}
76#[test] 76#[test]
77fn test_has_bind_pat_parent() { 77fn test_has_bind_pat_parent() {
78 check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent); 78 check_pattern_is_applicable(r"fn my_fn(m$0) {}", has_bind_pat_parent);
79 check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent); 79 check_pattern_is_applicable(r"fn my_fn() { let m$0 }", has_bind_pat_parent);
80} 80}
81 81
82pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool { 82pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
@@ -86,8 +86,8 @@ pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
86} 86}
87#[test] 87#[test]
88fn test_has_ref_parent() { 88fn test_has_ref_parent() {
89 check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent); 89 check_pattern_is_applicable(r"fn my_fn(&m$0) {}", has_ref_parent);
90 check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent); 90 check_pattern_is_applicable(r"fn my() { let &m$0 }", has_ref_parent);
91} 91}
92 92
93pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { 93pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
@@ -99,8 +99,8 @@ pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> boo
99} 99}
100#[test] 100#[test]
101fn test_has_item_list_or_source_file_parent() { 101fn test_has_item_list_or_source_file_parent() {
102 check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent); 102 check_pattern_is_applicable(r"i$0", has_item_list_or_source_file_parent);
103 check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent); 103 check_pattern_is_applicable(r"mod foo { f$0 }", has_item_list_or_source_file_parent);
104} 104}
105 105
106pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { 106pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
@@ -112,26 +112,26 @@ pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
112} 112}
113#[test] 113#[test]
114fn test_is_match_arm() { 114fn test_is_match_arm() {
115 check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm); 115 check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm);
116} 116}
117 117
118pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { 118pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
119 element 119 element
120 .into_token() 120 .into_token()
121 .and_then(|it| previous_non_trivia_token(it)) 121 .and_then(|it| previous_non_trivia_token(it))
122 .filter(|it| it.kind() == UNSAFE_KW) 122 .filter(|it| it.kind() == T![unsafe])
123 .is_some() 123 .is_some()
124} 124}
125#[test] 125#[test]
126fn test_unsafe_is_prev() { 126fn test_unsafe_is_prev() {
127 check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev); 127 check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev);
128} 128}
129 129
130pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { 130pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
131 element 131 element
132 .into_token() 132 .into_token()
133 .and_then(|it| previous_non_trivia_token(it)) 133 .and_then(|it| previous_non_trivia_token(it))
134 .filter(|it| it.kind() == IF_KW) 134 .filter(|it| it.kind() == T![if])
135 .is_some() 135 .is_some()
136} 136}
137 137
@@ -139,32 +139,32 @@ pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool {
139 element 139 element
140 .into_token() 140 .into_token()
141 .and_then(|it| previous_non_trivia_token(it)) 141 .and_then(|it| previous_non_trivia_token(it))
142 .filter(|it| it.kind() == FN_KW) 142 .filter(|it| it.kind() == T![fn])
143 .is_some() 143 .is_some()
144} 144}
145#[test] 145#[test]
146fn test_fn_is_prev() { 146fn test_fn_is_prev() {
147 check_pattern_is_applicable(r"fn l<|>", fn_is_prev); 147 check_pattern_is_applicable(r"fn l$0", fn_is_prev);
148} 148}
149 149
150/// Check if the token previous to the previous one is `for`. 150/// Check if the token previous to the previous one is `for`.
151/// For example, `for _ i<|>` => true. 151/// For example, `for _ i$0` => true.
152pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { 152pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool {
153 element 153 element
154 .into_token() 154 .into_token()
155 .and_then(|it| previous_non_trivia_token(it)) 155 .and_then(|it| previous_non_trivia_token(it))
156 .and_then(|it| previous_non_trivia_token(it)) 156 .and_then(|it| previous_non_trivia_token(it))
157 .filter(|it| it.kind() == FOR_KW) 157 .filter(|it| it.kind() == T![for])
158 .is_some() 158 .is_some()
159} 159}
160#[test] 160#[test]
161fn test_for_is_prev2() { 161fn test_for_is_prev2() {
162 check_pattern_is_applicable(r"for i i<|>", for_is_prev2); 162 check_pattern_is_applicable(r"for i i$0", for_is_prev2);
163} 163}
164 164
165#[test] 165#[test]
166fn test_if_is_prev() { 166fn test_if_is_prev() {
167 check_pattern_is_applicable(r"if l<|>", if_is_prev); 167 check_pattern_is_applicable(r"if l$0", if_is_prev);
168} 168}
169 169
170pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { 170pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
@@ -172,7 +172,7 @@ pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
172} 172}
173#[test] 173#[test]
174fn test_has_trait_as_prev_sibling() { 174fn test_has_trait_as_prev_sibling() {
175 check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling); 175 check_pattern_is_applicable(r"trait A w$0 {}", has_trait_as_prev_sibling);
176} 176}
177 177
178pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { 178pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
@@ -180,7 +180,7 @@ pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
180} 180}
181#[test] 181#[test]
182fn test_has_impl_as_prev_sibling() { 182fn test_has_impl_as_prev_sibling() {
183 check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling); 183 check_pattern_is_applicable(r"impl A w$0 {}", has_impl_as_prev_sibling);
184} 184}
185 185
186pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { 186pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 7554c1565..820dd01d1 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -51,11 +51,16 @@ pub(crate) fn render_resolution_with_import<'a>(
51 import_edit: ImportEdit, 51 import_edit: ImportEdit,
52 resolution: &ScopeDef, 52 resolution: &ScopeDef,
53) -> Option<CompletionItem> { 53) -> Option<CompletionItem> {
54 Render::new(ctx).render_resolution( 54 Render::new(ctx)
55 import_edit.import_path.segments.last()?.to_string(), 55 .render_resolution(
56 Some(import_edit), 56 import_edit.import_path.segments.last()?.to_string(),
57 resolution, 57 Some(import_edit),
58 ) 58 resolution,
59 )
60 .map(|mut item| {
61 item.completion_kind = CompletionKind::Magic;
62 item
63 })
59} 64}
60 65
61/// Interface for data and methods required for items rendering. 66/// Interface for data and methods required for items rendering.
@@ -358,7 +363,7 @@ mod tests {
358 r#" 363 r#"
359enum Foo { Foo { x: i32, y: i32 } } 364enum Foo { Foo { x: i32, y: i32 } }
360 365
361fn main() { Foo::Fo<|> } 366fn main() { Foo::Fo$0 }
362"#, 367"#,
363 expect![[r#" 368 expect![[r#"
364 [ 369 [
@@ -381,7 +386,7 @@ fn main() { Foo::Fo<|> }
381 r#" 386 r#"
382enum Foo { Foo (i32, i32) } 387enum Foo { Foo (i32, i32) }
383 388
384fn main() { Foo::Fo<|> } 389fn main() { Foo::Fo$0 }
385"#, 390"#,
386 expect![[r#" 391 expect![[r#"
387 [ 392 [
@@ -406,7 +411,7 @@ fn main() { Foo::Fo<|> }
406 r#" 411 r#"
407enum Foo { Foo } 412enum Foo { Foo }
408 413
409fn main() { Foo::Fo<|> } 414fn main() { Foo::Fo$0 }
410"#, 415"#,
411 expect![[r#" 416 expect![[r#"
412 [ 417 [
@@ -430,7 +435,7 @@ fn main() { Foo::Fo<|> }
430mod m { 435mod m {
431 pub enum Spam { Foo, Bar(i32) } 436 pub enum Spam { Foo, Bar(i32) }
432} 437}
433fn main() { let _: m::Spam = S<|> } 438fn main() { let _: m::Spam = S$0 }
434"#, 439"#,
435 expect![[r#" 440 expect![[r#"
436 [ 441 [
@@ -483,7 +488,7 @@ fn something_deprecated() {}
483#[deprecated(since = "1.0.0")] 488#[deprecated(since = "1.0.0")]
484fn something_else_deprecated() {} 489fn something_else_deprecated() {}
485 490
486fn main() { som<|> } 491fn main() { som$0 }
487"#, 492"#,
488 expect![[r#" 493 expect![[r#"
489 [ 494 [
@@ -523,7 +528,7 @@ fn main() { som<|> }
523 check( 528 check(
524 r#" 529 r#"
525struct A { #[deprecated] the_field: u32 } 530struct A { #[deprecated] the_field: u32 }
526fn foo() { A { the<|> } } 531fn foo() { A { the$0 } }
527"#, 532"#,
528 expect![[r#" 533 expect![[r#"
529 [ 534 [
@@ -551,7 +556,7 @@ struct S {
551} 556}
552impl S { 557impl S {
553 /// Method docs 558 /// Method docs
554 fn bar(self) { self.<|> } 559 fn bar(self) { self.$0 }
555}"#, 560}"#,
556 expect![[r#" 561 expect![[r#"
557 [ 562 [
@@ -584,7 +589,7 @@ impl S {
584 589
585 check( 590 check(
586 r#" 591 r#"
587use self::my<|>; 592use self::my$0;
588 593
589/// mod docs 594/// mod docs
590mod my { } 595mod my { }
@@ -643,7 +648,7 @@ impl S {
643 #[inline] 648 #[inline]
644 fn the_method(&self) { } 649 fn the_method(&self) { }
645} 650}
646fn foo(s: S) { s.<|> } 651fn foo(s: S) { s.$0 }
647"#, 652"#,
648 expect![[r#" 653 expect![[r#"
649 [ 654 [
@@ -671,7 +676,7 @@ fn foo(foo: u8, bar: u8) {}
671struct ManualVtable { f: fn(u8, u8) } 676struct ManualVtable { f: fn(u8, u8) }
672 677
673fn main() -> ManualVtable { 678fn main() -> ManualVtable {
674 ManualVtable { f: f<|> } 679 ManualVtable { f: f$0 }
675} 680}
676"#, 681"#,
677 r#" 682 r#"
@@ -692,7 +697,7 @@ fn main() -> ManualVtable {
692 "foo", 697 "foo",
693 r#" 698 r#"
694mod m { pub fn foo() {} } 699mod m { pub fn foo() {} }
695use crate::m::f<|>; 700use crate::m::f$0;
696"#, 701"#,
697 r#" 702 r#"
698mod m { pub fn foo() {} } 703mod m { pub fn foo() {} }
@@ -707,7 +712,7 @@ use crate::m::foo;
707 "foo", 712 "foo",
708 r#" 713 r#"
709fn foo(x: i32) {} 714fn foo(x: i32) {}
710fn main() { f<|>(); } 715fn main() { f$0(); }
711"#, 716"#,
712 r#" 717 r#"
713fn foo(x: i32) {} 718fn foo(x: i32) {}
@@ -719,7 +724,7 @@ fn main() { foo(); }
719 r#" 724 r#"
720struct Foo; 725struct Foo;
721impl Foo { fn foo(&self){} } 726impl Foo { fn foo(&self){} }
722fn f(foo: &Foo) { foo.f<|>(); } 727fn f(foo: &Foo) { foo.f$0(); }
723"#, 728"#,
724 r#" 729 r#"
725struct Foo; 730struct Foo;
@@ -736,7 +741,7 @@ fn f(foo: &Foo) { foo.foo(); }
736 "Vec", 741 "Vec",
737 r#" 742 r#"
738struct Vec<T> {} 743struct Vec<T> {}
739fn foo(xs: Ve<|>) 744fn foo(xs: Ve$0)
740"#, 745"#,
741 r#" 746 r#"
742struct Vec<T> {} 747struct Vec<T> {}
@@ -747,7 +752,7 @@ fn foo(xs: Vec<$0>)
747 "Vec", 752 "Vec",
748 r#" 753 r#"
749type Vec<T> = (T,); 754type Vec<T> = (T,);
750fn foo(xs: Ve<|>) 755fn foo(xs: Ve$0)
751"#, 756"#,
752 r#" 757 r#"
753type Vec<T> = (T,); 758type Vec<T> = (T,);
@@ -758,7 +763,7 @@ fn foo(xs: Vec<$0>)
758 "Vec", 763 "Vec",
759 r#" 764 r#"
760struct Vec<T = i128> {} 765struct Vec<T = i128> {}
761fn foo(xs: Ve<|>) 766fn foo(xs: Ve$0)
762"#, 767"#,
763 r#" 768 r#"
764struct Vec<T = i128> {} 769struct Vec<T = i128> {}
@@ -769,7 +774,7 @@ fn foo(xs: Vec)
769 "Vec", 774 "Vec",
770 r#" 775 r#"
771struct Vec<T> {} 776struct Vec<T> {}
772fn foo(xs: Ve<|><i128>) 777fn foo(xs: Ve$0<i128>)
773"#, 778"#,
774 r#" 779 r#"
775struct Vec<T> {} 780struct Vec<T> {}
@@ -785,7 +790,7 @@ fn foo(xs: Vec<i128>)
785 r#" 790 r#"
786struct S { foo: i64, bar: u32, baz: u32 } 791struct S { foo: i64, bar: u32, baz: u32 }
787fn test(bar: u32) { } 792fn test(bar: u32) { }
788fn foo(s: S) { test(s.<|>) } 793fn foo(s: S) { test(s.$0) }
789"#, 794"#,
790 expect![[r#" 795 expect![[r#"
791 fd bar [type+name] 796 fd bar [type+name]
@@ -802,7 +807,7 @@ fn foo(s: S) { test(s.<|>) }
802 r#" 807 r#"
803struct A { foo: i64, bar: u32, baz: u32 } 808struct A { foo: i64, bar: u32, baz: u32 }
804struct B { x: (), y: f32, bar: u32 } 809struct B { x: (), y: f32, bar: u32 }
805fn foo(a: A) { B { bar: a.<|> }; } 810fn foo(a: A) { B { bar: a.$0 }; }
806"#, 811"#,
807 expect![[r#" 812 expect![[r#"
808 fd bar [type+name] 813 fd bar [type+name]
@@ -819,7 +824,7 @@ fn foo(a: A) { B { bar: a.<|> }; }
819struct A { foo: i64, bar: u32, baz: u32 } 824struct A { foo: i64, bar: u32, baz: u32 }
820struct B { x: (), y: f32, bar: u32 } 825struct B { x: (), y: f32, bar: u32 }
821fn f(foo: i64) { } 826fn f(foo: i64) { }
822fn foo(a: A) { B { bar: f(a.<|>) }; } 827fn foo(a: A) { B { bar: f(a.$0) }; }
823"#, 828"#,
824 expect![[r#" 829 expect![[r#"
825 fd foo [type+name] 830 fd foo [type+name]
@@ -832,7 +837,7 @@ fn foo(a: A) { B { bar: f(a.<|>) }; }
832struct A { foo: i64, bar: u32, baz: u32 } 837struct A { foo: i64, bar: u32, baz: u32 }
833struct B { x: (), y: f32, bar: u32 } 838struct B { x: (), y: f32, bar: u32 }
834fn f(foo: i64) { } 839fn f(foo: i64) { }
835fn foo(a: A) { f(B { bar: a.<|> }); } 840fn foo(a: A) { f(B { bar: a.$0 }); }
836"#, 841"#,
837 expect![[r#" 842 expect![[r#"
838 fd bar [type+name] 843 fd bar [type+name]
@@ -847,7 +852,7 @@ fn foo(a: A) { f(B { bar: a.<|> }); }
847 check_scores( 852 check_scores(
848 r#" 853 r#"
849struct WorldSnapshot { _f: () }; 854struct WorldSnapshot { _f: () };
850fn go(world: &WorldSnapshot) { go(w<|>) } 855fn go(world: &WorldSnapshot) { go(w$0) }
851"#, 856"#,
852 expect![[r#" 857 expect![[r#"
853 bn world [type+name] 858 bn world [type+name]
@@ -862,7 +867,7 @@ fn go(world: &WorldSnapshot) { go(w<|>) }
862 check_scores( 867 check_scores(
863 r#" 868 r#"
864struct Foo; 869struct Foo;
865fn f(foo: &Foo) { f(foo, w<|>) } 870fn f(foo: &Foo) { f(foo, w$0) }
866"#, 871"#,
867 expect![[r#" 872 expect![[r#"
868 st Foo [] 873 st Foo []
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index 732e139ec..89fb49773 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -115,7 +115,7 @@ mod tests {
115enum Option<T> { Some(T), None } 115enum Option<T> { Some(T), None }
116use Option::*; 116use Option::*;
117fn main() -> Option<i32> { 117fn main() -> Option<i32> {
118 Som<|> 118 Som$0
119} 119}
120"#, 120"#,
121 r#" 121 r#"
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 7b2f62b4b..f5b0ce3e3 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -124,7 +124,7 @@ mod tests {
124 "no_args", 124 "no_args",
125 r#" 125 r#"
126fn no_args() {} 126fn no_args() {}
127fn main() { no_<|> } 127fn main() { no_$0 }
128"#, 128"#,
129 r#" 129 r#"
130fn no_args() {} 130fn no_args() {}
@@ -136,7 +136,7 @@ fn main() { no_args()$0 }
136 "with_args", 136 "with_args",
137 r#" 137 r#"
138fn with_args(x: i32, y: String) {} 138fn with_args(x: i32, y: String) {}
139fn main() { with_<|> } 139fn main() { with_$0 }
140"#, 140"#,
141 r#" 141 r#"
142fn with_args(x: i32, y: String) {} 142fn with_args(x: i32, y: String) {}
@@ -151,7 +151,7 @@ struct S;
151impl S { 151impl S {
152 fn foo(&self) {} 152 fn foo(&self) {}
153} 153}
154fn bar(s: &S) { s.f<|> } 154fn bar(s: &S) { s.f$0 }
155"#, 155"#,
156 r#" 156 r#"
157struct S; 157struct S;
@@ -170,7 +170,7 @@ impl S {
170 fn foo(&self, x: i32) {} 170 fn foo(&self, x: i32) {}
171} 171}
172fn bar(s: &S) { 172fn bar(s: &S) {
173 s.f<|> 173 s.f$0
174} 174}
175"#, 175"#,
176 r#" 176 r#"
@@ -195,7 +195,7 @@ struct S;
195impl S { 195impl S {
196 fn foo(&self) {} 196 fn foo(&self) {}
197} 197}
198fn main() { S::f<|> } 198fn main() { S::f$0 }
199"#, 199"#,
200 r#" 200 r#"
201struct S; 201struct S;
@@ -215,7 +215,7 @@ fn main() { S::foo(${1:&self})$0 }
215 "with_args", 215 "with_args",
216 r#" 216 r#"
217fn with_args(x: i32, y: String) {} 217fn with_args(x: i32, y: String) {}
218fn main() { with_<|> } 218fn main() { with_$0 }
219"#, 219"#,
220 r#" 220 r#"
221fn with_args(x: i32, y: String) {} 221fn with_args(x: i32, y: String) {}
@@ -230,7 +230,7 @@ fn main() { with_args($0) }
230 "foo", 230 "foo",
231 r#" 231 r#"
232fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} 232fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
233fn main() { f<|> } 233fn main() { f$0 }
234"#, 234"#,
235 r#" 235 r#"
236fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} 236fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
@@ -248,7 +248,7 @@ struct Foo {}
248fn ref_arg(x: &Foo) {} 248fn ref_arg(x: &Foo) {}
249fn main() { 249fn main() {
250 let x = Foo {}; 250 let x = Foo {};
251 ref_ar<|> 251 ref_ar$0
252} 252}
253"#, 253"#,
254 r#" 254 r#"
@@ -271,7 +271,7 @@ struct Foo {}
271fn ref_arg(x: &mut Foo) {} 271fn ref_arg(x: &mut Foo) {}
272fn main() { 272fn main() {
273 let x = Foo {}; 273 let x = Foo {};
274 ref_ar<|> 274 ref_ar$0
275} 275}
276"#, 276"#,
277 r#" 277 r#"
@@ -299,7 +299,7 @@ impl Bar {
299fn main() { 299fn main() {
300 let x = Foo {}; 300 let x = Foo {};
301 let y = Bar {}; 301 let y = Bar {};
302 y.<|> 302 y.$0
303} 303}
304"#, 304"#,
305 r#" 305 r#"
@@ -326,7 +326,7 @@ fn main() {
326fn take_mutably(mut x: &i32) {} 326fn take_mutably(mut x: &i32) {}
327 327
328fn main() { 328fn main() {
329 take_m<|> 329 take_m$0
330} 330}
331"#, 331"#,
332 r#" 332 r#"
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index 6f4f9945c..f893e420a 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -135,7 +135,7 @@ mod tests {
135 "frobnicate!", 135 "frobnicate!",
136 r#" 136 r#"
137//- /main.rs crate:main deps:foo 137//- /main.rs crate:main deps:foo
138use foo::<|>; 138use foo::$0;
139//- /foo/lib.rs crate:foo 139//- /foo/lib.rs crate:foo
140#[macro_export] 140#[macro_export]
141macro_rules! frobnicate { () => () } 141macro_rules! frobnicate { () => () }
@@ -149,7 +149,7 @@ use foo::frobnicate;
149 "frobnicate!", 149 "frobnicate!",
150 r#" 150 r#"
151macro_rules! frobnicate { () => () } 151macro_rules! frobnicate { () => () }
152fn main() { frob<|>!(); } 152fn main() { frob$0!(); }
153"#, 153"#,
154 r#" 154 r#"
155macro_rules! frobnicate { () => () } 155macro_rules! frobnicate { () => () }
@@ -173,7 +173,7 @@ fn main() { frobnicate!(); }
173/// ``` 173/// ```
174macro_rules! vec { () => {} } 174macro_rules! vec { () => {} }
175 175
176fn fn main() { v<|> } 176fn fn main() { v$0 }
177"#, 177"#,
178 r#" 178 r#"
179/// Creates a [`Vec`] containing the arguments. 179/// Creates a [`Vec`] containing the arguments.
@@ -198,7 +198,7 @@ fn fn main() { vec![$0] }
198/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, 198/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`,
199/// call as `let _=foo! { hello world };` 199/// call as `let _=foo! { hello world };`
200macro_rules! foo { () => {} } 200macro_rules! foo { () => {} }
201fn main() { <|> } 201fn main() { $0 }
202"#, 202"#,
203 r#" 203 r#"
204/// Foo 204/// Foo
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index b5e296777..6ea6da989 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -1,9 +1,12 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use hir::Semantics; 3use hir::{PrefixKind, Semantics};
4use ide_db::{ 4use ide_db::{
5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, 5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
6 helpers::{insert_use::MergeBehavior, SnippetCap}, 6 helpers::{
7 insert_use::{InsertUseConfig, MergeBehavior},
8 SnippetCap,
9 },
7 RootDatabase, 10 RootDatabase,
8}; 11};
9use itertools::Itertools; 12use itertools::Itertools;
@@ -19,15 +22,18 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
19 add_call_parenthesis: true, 22 add_call_parenthesis: true,
20 add_call_argument_snippets: true, 23 add_call_argument_snippets: true,
21 snippet_cap: SnippetCap::new(true), 24 snippet_cap: SnippetCap::new(true),
22 merge: Some(MergeBehavior::Full), 25 insert_use: InsertUseConfig {
26 merge: Some(MergeBehavior::Full),
27 prefix_kind: PrefixKind::Plain,
28 },
23}; 29};
24 30
25/// Creates analysis from a multi-file fixture, returns positions marked with <|>. 31/// Creates analysis from a multi-file fixture, returns positions marked with $0.
26pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { 32pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
27 let change_fixture = ChangeFixture::parse(ra_fixture); 33 let change_fixture = ChangeFixture::parse(ra_fixture);
28 let mut database = RootDatabase::default(); 34 let mut database = RootDatabase::default();
29 database.apply_change(change_fixture.change); 35 database.apply_change(change_fixture.change);
30 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)"); 36 let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
31 let offset = match range_or_offset { 37 let offset = match range_or_offset {
32 RangeOrOffset::Range(_) => panic!(), 38 RangeOrOffset::Range(_) => panic!(),
33 RangeOrOffset::Offset(it) => it, 39 RangeOrOffset::Offset(it) => it,
@@ -110,7 +116,7 @@ pub(crate) fn check_edit_with_config(
110 116
111 let mut combined_edit = completion.text_edit().to_owned(); 117 let mut combined_edit = completion.text_edit().to_owned();
112 if let Some(import_text_edit) = 118 if let Some(import_text_edit) =
113 completion.import_to_add().and_then(|edit| edit.to_text_edit(config.merge)) 119 completion.import_to_add().and_then(|edit| edit.to_text_edit(config.insert_use.merge))
114 { 120 {
115 combined_edit.union(import_text_edit).expect( 121 combined_edit.union(import_text_edit).expect(
116 "Failed to apply completion resolve changes: change ranges overlap, but should not", 122 "Failed to apply completion resolve changes: change ranges overlap, but should not",