diff options
Diffstat (limited to 'crates/completion')
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; | |||
13 | pub(crate) mod macro_in_item_position; | 13 | pub(crate) mod macro_in_item_position; |
14 | pub(crate) mod trait_impl; | 14 | pub(crate) mod trait_impl; |
15 | pub(crate) mod mod_; | 15 | pub(crate) mod mod_; |
16 | pub(crate) mod flyimport; | ||
16 | 17 | ||
17 | use hir::{ModPath, ScopeDef, Type}; | 18 | use 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 | ||
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use rustc_hash::FxHashSet; | 7 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode, SyntaxKind}; | 8 | use syntax::{ast, AstNode, T}; |
9 | 9 | ||
10 | use crate::{ | 10 | use 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( | |||
211 | fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { | 205 | fn 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)] |
417 | struct Test {} | 410 | struct 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)] |
438 | struct Test {} | 431 | struct 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)] |
449 | struct Test {} | 442 | struct 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 } | |||
79 | impl S { | 79 | impl S { |
80 | fn bar(&self) {} | 80 | fn bar(&self) {} |
81 | } | 81 | } |
82 | fn foo(s: S) { s.<|> } | 82 | fn 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#" |
95 | struct S { the_field: (u32,) } | 95 | struct S { the_field: (u32,) } |
96 | impl S { | 96 | impl 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#" |
111 | struct A { the_field: (u32, i32) } | 111 | struct A { the_field: (u32, i32) } |
112 | impl A { | 112 | impl 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#" |
128 | struct A { the_field: u32 } | 128 | struct A { the_field: u32 } |
129 | fn foo(a: A) { a.<|>() } | 129 | fn 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 | } |
147 | fn foo(a: inner::A) { a.<|> } | 147 | fn 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 | } |
165 | fn foo(a: A) { a.<|> } | 165 | fn 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#" |
177 | union U { field: u8, other: u16 } | 177 | union U { field: u8, other: u16 } |
178 | fn foo(u: U) { u.<|> } | 178 | fn 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> { | |||
195 | impl A<i32> { | 195 | impl A<i32> { |
196 | fn the_other_method(&self) {} | 196 | fn the_other_method(&self) {} |
197 | } | 197 | } |
198 | fn foo(a: A<u32>) { a.<|> } | 198 | fn 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.<|> } | |||
210 | struct A {} | 210 | struct A {} |
211 | trait Trait { fn the_method(&self); } | 211 | trait Trait { fn the_method(&self); } |
212 | impl Trait for A {} | 212 | impl Trait for A {} |
213 | fn foo(a: A) { a.<|> } | 213 | fn 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.<|> } | |||
225 | struct A {} | 225 | struct A {} |
226 | trait Trait { fn the_method(&self); } | 226 | trait Trait { fn the_method(&self); } |
227 | impl<T> Trait for T {} | 227 | impl<T> Trait for T {} |
228 | fn foo(a: &A) { a.<|> } | 228 | fn 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 | } |
244 | use m::Trait; | 244 | use m::Trait; |
245 | impl Trait for A {} | 245 | impl Trait for A {} |
246 | fn foo(a: A) { a.<|> } | 246 | fn 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 | } |
262 | fn foo(a: A) { | 262 | fn 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#" |
274 | fn foo() { | 274 | fn 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); | |||
295 | impl T { | 295 | impl 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#" |
312 | struct A { the_field: u32 } | 312 | struct A { the_field: u32 } |
313 | const X: u32 = { | 313 | const 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 = { | |||
327 | macro_rules! m { ($e:expr) => { $e } } | 327 | macro_rules! m { ($e:expr) => { $e } } |
328 | struct A { the_field: u32 } | 328 | struct A { the_field: u32 } |
329 | fn foo(a: A) { | 329 | fn 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) { | |||
344 | macro_rules! m { ($e:expr) => { $e } } | 344 | macro_rules! m { ($e:expr) => { $e } } |
345 | struct A { the_field: u32 } | 345 | struct A { the_field: u32 } |
346 | fn foo(a: A) { | 346 | fn 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) { | |||
360 | macro_rules! m { ($e:expr) => { $e } } | 360 | macro_rules! m { ($e:expr) => { $e } } |
361 | struct A { the_field: u32 } | 361 | struct A { the_field: u32 } |
362 | fn foo(a: A) { | 362 | fn 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#" |
376 | macro_rules! dbg { | 376 | macro_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 | } |
387 | struct A { the_field: u32 } | 387 | struct A { the_field: u32 } |
388 | fn foo(a: A) { | 388 | fn 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 | } |
406 | fn foo() { | 406 | fn 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() { | |||
421 | struct S; | 421 | struct S; |
422 | impl S { fn foo(&self) {} } | 422 | impl S { fn foo(&self) {} } |
423 | macro_rules! make_s { () => { S }; } | 423 | macro_rules! make_s { () => { S }; } |
424 | fn main() { make_s!().f<|>; } | 424 | fn 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 | |||
48 | use either::Either; | ||
49 | use hir::{ModPath, ScopeDef}; | ||
50 | use ide_db::{helpers::insert_use::ImportScope, imports_locator}; | ||
51 | use syntax::AstNode; | ||
52 | use test_utils::mark; | ||
53 | |||
54 | use crate::{ | ||
55 | context::CompletionContext, | ||
56 | render::{render_resolution_with_import, RenderContext}, | ||
57 | ImportEdit, | ||
58 | }; | ||
59 | |||
60 | use super::Completions; | ||
61 | |||
62 | pub(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 | |||
115 | fn 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)] | ||
131 | mod 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 | ||
151 | pub mod io { | ||
152 | pub fn stdin() {} | ||
153 | }; | ||
154 | |||
155 | //- /main.rs crate:main deps:dep | ||
156 | fn main() { | ||
157 | stdi$0 | ||
158 | } | ||
159 | "#, | ||
160 | r#" | ||
161 | use dep::io::stdin; | ||
162 | |||
163 | fn 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] | ||
178 | macro_rules! macro_with_curlies { | ||
179 | () => {} | ||
180 | } | ||
181 | |||
182 | //- /main.rs crate:main deps:dep | ||
183 | fn main() { | ||
184 | curli$0 | ||
185 | } | ||
186 | "#, | ||
187 | r#" | ||
188 | use dep::macro_with_curlies; | ||
189 | |||
190 | fn 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 | ||
203 | pub struct FirstStruct; | ||
204 | pub mod some_module { | ||
205 | pub struct SecondStruct; | ||
206 | pub struct ThirdStruct; | ||
207 | } | ||
208 | |||
209 | //- /main.rs crate:main deps:dep | ||
210 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
211 | |||
212 | fn main() { | ||
213 | this$0 | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
218 | |||
219 | fn 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 | ||
232 | pub struct FirstStruct; | ||
233 | pub 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 | ||
247 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
248 | |||
249 | fn 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 | ||
266 | pub 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 | ||
283 | use dep::test_mod::TestStruct; | ||
284 | fn 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#" |
82 | fn foo(file_id: FileId) {} | 82 | fn foo(file_id: FileId) {} |
83 | fn bar(file_id: FileId) {} | 83 | fn bar(file_id: FileId) {} |
84 | fn baz(file<|>) {} | 84 | fn 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#" |
96 | fn foo(file_id: FileId) {} | 96 | fn foo(file_id: FileId) {} |
97 | fn baz(file<|>, x: i32) {} | 97 | fn 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#" |
126 | fn outer(text: String) { | 126 | fn 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 | ||
3 | use syntax::{ast, SyntaxKind}; | 3 | use syntax::SyntaxKind; |
4 | use test_utils::mark; | 4 | use test_utils::mark; |
5 | 5 | ||
6 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 6 | use 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 | |||
149 | fn 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 | ||
160 | fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) { | 160 | fn 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 { | |
164 | fn 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)] |
179 | mod tests { | 181 | mod 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#" |
334 | fn quux() -> i32 { | 336 | fn 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#" |
473 | fn test() { | 475 | fn 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 | /* |
482 | Some multi-line comment<|> | 484 | Some 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<|> | |||
501 | use std::future::*; | 503 | use std::future::*; |
502 | struct A {} | 504 | struct A {} |
503 | impl Future for A {} | 505 | impl Future for A {} |
504 | fn foo(a: A) { a.<|> } | 506 | fn foo(a: A) { a.$0 } |
505 | 507 | ||
506 | //- /std/lib.rs crate:std | 508 | //- /std/lib.rs crate:std |
507 | pub mod future { | 509 | pub mod future { |
@@ -520,7 +522,7 @@ pub mod future { | |||
520 | use std::future::*; | 522 | use std::future::*; |
521 | fn foo() { | 523 | fn 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#" |
559 | struct Foo { | 561 | struct Foo { |
560 | <|> | 562 | $0 |
561 | pub f: i32, | 563 | pub f: i32, |
562 | } | 564 | } |
563 | "#, | 565 | "#, |
@@ -578,7 +580,7 @@ struct Foo { | |||
578 | } | 580 | } |
579 | fn foo() { | 581 | fn foo() { |
580 | Foo { | 582 | Foo { |
581 | <|> | 583 | $0 |
582 | } | 584 | } |
583 | } | 585 | } |
584 | "#, | 586 | "#, |
@@ -595,7 +597,7 @@ struct Foo { | |||
595 | } | 597 | } |
596 | fn foo() { | 598 | fn 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#" | ||
621 | fn main() { let x = $0 } | ||
622 | "#, | ||
623 | r#" | ||
624 | fn main() { let x = match $0 {}; } | ||
625 | "#, | ||
626 | ); | ||
627 | |||
628 | check_edit( | ||
629 | "if", | ||
630 | r#" | ||
631 | fn main() { | ||
632 | let x = $0 | ||
633 | let y = 92; | ||
634 | } | ||
635 | "#, | ||
636 | r#" | ||
637 | fn main() { | ||
638 | let x = if $0 {}; | ||
639 | let y = 92; | ||
640 | } | ||
641 | "#, | ||
642 | ); | ||
643 | |||
644 | check_edit( | ||
645 | "loop", | ||
646 | r#" | ||
647 | fn main() { | ||
648 | let x = $0 | ||
649 | bar(); | ||
650 | } | ||
651 | "#, | ||
652 | r#" | ||
653 | fn 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 { | |||
31 | macro_rules! foo { () => {} } | 31 | macro_rules! foo { () => {} } |
32 | fn foo() {} | 32 | fn 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 | ||
3 | use std::iter; | ||
4 | |||
3 | use hir::{Module, ModuleSource}; | 5 | use hir::{Module, ModuleSource}; |
4 | use ide_db::base_db::{SourceDatabaseExt, VfsPath}; | 6 | use ide_db::base_db::{SourceDatabaseExt, VfsPath}; |
5 | use ide_db::RootDatabase; | 7 | use ide_db::RootDatabase; |
@@ -9,12 +11,11 @@ use crate::{CompletionItem, CompletionItemKind}; | |||
9 | 11 | ||
10 | use crate::{context::CompletionContext, item::CompletionKind, Completions}; | 12 | use crate::{context::CompletionContext, item::CompletionKind, Completions}; |
11 | 13 | ||
12 | /// Complete mod declaration, i.e. `mod <|> ;` | 14 | /// Complete mod declaration, i.e. `mod $0 ;` |
13 | pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 15 | pub(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 | ||
126 | fn module_chain_to_containing_module_file( | 126 | fn 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; | |||
71 | struct Bar { f: u32 } | 71 | struct Bar { f: u32 } |
72 | 72 | ||
73 | fn foo() { | 73 | fn 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 } } | |||
92 | enum E { X } | 92 | enum E { X } |
93 | 93 | ||
94 | fn foo() { | 94 | fn 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; | |||
115 | struct Bar { f: u32 } | 115 | struct Bar { f: u32 } |
116 | 116 | ||
117 | fn foo() { | 117 | fn foo() { |
118 | let <|> | 118 | let $0 |
119 | } | 119 | } |
120 | "#, | 120 | "#, |
121 | expect![[r#" | 121 | expect![[r#" |
@@ -133,7 +133,7 @@ enum E { X } | |||
133 | static FOO: E = E::X; | 133 | static FOO: E = E::X; |
134 | struct Bar { f: u32 } | 134 | struct Bar { f: u32 } |
135 | 135 | ||
136 | fn foo(<|>) { | 136 | fn foo($0) { |
137 | } | 137 | } |
138 | "#, | 138 | "#, |
139 | expect![[r#" | 139 | expect![[r#" |
@@ -149,7 +149,7 @@ fn foo(<|>) { | |||
149 | struct Bar { f: u32 } | 149 | struct Bar { f: u32 } |
150 | 150 | ||
151 | fn foo() { | 151 | fn foo() { |
152 | let <|> | 152 | let $0 |
153 | } | 153 | } |
154 | "#, | 154 | "#, |
155 | expect![[r#" | 155 | expect![[r#" |
@@ -165,7 +165,7 @@ fn foo() { | |||
165 | struct Foo { bar: String, baz: String } | 165 | struct Foo { bar: String, baz: String } |
166 | struct Bar(String, String); | 166 | struct Bar(String, String); |
167 | struct Baz; | 167 | struct Baz; |
168 | fn outer(<|>) {} | 168 | fn 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 } | |||
182 | struct Bar(String, String); | 182 | struct Bar(String, String); |
183 | struct Baz; | 183 | struct Baz; |
184 | fn outer() { | 184 | fn outer() { |
185 | let <|> | 185 | let $0 |
186 | } | 186 | } |
187 | "#, | 187 | "#, |
188 | expect![[r#" | 188 | expect![[r#" |
@@ -201,7 +201,7 @@ struct Bar(String, String); | |||
201 | struct Baz; | 201 | struct Baz; |
202 | fn outer() { | 202 | fn outer() { |
203 | match () { | 203 | match () { |
204 | <|> | 204 | $0 |
205 | } | 205 | } |
206 | } | 206 | } |
207 | "#, | 207 | "#, |
@@ -225,7 +225,7 @@ use foo::*; | |||
225 | 225 | ||
226 | fn outer() { | 226 | fn outer() { |
227 | match () { | 227 | match () { |
228 | <|> | 228 | $0 |
229 | } | 229 | } |
230 | } | 230 | } |
231 | "#, | 231 | "#, |
@@ -244,7 +244,7 @@ fn outer() { | |||
244 | struct Foo(i32); | 244 | struct Foo(i32); |
245 | fn main() { | 245 | fn 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 | ||
3 | mod format_like; | 3 | mod 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#" |
311 | fn main() { | 314 | fn 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 | ||
343 | fn main() { | 346 | fn 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#" |
369 | fn main() { | 372 | fn 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#" |
394 | fn main() { | 397 | fn 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 | ||
425 | fn main() { | 428 | fn 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 | ||
450 | fn main() { | 453 | fn 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() { | |||
479 | macro_rules! m { ($e:expr) => { $e } } | 482 | macro_rules! m { ($e:expr) => { $e } } |
480 | fn main() { | 483 | fn 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#" | ||
505 | enum Option<T> { Some(T), None } | ||
506 | |||
507 | fn main() { | ||
508 | let bar = &Option::Some(true); | ||
509 | bar.$0 | ||
510 | } | ||
511 | "#, | ||
512 | r#" | ||
513 | enum Option<T> { Some(T), None } | ||
514 | |||
515 | fn 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 | ||
3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; | 3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; |
4 | use rustc_hash::FxHashSet; | 4 | use 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#" |
183 | mod foo { pub struct S; } | 183 | mod foo { pub struct S; } |
184 | use self::{foo::*, bar<|>}; | 184 | use 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#" |
233 | use self::my::<|>; | 233 | use self::my::$0; |
234 | 234 | ||
235 | mod my { pub struct Bar; } | 235 | mod my { pub struct Bar; } |
236 | fn my() {} | 236 | fn my() {} |
@@ -245,7 +245,7 @@ fn my() {} | |||
245 | fn filters_visibility() { | 245 | fn filters_visibility() { |
246 | check( | 246 | check( |
247 | r#" | 247 | r#" |
248 | use self::my::<|>; | 248 | use self::my::$0; |
249 | 249 | ||
250 | mod my { | 250 | mod 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#" |
267 | use self::m::<|>; | 267 | use self::m::$0; |
268 | 268 | ||
269 | mod m { pub struct Bar; } | 269 | mod m { pub struct Bar; } |
270 | "#, | 270 | "#, |
@@ -282,7 +282,7 @@ mod m { pub struct Bar; } | |||
282 | mod foo; | 282 | mod foo; |
283 | struct Spam; | 283 | struct Spam; |
284 | //- /foo.rs | 284 | //- /foo.rs |
285 | use crate::Sp<|> | 285 | use crate::Sp$0 |
286 | "#, | 286 | "#, |
287 | expect![[r#" | 287 | expect![[r#" |
288 | md foo | 288 | md foo |
@@ -299,7 +299,7 @@ use crate::Sp<|> | |||
299 | mod foo; | 299 | mod foo; |
300 | struct Spam; | 300 | struct Spam; |
301 | //- /foo.rs | 301 | //- /foo.rs |
302 | use crate::{Sp<|>}; | 302 | use 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 |
323 | use crate::{bar::{baz::Sp<|>}}; | 323 | use 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#" |
335 | enum E { Foo, Bar(i32) } | 335 | enum E { Foo, Bar(i32) } |
336 | fn foo() { let _ = E::<|> } | 336 | fn 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 | ||
359 | fn foo() { let _ = S::<|> } | 359 | fn 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 | ||
387 | fn foo() { let _ = S::<|> } | 387 | fn 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::<|> } | |||
401 | enum E {}; | 401 | enum E {}; |
402 | impl E { fn m() { } } | 402 | impl E { fn m() { } } |
403 | 403 | ||
404 | fn foo() { let _ = E::<|> } | 404 | fn 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::<|> } | |||
416 | union U {}; | 416 | union U {}; |
417 | impl U { fn m() { } } | 417 | impl U { fn m() { } } |
418 | 418 | ||
419 | fn foo() { let _ = U::<|> } | 419 | fn 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 |
432 | use foo::<|>; | 432 | use foo::$0; |
433 | 433 | ||
434 | //- /foo/lib.rs crate:foo | 434 | //- /foo/lib.rs crate:foo |
435 | pub mod bar { pub struct S; } | 435 | pub mod bar { pub struct S; } |
@@ -446,7 +446,7 @@ pub mod bar { pub struct S; } | |||
446 | r#" | 446 | r#" |
447 | trait Trait { fn m(); } | 447 | trait Trait { fn m(); } |
448 | 448 | ||
449 | fn foo() { let _ = Trait::<|> } | 449 | fn 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(); } | |||
463 | struct S; | 463 | struct S; |
464 | impl Trait for S {} | 464 | impl Trait for S {} |
465 | 465 | ||
466 | fn foo() { let _ = S::<|> } | 466 | fn 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(); } | |||
480 | struct S; | 480 | struct S; |
481 | impl Trait for S {} | 481 | impl Trait for S {} |
482 | 482 | ||
483 | fn foo() { let _ = <S as Trait>::<|> } | 483 | fn 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 | ||
509 | fn foo<T: Sub>() { T::<|> } | 509 | fn 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> {} | |||
544 | impl<T> Sub for Wrap<T> { | 544 | impl<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() {} } | |||
570 | type T = S; | 570 | type T = S; |
571 | impl T { fn bar() {} } | 571 | impl T { fn bar() {} } |
572 | 572 | ||
573 | fn main() { T::<|>; } | 573 | fn 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] |
587 | macro_rules! foo { () => {} } | 587 | macro_rules! foo { () => {} } |
588 | 588 | ||
589 | fn main() { let _ = crate::<|> } | 589 | fn 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#" |
622 | fn foo() { self::m::<|> } | 621 | fn foo() { self::m::$0 } |
623 | 622 | ||
624 | mod m { | 623 | mod 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#" |
645 | fn foo() { self::m::<|> } | 644 | fn foo() { self::m::$0 } |
646 | 645 | ||
647 | mod m { | 646 | mod 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#" |
679 | macro_rules! m { ($e:expr) => { $e } } | 678 | macro_rules! m { ($e:expr) => { $e } } |
680 | fn main() { m!(self::f<|>); } | 679 | fn main() { m!(self::f$0); } |
681 | fn foo() {} | 680 | fn 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#" |
694 | fn foo() { self::m::<|> } | 693 | fn foo() { self::m::$0 } |
695 | 694 | ||
696 | mod m { | 695 | mod 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 | } |
718 | fn foo() { | 717 | fn 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#" |
732 | mod foo { pub struct Foo; } | 731 | mod foo { pub struct Foo; } |
733 | #[foo::<|>] | 732 | #[foo::$0] |
734 | fn f() {} | 733 | fn f() {} |
735 | "#, | 734 | "#, |
736 | expect![[""]], | 735 | expect![[""]], |
@@ -749,7 +748,7 @@ fn foo( | |||
749 | } | 748 | } |
750 | 749 | ||
751 | fn main() { | 750 | fn main() { |
752 | fo<|> | 751 | fo$0 |
753 | } | 752 | } |
754 | "#, | 753 | "#, |
755 | expect![[r#" | 754 | expect![[r#" |
@@ -770,7 +769,7 @@ enum Foo { | |||
770 | 769 | ||
771 | impl Foo { | 770 | impl 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 { | |||
99 | fn process(f: S) { | 99 | fn 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 { | |||
139 | fn process(f: S) { | 139 | fn 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 } | |||
173 | fn process(f: S) { | 173 | fn 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 | ||
202 | fn process(f: S) { | 202 | fn 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 | ||
220 | fn process(e: E) { | 220 | fn 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 | ||
240 | fn process(f: S) { | 240 | fn 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#" |
280 | struct A { the_field: u32 } | 280 | struct A { the_field: u32 } |
281 | fn foo() { | 281 | fn 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#" |
295 | enum E { A { a: u32 } } | 295 | enum E { A { a: u32 } } |
296 | fn foo() { | 296 | fn 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 } | |||
311 | struct B { b: u32 } | 311 | struct B { b: u32 } |
312 | 312 | ||
313 | fn foo() { | 313 | fn 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() { | |||
327 | struct A<T> { a: T } | 327 | struct A<T> { a: T } |
328 | 328 | ||
329 | fn foo() { | 329 | fn 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() { | |||
343 | macro_rules! m { ($e:expr) => { $e } } | 343 | macro_rules! m { ($e:expr) => { $e } } |
344 | struct A { the_field: u32 } | 344 | struct A { the_field: u32 } |
345 | fn foo() { | 345 | fn 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 | ||
364 | fn main() { | 364 | fn 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 | ||
382 | fn main() { | 382 | fn 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)] |
105 | mod tests { | 105 | mod 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 | ||
83 | fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { | 83 | fn 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 { | |||
267 | struct T; | 267 | struct T; |
268 | 268 | ||
269 | impl Test for T { | 269 | impl Test for T { |
270 | t<|> | 270 | t$0 |
271 | } | 271 | } |
272 | "#, | 272 | "#, |
273 | expect![[" | 273 | expect![[" |
@@ -287,7 +287,7 @@ struct T; | |||
287 | 287 | ||
288 | impl Test for T { | 288 | impl 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 | ||
302 | impl Test for T { | 302 | impl 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 | ||
316 | impl Test for T { | 316 | impl 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 | ||
331 | impl Test for T { | 331 | impl 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(); } | |||
343 | struct T; | 343 | struct T; |
344 | 344 | ||
345 | impl Test for T { | 345 | impl 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(); } | |||
355 | struct T; | 355 | struct T; |
356 | 356 | ||
357 | impl Test for T { | 357 | impl 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(); } | |||
370 | struct T; | 370 | struct T; |
371 | 371 | ||
372 | impl Test for T { | 372 | impl 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(); } | |||
382 | struct T; | 382 | struct T; |
383 | 383 | ||
384 | impl Test for T { | 384 | impl 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(); } | |||
394 | struct T; | 394 | struct T; |
395 | 395 | ||
396 | impl Test for T { | 396 | impl 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 | ||
408 | impl Test for T { | 408 | impl 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 | ||
422 | impl Test for T { | 422 | impl 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 | ||
436 | impl Test for T { | 436 | impl 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(); } | |||
451 | struct T; | 451 | struct T; |
452 | 452 | ||
453 | impl Test for T { | 453 | impl 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(); } | |||
463 | struct T; | 463 | struct T; |
464 | 464 | ||
465 | impl Test for T { | 465 | impl 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 { | |||
481 | struct T; | 481 | struct T; |
482 | 482 | ||
483 | impl Test for T { | 483 | impl Test for T { |
484 | t<|> | 484 | t$0 |
485 | } | 485 | } |
486 | "#, | 486 | "#, |
487 | r#" | 487 | r#" |
@@ -510,7 +510,7 @@ trait Test { | |||
510 | struct T; | 510 | struct T; |
511 | 511 | ||
512 | impl Test for T { | 512 | impl 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 | ||
541 | impl Test for T { | 541 | impl 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 { | |||
560 | struct T; | 560 | struct T; |
561 | 561 | ||
562 | impl Test for T { | 562 | impl Test for T { |
563 | fn f<|> | 563 | fn f$0 |
564 | } | 564 | } |
565 | "#, | 565 | "#, |
566 | r#" | 566 | r#" |
@@ -585,7 +585,7 @@ trait Test { | |||
585 | struct T; | 585 | struct T; |
586 | 586 | ||
587 | impl Test for T { | 587 | impl 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 | ||
616 | impl Test for () { | 616 | impl 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 | ||
641 | impl Test for () { | 641 | impl 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 | ||
663 | impl Test for () { | 663 | impl 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 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use either::Either; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
6 | use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type}; | ||
7 | use ide_db::helpers::insert_use::ImportScope; | ||
8 | use ide_db::imports_locator; | ||
9 | use syntax::AstNode; | 6 | use syntax::AstNode; |
10 | use test_utils::mark; | 7 | use test_utils::mark; |
11 | 8 | ||
12 | use crate::{ | 9 | use crate::{CompletionContext, Completions}; |
13 | render::{render_resolution_with_import, RenderContext}, | ||
14 | CompletionContext, Completions, ImportEdit, | ||
15 | }; | ||
16 | 10 | ||
17 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 11 | pub(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 | ||
54 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 44 | fn 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. | ||
126 | fn 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 | |||
174 | fn 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)] |
190 | mod tests { | 71 | mod 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#" |
215 | use foo<|> | 94 | use foo$0 |
216 | use std::collections; | 95 | use std::collections; |
217 | "#, | 96 | "#, |
218 | expect![[r#" | 97 | expect![[r#" |
@@ -229,7 +108,7 @@ enum Enum { A, B } | |||
229 | fn quux(x: Option<Enum>) { | 108 | fn 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 } | |||
245 | fn quux(x: Option<Enum>) { | 124 | fn 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 } | |||
261 | fn quux(x: Option<Enum>) { | 140 | fn 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#" |
278 | fn quux(x: i32) { | 157 | fn 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#" |
318 | fn quux() { | 197 | fn 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#" |
335 | fn main() { | 214 | fn 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#" |
387 | struct S; | 266 | struct S; |
388 | enum E {} | 267 | enum E {} |
389 | fn quux() { <|> } | 268 | fn 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#" |
405 | fn main() { | 284 | fn main() { |
406 | _<|> | 285 | _$0 |
407 | } | 286 | } |
408 | fn _alpha() {} | 287 | fn _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 |
424 | use <|>; | 303 | use $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 <|>; | |||
439 | struct Foo; | 318 | struct Foo; |
440 | mod m { | 319 | mod 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#" |
456 | struct Foo; | 335 | struct Foo; |
457 | fn x() -> <|> | 336 | fn 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 |
503 | fn foo() { let x: <|> } | 382 | fn 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 | ||
403 | fn f() {$0} | ||
404 | |||
405 | //- /std/lib.rs crate:std | ||
406 | #[prelude_import] | ||
407 | pub use prelude::*; | ||
408 | |||
409 | #[macro_use] | ||
410 | mod prelude { | ||
411 | pub use crate::concat; | ||
412 | } | ||
413 | |||
414 | mod 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 |
524 | fn foo() { let x: <|> } | 433 | fn 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 | ||
565 | fn main() { let v = <|> } | 474 | fn 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#" |
583 | macro_rules! foo { () => {} } | 491 | macro_rules! foo { () => {} } |
584 | fn foo() { <|> } | 492 | fn 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#" |
597 | macro_rules! foo { () => {} } | 505 | macro_rules! foo { () => {} } |
598 | fn main() { let x: <|> } | 506 | fn 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#" |
611 | macro_rules! foo { () => {} } | 519 | macro_rules! foo { () => {} } |
612 | fn main() { <|> } | 520 | fn 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#" |
625 | fn main() { | 533 | fn main() { |
626 | return f<|>; | 534 | return f$0; |
627 | fn frobnicate() {} | 535 | fn frobnicate() {} |
628 | } | 536 | } |
629 | "#, | 537 | "#, |
@@ -641,7 +549,7 @@ fn main() { | |||
641 | macro_rules! m { ($e:expr) => { $e } } | 549 | macro_rules! m { ($e:expr) => { $e } } |
642 | fn quux(x: i32) { | 550 | fn 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) { | |||
660 | macro_rules! m { ($e:expr) => { $e } } | 568 | macro_rules! m { ($e:expr) => { $e } } |
661 | fn quux(x: i32) { | 569 | fn 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) { | |||
679 | macro_rules! m { ($e:expr) => { $e } } | 587 | macro_rules! m { ($e:expr) => { $e } } |
680 | fn quux(x: i32) { | 588 | fn 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#" |
698 | use spam::Quux; | 606 | use spam::Quux; |
699 | 607 | ||
700 | fn main() { <|> } | 608 | fn 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 | ||
715 | fn main() { | 623 | fn 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 | ||
735 | fn main() { | 643 | fn 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 | ||
755 | fn main() { | 663 | fn 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#" |
773 | enum Foo { Bar, Baz, Quux } | 681 | enum Foo { Bar, Baz, Quux } |
774 | fn main() { let foo: Foo = Q<|> } | 682 | fn 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#" |
790 | mod m { pub enum E { V } } | 698 | mod m { pub enum E { V } } |
791 | fn f() -> m::E { V<|> } | 699 | fn 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#" |
805 | struct Foo; | 713 | struct Foo; |
806 | #[<|>] | 714 | #[$0] |
807 | fn f() {} | 715 | fn f() {} |
808 | "#, | 716 | "#, |
809 | expect![[""]], | 717 | expect![[""]], |
@@ -817,7 +725,7 @@ fn f() {} | |||
817 | trait MyTrait {} | 725 | trait MyTrait {} |
818 | struct MyStruct {} | 726 | struct MyStruct {} |
819 | 727 | ||
820 | impl My<|> | 728 | impl 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 | ||
837 | pub mod io { | ||
838 | pub fn stdin() {} | ||
839 | }; | ||
840 | |||
841 | //- /main.rs crate:main deps:dep | ||
842 | fn main() { | ||
843 | stdi<|> | ||
844 | } | ||
845 | "#, | ||
846 | r#" | ||
847 | use dep::io::stdin; | ||
848 | |||
849 | fn 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] | ||
865 | macro_rules! macro_with_curlies { | ||
866 | () => {} | ||
867 | } | ||
868 | |||
869 | //- /main.rs crate:main deps:dep | ||
870 | fn main() { | ||
871 | curli<|> | ||
872 | } | ||
873 | "#, | ||
874 | r#" | ||
875 | use dep::macro_with_curlies; | ||
876 | |||
877 | fn 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 | ||
891 | pub struct FirstStruct; | ||
892 | pub mod some_module { | ||
893 | pub struct SecondStruct; | ||
894 | pub struct ThirdStruct; | ||
895 | } | ||
896 | |||
897 | //- /main.rs crate:main deps:dep | ||
898 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
899 | |||
900 | fn main() { | ||
901 | this<|> | ||
902 | } | ||
903 | "#, | ||
904 | r#" | ||
905 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
906 | |||
907 | fn 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 | ||
921 | pub struct FirstStruct; | ||
922 | pub 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 | ||
936 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
937 | |||
938 | fn 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 | ||
7 | use ide_db::helpers::{insert_use::MergeBehavior, SnippetCap}; | 7 | use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; |
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct CompletionConfig { | 10 | pub 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}; | |||
4 | use ide_db::base_db::{FilePosition, SourceDatabase}; | 4 | use ide_db::base_db::{FilePosition, SourceDatabase}; |
5 | use ide_db::{call_info::ActiveParameter, RootDatabase}; | 5 | use ide_db::{call_info::ActiveParameter, RootDatabase}; |
6 | use syntax::{ | 6 | use 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 | }; |
12 | use test_utils::mark; | 10 | use test_utils::mark; |
13 | use text_edit::Indel; | 11 | use 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 | ||
509 | fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> { | 513 | fn 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 | ||
513 | fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { | 517 | fn 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 | }; |
10 | use stdx::assert_never; | ||
10 | use syntax::{algo, TextRange}; | 11 | use syntax::{algo, TextRange}; |
11 | use text_edit::TextEdit; | 12 | use 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] |
22 | fn test_has_trait_parent() { | 22 | fn 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 | ||
26 | pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool { | 26 | pub(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] |
34 | fn test_has_impl_parent() { | 34 | fn 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 | ||
38 | pub(crate) fn inside_impl_trait_block(element: SyntaxElement) -> bool { | 38 | pub(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] |
49 | fn test_inside_impl_trait_block() { | 49 | fn 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 | ||
56 | pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { | 56 | pub(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] |
60 | fn test_has_field_list_parent() { | 60 | fn 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 | ||
65 | pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { | 65 | pub(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] |
69 | fn test_has_block_expr_parent() { | 69 | fn 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 | ||
73 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 73 | pub(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] |
77 | fn test_has_bind_pat_parent() { | 77 | fn 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 | ||
82 | pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool { | 82 | pub(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] |
88 | fn test_has_ref_parent() { | 88 | fn 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 | ||
93 | pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool { | 93 | pub(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] |
101 | fn test_has_item_list_or_source_file_parent() { | 101 | fn 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 | ||
106 | pub(crate) fn is_match_arm(element: SyntaxElement) -> bool { | 106 | pub(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] |
114 | fn test_is_match_arm() { | 114 | fn 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 | ||
118 | pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { | 118 | pub(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] |
126 | fn test_unsafe_is_prev() { | 126 | fn 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 | ||
130 | pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { | 130 | pub(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] |
146 | fn test_fn_is_prev() { | 146 | fn 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. |
152 | pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { | 152 | pub(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] |
161 | fn test_for_is_prev2() { | 161 | fn 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] |
166 | fn test_if_is_prev() { | 166 | fn 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 | ||
170 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | 170 | pub(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] |
174 | fn test_has_trait_as_prev_sibling() { | 174 | fn 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 | ||
178 | pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { | 178 | pub(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] |
182 | fn test_has_impl_as_prev_sibling() { | 182 | fn 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 | ||
186 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 186 | pub(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#" |
359 | enum Foo { Foo { x: i32, y: i32 } } | 364 | enum Foo { Foo { x: i32, y: i32 } } |
360 | 365 | ||
361 | fn main() { Foo::Fo<|> } | 366 | fn 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#" |
382 | enum Foo { Foo (i32, i32) } | 387 | enum Foo { Foo (i32, i32) } |
383 | 388 | ||
384 | fn main() { Foo::Fo<|> } | 389 | fn 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#" |
407 | enum Foo { Foo } | 412 | enum Foo { Foo } |
408 | 413 | ||
409 | fn main() { Foo::Fo<|> } | 414 | fn main() { Foo::Fo$0 } |
410 | "#, | 415 | "#, |
411 | expect![[r#" | 416 | expect![[r#" |
412 | [ | 417 | [ |
@@ -430,7 +435,7 @@ fn main() { Foo::Fo<|> } | |||
430 | mod m { | 435 | mod m { |
431 | pub enum Spam { Foo, Bar(i32) } | 436 | pub enum Spam { Foo, Bar(i32) } |
432 | } | 437 | } |
433 | fn main() { let _: m::Spam = S<|> } | 438 | fn 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")] |
484 | fn something_else_deprecated() {} | 489 | fn something_else_deprecated() {} |
485 | 490 | ||
486 | fn main() { som<|> } | 491 | fn 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#" |
525 | struct A { #[deprecated] the_field: u32 } | 530 | struct A { #[deprecated] the_field: u32 } |
526 | fn foo() { A { the<|> } } | 531 | fn foo() { A { the$0 } } |
527 | "#, | 532 | "#, |
528 | expect![[r#" | 533 | expect![[r#" |
529 | [ | 534 | [ |
@@ -551,7 +556,7 @@ struct S { | |||
551 | } | 556 | } |
552 | impl S { | 557 | impl 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#" |
587 | use self::my<|>; | 592 | use self::my$0; |
588 | 593 | ||
589 | /// mod docs | 594 | /// mod docs |
590 | mod my { } | 595 | mod my { } |
@@ -643,7 +648,7 @@ impl S { | |||
643 | #[inline] | 648 | #[inline] |
644 | fn the_method(&self) { } | 649 | fn the_method(&self) { } |
645 | } | 650 | } |
646 | fn foo(s: S) { s.<|> } | 651 | fn 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) {} | |||
671 | struct ManualVtable { f: fn(u8, u8) } | 676 | struct ManualVtable { f: fn(u8, u8) } |
672 | 677 | ||
673 | fn main() -> ManualVtable { | 678 | fn 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#" |
694 | mod m { pub fn foo() {} } | 699 | mod m { pub fn foo() {} } |
695 | use crate::m::f<|>; | 700 | use crate::m::f$0; |
696 | "#, | 701 | "#, |
697 | r#" | 702 | r#" |
698 | mod m { pub fn foo() {} } | 703 | mod m { pub fn foo() {} } |
@@ -707,7 +712,7 @@ use crate::m::foo; | |||
707 | "foo", | 712 | "foo", |
708 | r#" | 713 | r#" |
709 | fn foo(x: i32) {} | 714 | fn foo(x: i32) {} |
710 | fn main() { f<|>(); } | 715 | fn main() { f$0(); } |
711 | "#, | 716 | "#, |
712 | r#" | 717 | r#" |
713 | fn foo(x: i32) {} | 718 | fn foo(x: i32) {} |
@@ -719,7 +724,7 @@ fn main() { foo(); } | |||
719 | r#" | 724 | r#" |
720 | struct Foo; | 725 | struct Foo; |
721 | impl Foo { fn foo(&self){} } | 726 | impl Foo { fn foo(&self){} } |
722 | fn f(foo: &Foo) { foo.f<|>(); } | 727 | fn f(foo: &Foo) { foo.f$0(); } |
723 | "#, | 728 | "#, |
724 | r#" | 729 | r#" |
725 | struct Foo; | 730 | struct Foo; |
@@ -736,7 +741,7 @@ fn f(foo: &Foo) { foo.foo(); } | |||
736 | "Vec", | 741 | "Vec", |
737 | r#" | 742 | r#" |
738 | struct Vec<T> {} | 743 | struct Vec<T> {} |
739 | fn foo(xs: Ve<|>) | 744 | fn foo(xs: Ve$0) |
740 | "#, | 745 | "#, |
741 | r#" | 746 | r#" |
742 | struct Vec<T> {} | 747 | struct Vec<T> {} |
@@ -747,7 +752,7 @@ fn foo(xs: Vec<$0>) | |||
747 | "Vec", | 752 | "Vec", |
748 | r#" | 753 | r#" |
749 | type Vec<T> = (T,); | 754 | type Vec<T> = (T,); |
750 | fn foo(xs: Ve<|>) | 755 | fn foo(xs: Ve$0) |
751 | "#, | 756 | "#, |
752 | r#" | 757 | r#" |
753 | type Vec<T> = (T,); | 758 | type Vec<T> = (T,); |
@@ -758,7 +763,7 @@ fn foo(xs: Vec<$0>) | |||
758 | "Vec", | 763 | "Vec", |
759 | r#" | 764 | r#" |
760 | struct Vec<T = i128> {} | 765 | struct Vec<T = i128> {} |
761 | fn foo(xs: Ve<|>) | 766 | fn foo(xs: Ve$0) |
762 | "#, | 767 | "#, |
763 | r#" | 768 | r#" |
764 | struct Vec<T = i128> {} | 769 | struct Vec<T = i128> {} |
@@ -769,7 +774,7 @@ fn foo(xs: Vec) | |||
769 | "Vec", | 774 | "Vec", |
770 | r#" | 775 | r#" |
771 | struct Vec<T> {} | 776 | struct Vec<T> {} |
772 | fn foo(xs: Ve<|><i128>) | 777 | fn foo(xs: Ve$0<i128>) |
773 | "#, | 778 | "#, |
774 | r#" | 779 | r#" |
775 | struct Vec<T> {} | 780 | struct Vec<T> {} |
@@ -785,7 +790,7 @@ fn foo(xs: Vec<i128>) | |||
785 | r#" | 790 | r#" |
786 | struct S { foo: i64, bar: u32, baz: u32 } | 791 | struct S { foo: i64, bar: u32, baz: u32 } |
787 | fn test(bar: u32) { } | 792 | fn test(bar: u32) { } |
788 | fn foo(s: S) { test(s.<|>) } | 793 | fn 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#" |
803 | struct A { foo: i64, bar: u32, baz: u32 } | 808 | struct A { foo: i64, bar: u32, baz: u32 } |
804 | struct B { x: (), y: f32, bar: u32 } | 809 | struct B { x: (), y: f32, bar: u32 } |
805 | fn foo(a: A) { B { bar: a.<|> }; } | 810 | fn 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.<|> }; } | |||
819 | struct A { foo: i64, bar: u32, baz: u32 } | 824 | struct A { foo: i64, bar: u32, baz: u32 } |
820 | struct B { x: (), y: f32, bar: u32 } | 825 | struct B { x: (), y: f32, bar: u32 } |
821 | fn f(foo: i64) { } | 826 | fn f(foo: i64) { } |
822 | fn foo(a: A) { B { bar: f(a.<|>) }; } | 827 | fn 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.<|>) }; } | |||
832 | struct A { foo: i64, bar: u32, baz: u32 } | 837 | struct A { foo: i64, bar: u32, baz: u32 } |
833 | struct B { x: (), y: f32, bar: u32 } | 838 | struct B { x: (), y: f32, bar: u32 } |
834 | fn f(foo: i64) { } | 839 | fn f(foo: i64) { } |
835 | fn foo(a: A) { f(B { bar: a.<|> }); } | 840 | fn 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#" |
849 | struct WorldSnapshot { _f: () }; | 854 | struct WorldSnapshot { _f: () }; |
850 | fn go(world: &WorldSnapshot) { go(w<|>) } | 855 | fn 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#" |
864 | struct Foo; | 869 | struct Foo; |
865 | fn f(foo: &Foo) { f(foo, w<|>) } | 870 | fn 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 { | |||
115 | enum Option<T> { Some(T), None } | 115 | enum Option<T> { Some(T), None } |
116 | use Option::*; | 116 | use Option::*; |
117 | fn main() -> Option<i32> { | 117 | fn 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#" |
126 | fn no_args() {} | 126 | fn no_args() {} |
127 | fn main() { no_<|> } | 127 | fn main() { no_$0 } |
128 | "#, | 128 | "#, |
129 | r#" | 129 | r#" |
130 | fn no_args() {} | 130 | fn no_args() {} |
@@ -136,7 +136,7 @@ fn main() { no_args()$0 } | |||
136 | "with_args", | 136 | "with_args", |
137 | r#" | 137 | r#" |
138 | fn with_args(x: i32, y: String) {} | 138 | fn with_args(x: i32, y: String) {} |
139 | fn main() { with_<|> } | 139 | fn main() { with_$0 } |
140 | "#, | 140 | "#, |
141 | r#" | 141 | r#" |
142 | fn with_args(x: i32, y: String) {} | 142 | fn with_args(x: i32, y: String) {} |
@@ -151,7 +151,7 @@ struct S; | |||
151 | impl S { | 151 | impl S { |
152 | fn foo(&self) {} | 152 | fn foo(&self) {} |
153 | } | 153 | } |
154 | fn bar(s: &S) { s.f<|> } | 154 | fn bar(s: &S) { s.f$0 } |
155 | "#, | 155 | "#, |
156 | r#" | 156 | r#" |
157 | struct S; | 157 | struct S; |
@@ -170,7 +170,7 @@ impl S { | |||
170 | fn foo(&self, x: i32) {} | 170 | fn foo(&self, x: i32) {} |
171 | } | 171 | } |
172 | fn bar(s: &S) { | 172 | fn bar(s: &S) { |
173 | s.f<|> | 173 | s.f$0 |
174 | } | 174 | } |
175 | "#, | 175 | "#, |
176 | r#" | 176 | r#" |
@@ -195,7 +195,7 @@ struct S; | |||
195 | impl S { | 195 | impl S { |
196 | fn foo(&self) {} | 196 | fn foo(&self) {} |
197 | } | 197 | } |
198 | fn main() { S::f<|> } | 198 | fn main() { S::f$0 } |
199 | "#, | 199 | "#, |
200 | r#" | 200 | r#" |
201 | struct S; | 201 | struct S; |
@@ -215,7 +215,7 @@ fn main() { S::foo(${1:&self})$0 } | |||
215 | "with_args", | 215 | "with_args", |
216 | r#" | 216 | r#" |
217 | fn with_args(x: i32, y: String) {} | 217 | fn with_args(x: i32, y: String) {} |
218 | fn main() { with_<|> } | 218 | fn main() { with_$0 } |
219 | "#, | 219 | "#, |
220 | r#" | 220 | r#" |
221 | fn with_args(x: i32, y: String) {} | 221 | fn with_args(x: i32, y: String) {} |
@@ -230,7 +230,7 @@ fn main() { with_args($0) } | |||
230 | "foo", | 230 | "foo", |
231 | r#" | 231 | r#" |
232 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | 232 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} |
233 | fn main() { f<|> } | 233 | fn main() { f$0 } |
234 | "#, | 234 | "#, |
235 | r#" | 235 | r#" |
236 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} | 236 | fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} |
@@ -248,7 +248,7 @@ struct Foo {} | |||
248 | fn ref_arg(x: &Foo) {} | 248 | fn ref_arg(x: &Foo) {} |
249 | fn main() { | 249 | fn 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 {} | |||
271 | fn ref_arg(x: &mut Foo) {} | 271 | fn ref_arg(x: &mut Foo) {} |
272 | fn main() { | 272 | fn 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 { | |||
299 | fn main() { | 299 | fn 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() { | |||
326 | fn take_mutably(mut x: &i32) {} | 326 | fn take_mutably(mut x: &i32) {} |
327 | 327 | ||
328 | fn main() { | 328 | fn 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 |
138 | use foo::<|>; | 138 | use foo::$0; |
139 | //- /foo/lib.rs crate:foo | 139 | //- /foo/lib.rs crate:foo |
140 | #[macro_export] | 140 | #[macro_export] |
141 | macro_rules! frobnicate { () => () } | 141 | macro_rules! frobnicate { () => () } |
@@ -149,7 +149,7 @@ use foo::frobnicate; | |||
149 | "frobnicate!", | 149 | "frobnicate!", |
150 | r#" | 150 | r#" |
151 | macro_rules! frobnicate { () => () } | 151 | macro_rules! frobnicate { () => () } |
152 | fn main() { frob<|>!(); } | 152 | fn main() { frob$0!(); } |
153 | "#, | 153 | "#, |
154 | r#" | 154 | r#" |
155 | macro_rules! frobnicate { () => () } | 155 | macro_rules! frobnicate { () => () } |
@@ -173,7 +173,7 @@ fn main() { frobnicate!(); } | |||
173 | /// ``` | 173 | /// ``` |
174 | macro_rules! vec { () => {} } | 174 | macro_rules! vec { () => {} } |
175 | 175 | ||
176 | fn fn main() { v<|> } | 176 | fn 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 };` |
200 | macro_rules! foo { () => {} } | 200 | macro_rules! foo { () => {} } |
201 | fn main() { <|> } | 201 | fn 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 | ||
3 | use hir::Semantics; | 3 | use hir::{PrefixKind, Semantics}; |
4 | use ide_db::{ | 4 | use 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 | }; |
9 | use itertools::Itertools; | 12 | use 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. |
26 | pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { | 32 | pub(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", |