diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-04 18:04:20 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-04 18:04:20 +0100 |
commit | c815d5b49660e9b93c6a70039abef5fa02ae8013 (patch) | |
tree | 90b2c90cbd9a429f18f576c52b6e7c2e0d75e5a9 | |
parent | a826ac6b9cc27e92f98a8638c7599647e59b13fd (diff) | |
parent | 943fa4639569cc2c93d3ff8f7f5b1a30cc332cb0 (diff) |
Merge #5225
5225: Alight details in comkplation list r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_ide/src/completion.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_dot.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_keyword.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_pattern.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_postfix.rs | 24 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_qualified_path.rs | 1523 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_snippet.rs | 106 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 51 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/test_utils.rs | 17 |
9 files changed, 542 insertions, 1207 deletions
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index 9ebb8ebb7..f3a5e9573 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs | |||
@@ -2,6 +2,9 @@ mod completion_config; | |||
2 | mod completion_item; | 2 | mod completion_item; |
3 | mod completion_context; | 3 | mod completion_context; |
4 | mod presentation; | 4 | mod presentation; |
5 | mod patterns; | ||
6 | #[cfg(test)] | ||
7 | mod test_utils; | ||
5 | 8 | ||
6 | mod complete_attribute; | 9 | mod complete_attribute; |
7 | mod complete_dot; | 10 | mod complete_dot; |
@@ -15,9 +18,6 @@ mod complete_unqualified_path; | |||
15 | mod complete_postfix; | 18 | mod complete_postfix; |
16 | mod complete_macro_in_item_position; | 19 | mod complete_macro_in_item_position; |
17 | mod complete_trait_impl; | 20 | mod complete_trait_impl; |
18 | mod patterns; | ||
19 | #[cfg(test)] | ||
20 | mod test_utils; | ||
21 | 21 | ||
22 | use ra_ide_db::RootDatabase; | 22 | use ra_ide_db::RootDatabase; |
23 | 23 | ||
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 667a8b949..3c6c8c81a 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -83,7 +83,7 @@ fn foo(s: S) { s.<|> } | |||
83 | "#, | 83 | "#, |
84 | expect![[r#" | 84 | expect![[r#" |
85 | me bar() fn bar(&self) | 85 | me bar() fn bar(&self) |
86 | fd foo u32 | 86 | fd foo u32 |
87 | "#]], | 87 | "#]], |
88 | ); | 88 | ); |
89 | } | 89 | } |
@@ -98,7 +98,7 @@ impl S { | |||
98 | } | 98 | } |
99 | "#, | 99 | "#, |
100 | expect![[r#" | 100 | expect![[r#" |
101 | me foo() fn foo(self) | 101 | me foo() fn foo(self) |
102 | fd the_field (u32,) | 102 | fd the_field (u32,) |
103 | "#]], | 103 | "#]], |
104 | ) | 104 | ) |
@@ -114,7 +114,7 @@ impl A { | |||
114 | } | 114 | } |
115 | "#, | 115 | "#, |
116 | expect![[r#" | 116 | expect![[r#" |
117 | me foo() fn foo(&self) | 117 | me foo() fn foo(&self) |
118 | fd the_field (u32, i32) | 118 | fd the_field (u32, i32) |
119 | "#]], | 119 | "#]], |
120 | ) | 120 | ) |
@@ -148,7 +148,7 @@ fn foo(a: inner::A) { a.<|> } | |||
148 | "#, | 148 | "#, |
149 | expect![[r#" | 149 | expect![[r#" |
150 | fd crate_field u32 | 150 | fd crate_field u32 |
151 | fd pub_field u32 | 151 | fd pub_field u32 |
152 | fd super_field u32 | 152 | fd super_field u32 |
153 | "#]], | 153 | "#]], |
154 | ); | 154 | ); |
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 340d57a49..2dc401f57 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs | |||
@@ -216,17 +216,17 @@ mod tests { | |||
216 | check( | 216 | check( |
217 | r"use a::<|>", | 217 | r"use a::<|>", |
218 | expect![[r#" | 218 | expect![[r#" |
219 | kw self | 219 | kw self |
220 | kw super:: | 220 | kw super:: |
221 | "#]], | 221 | "#]], |
222 | ); | 222 | ); |
223 | 223 | ||
224 | check( | 224 | check( |
225 | r"use a::{b, <|>}", | 225 | r"use a::{b, <|>}", |
226 | expect![[r#" | 226 | expect![[r#" |
227 | kw self | 227 | kw self |
228 | kw super:: | 228 | kw super:: |
229 | "#]], | 229 | "#]], |
230 | ); | 230 | ); |
231 | } | 231 | } |
232 | 232 | ||
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs index 41c16df7b..13fa7548d 100644 --- a/crates/ra_ide/src/completion/complete_pattern.rs +++ b/crates/ra_ide/src/completion/complete_pattern.rs | |||
@@ -61,7 +61,7 @@ fn foo() { | |||
61 | expect![[r#" | 61 | expect![[r#" |
62 | st Bar | 62 | st Bar |
63 | en E | 63 | en E |
64 | ev X () | 64 | ev X () |
65 | ct Z | 65 | ct Z |
66 | md m | 66 | md m |
67 | "#]], | 67 | "#]], |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 14013dc2f..8735b9010 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -260,14 +260,14 @@ fn main() { | |||
260 | } | 260 | } |
261 | "#, | 261 | "#, |
262 | expect![[r#" | 262 | expect![[r#" |
263 | sn box Box::new(expr) | 263 | sn box Box::new(expr) |
264 | sn call function(expr) | 264 | sn call function(expr) |
265 | sn dbg dbg!(expr) | 265 | sn dbg dbg!(expr) |
266 | sn if if expr {} | 266 | sn if if expr {} |
267 | sn match match expr {} | 267 | sn match match expr {} |
268 | sn not !expr | 268 | sn not !expr |
269 | sn ref &expr | 269 | sn ref &expr |
270 | sn refm &mut expr | 270 | sn refm &mut expr |
271 | sn while while expr {} | 271 | sn while while expr {} |
272 | "#]], | 272 | "#]], |
273 | ); | 273 | ); |
@@ -283,12 +283,12 @@ fn main() { | |||
283 | } | 283 | } |
284 | "#, | 284 | "#, |
285 | expect![[r#" | 285 | expect![[r#" |
286 | sn box Box::new(expr) | 286 | sn box Box::new(expr) |
287 | sn call function(expr) | 287 | sn call function(expr) |
288 | sn dbg dbg!(expr) | 288 | sn dbg dbg!(expr) |
289 | sn match match expr {} | 289 | sn match match expr {} |
290 | sn ref &expr | 290 | sn ref &expr |
291 | sn refm &mut expr | 291 | sn refm &mut expr |
292 | "#]], | 292 | "#]], |
293 | ) | 293 | ) |
294 | } | 294 | } |
diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index 5175c8afe..e5553e28f 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs | |||
@@ -147,1269 +147,588 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
147 | 147 | ||
148 | #[cfg(test)] | 148 | #[cfg(test)] |
149 | mod tests { | 149 | mod tests { |
150 | use expect::{expect, Expect}; | ||
150 | use test_utils::mark; | 151 | use test_utils::mark; |
151 | 152 | ||
152 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 153 | use crate::completion::{ |
153 | use insta::assert_debug_snapshot; | 154 | test_utils::{check_edit, completion_list}, |
155 | CompletionKind, | ||
156 | }; | ||
157 | |||
158 | fn check(ra_fixture: &str, expect: Expect) { | ||
159 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | ||
160 | expect.assert_eq(&actual); | ||
161 | } | ||
154 | 162 | ||
155 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { | 163 | fn check_builtin(ra_fixture: &str, expect: Expect) { |
156 | do_completion(code, CompletionKind::Reference) | 164 | let actual = completion_list(ra_fixture, CompletionKind::BuiltinType); |
165 | expect.assert_eq(&actual); | ||
157 | } | 166 | } |
158 | 167 | ||
159 | #[test] | 168 | #[test] |
160 | fn dont_complete_current_use() { | 169 | fn dont_complete_current_use() { |
161 | mark::check!(dont_complete_current_use); | 170 | mark::check!(dont_complete_current_use); |
162 | let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); | 171 | check(r#"use self::foo<|>;"#, expect![[""]]); |
163 | assert!(completions.is_empty()); | ||
164 | } | 172 | } |
165 | 173 | ||
166 | #[test] | 174 | #[test] |
167 | fn dont_complete_current_use_in_braces_with_glob() { | 175 | fn dont_complete_current_use_in_braces_with_glob() { |
168 | let completions = do_completion( | 176 | check( |
169 | r" | 177 | r#" |
170 | mod foo { pub struct S; } | 178 | mod foo { pub struct S; } |
171 | use self::{foo::*, bar<|>}; | 179 | use self::{foo::*, bar<|>}; |
172 | ", | 180 | "#, |
173 | CompletionKind::Reference, | 181 | expect![[r#" |
182 | st S | ||
183 | md foo | ||
184 | "#]], | ||
174 | ); | 185 | ); |
175 | assert_eq!(completions.len(), 2); | ||
176 | } | 186 | } |
177 | 187 | ||
178 | #[test] | 188 | #[test] |
179 | fn dont_complete_primitive_in_use() { | 189 | fn dont_complete_primitive_in_use() { |
180 | let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); | 190 | check_builtin(r#"use self::<|>;"#, expect![[""]]); |
181 | assert!(completions.is_empty()); | ||
182 | } | 191 | } |
183 | 192 | ||
184 | #[test] | 193 | #[test] |
185 | fn dont_complete_primitive_in_module_scope() { | 194 | fn dont_complete_primitive_in_module_scope() { |
186 | let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); | 195 | check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]); |
187 | assert!(completions.is_empty()); | ||
188 | } | 196 | } |
189 | 197 | ||
190 | #[test] | 198 | #[test] |
191 | fn completes_primitives() { | 199 | fn completes_primitives() { |
192 | let completions = | 200 | check_builtin( |
193 | do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); | 201 | r#"fn main() { let _: <|> = 92; }"#, |
194 | assert_eq!(completions.len(), 17); | 202 | expect![[r#" |
195 | } | 203 | bt bool |
196 | 204 | bt char | |
197 | #[test] | 205 | bt f32 |
198 | fn completes_mod_with_docs() { | 206 | bt f64 |
199 | assert_debug_snapshot!( | 207 | bt i128 |
200 | do_reference_completion( | 208 | bt i16 |
201 | r" | 209 | bt i32 |
202 | use self::my<|>; | 210 | bt i64 |
203 | 211 | bt i8 | |
204 | /// Some simple | 212 | bt isize |
205 | /// docs describing `mod my`. | 213 | bt str |
206 | mod my { | 214 | bt u128 |
207 | struct Bar; | 215 | bt u16 |
208 | } | 216 | bt u32 |
209 | " | 217 | bt u64 |
210 | ), | 218 | bt u8 |
211 | @r###" | 219 | bt usize |
212 | [ | 220 | "#]], |
213 | CompletionItem { | ||
214 | label: "my", | ||
215 | source_range: 10..12, | ||
216 | delete: 10..12, | ||
217 | insert: "my", | ||
218 | kind: Module, | ||
219 | documentation: Documentation( | ||
220 | "Some simple\ndocs describing `mod my`.", | ||
221 | ), | ||
222 | }, | ||
223 | ] | ||
224 | "### | ||
225 | ); | 221 | ); |
226 | } | 222 | } |
227 | 223 | ||
228 | #[test] | 224 | #[test] |
229 | fn completes_mod_with_same_name_as_function() { | 225 | fn completes_mod_with_same_name_as_function() { |
230 | assert_debug_snapshot!( | 226 | check( |
231 | do_reference_completion( | 227 | r#" |
232 | r" | 228 | use self::my::<|>; |
233 | use self::my::<|>; | 229 | |
234 | 230 | mod my { pub struct Bar; } | |
235 | mod my { | 231 | fn my() {} |
236 | pub struct Bar; | 232 | "#, |
237 | } | 233 | expect![[r#" |
238 | 234 | st Bar | |
239 | fn my() {} | 235 | "#]], |
240 | " | ||
241 | ), | ||
242 | @r###" | ||
243 | [ | ||
244 | CompletionItem { | ||
245 | label: "Bar", | ||
246 | source_range: 14..14, | ||
247 | delete: 14..14, | ||
248 | insert: "Bar", | ||
249 | kind: Struct, | ||
250 | }, | ||
251 | ] | ||
252 | "### | ||
253 | ); | 236 | ); |
254 | } | 237 | } |
255 | 238 | ||
256 | #[test] | 239 | #[test] |
257 | fn path_visibility() { | 240 | fn filters_visibility() { |
258 | assert_debug_snapshot!( | 241 | check( |
259 | do_reference_completion( | 242 | r#" |
260 | r" | 243 | use self::my::<|>; |
261 | use self::my::<|>; | 244 | |
262 | 245 | mod my { | |
263 | mod my { | 246 | struct Bar; |
264 | struct Bar; | 247 | pub struct Foo; |
265 | pub struct Foo; | 248 | pub use Bar as PublicBar; |
266 | pub use Bar as PublicBar; | 249 | } |
267 | } | 250 | "#, |
268 | " | 251 | expect![[r#" |
269 | ), | 252 | st Foo |
270 | @r###" | 253 | st PublicBar |
271 | [ | 254 | "#]], |
272 | CompletionItem { | ||
273 | label: "Foo", | ||
274 | source_range: 14..14, | ||
275 | delete: 14..14, | ||
276 | insert: "Foo", | ||
277 | kind: Struct, | ||
278 | }, | ||
279 | CompletionItem { | ||
280 | label: "PublicBar", | ||
281 | source_range: 14..14, | ||
282 | delete: 14..14, | ||
283 | insert: "PublicBar", | ||
284 | kind: Struct, | ||
285 | }, | ||
286 | ] | ||
287 | "### | ||
288 | ); | 255 | ); |
289 | } | 256 | } |
290 | 257 | ||
291 | #[test] | 258 | #[test] |
292 | fn completes_use_item_starting_with_self() { | 259 | fn completes_use_item_starting_with_self() { |
293 | assert_debug_snapshot!( | 260 | check( |
294 | do_reference_completion( | 261 | r#" |
295 | r" | 262 | use self::m::<|>; |
296 | use self::m::<|>; | ||
297 | 263 | ||
298 | mod m { | 264 | mod m { pub struct Bar; } |
299 | pub struct Bar; | 265 | "#, |
300 | } | 266 | expect![[r#" |
301 | " | 267 | st Bar |
302 | ), | 268 | "#]], |
303 | @r###" | ||
304 | [ | ||
305 | CompletionItem { | ||
306 | label: "Bar", | ||
307 | source_range: 13..13, | ||
308 | delete: 13..13, | ||
309 | insert: "Bar", | ||
310 | kind: Struct, | ||
311 | }, | ||
312 | ] | ||
313 | "### | ||
314 | ); | 269 | ); |
315 | } | 270 | } |
316 | 271 | ||
317 | #[test] | 272 | #[test] |
318 | fn completes_use_item_starting_with_crate() { | 273 | fn completes_use_item_starting_with_crate() { |
319 | assert_debug_snapshot!( | 274 | check( |
320 | do_reference_completion( | 275 | r#" |
321 | " | 276 | //- /lib.rs |
322 | //- /lib.rs | 277 | mod foo; |
323 | mod foo; | 278 | struct Spam; |
324 | struct Spam; | 279 | //- /foo.rs |
325 | //- /foo.rs | 280 | use crate::Sp<|> |
326 | use crate::Sp<|> | 281 | "#, |
327 | " | 282 | expect![[r#" |
328 | ), | 283 | st Spam |
329 | @r###" | 284 | md foo |
330 | [ | 285 | "#]], |
331 | CompletionItem { | ||
332 | label: "Spam", | ||
333 | source_range: 11..13, | ||
334 | delete: 11..13, | ||
335 | insert: "Spam", | ||
336 | kind: Struct, | ||
337 | }, | ||
338 | CompletionItem { | ||
339 | label: "foo", | ||
340 | source_range: 11..13, | ||
341 | delete: 11..13, | ||
342 | insert: "foo", | ||
343 | kind: Module, | ||
344 | }, | ||
345 | ] | ||
346 | "### | ||
347 | ); | 286 | ); |
348 | } | 287 | } |
349 | 288 | ||
350 | #[test] | 289 | #[test] |
351 | fn completes_nested_use_tree() { | 290 | fn completes_nested_use_tree() { |
352 | assert_debug_snapshot!( | 291 | check( |
353 | do_reference_completion( | 292 | r#" |
354 | " | 293 | //- /lib.rs |
355 | //- /lib.rs | 294 | mod foo; |
356 | mod foo; | 295 | struct Spam; |
357 | struct Spam; | 296 | //- /foo.rs |
358 | //- /foo.rs | 297 | use crate::{Sp<|>}; |
359 | use crate::{Sp<|>}; | 298 | "#, |
360 | " | 299 | expect![[r#" |
361 | ), | 300 | st Spam |
362 | @r###" | 301 | md foo |
363 | [ | 302 | "#]], |
364 | CompletionItem { | ||
365 | label: "Spam", | ||
366 | source_range: 12..14, | ||
367 | delete: 12..14, | ||
368 | insert: "Spam", | ||
369 | kind: Struct, | ||
370 | }, | ||
371 | CompletionItem { | ||
372 | label: "foo", | ||
373 | source_range: 12..14, | ||
374 | delete: 12..14, | ||
375 | insert: "foo", | ||
376 | kind: Module, | ||
377 | }, | ||
378 | ] | ||
379 | "### | ||
380 | ); | 303 | ); |
381 | } | 304 | } |
382 | 305 | ||
383 | #[test] | 306 | #[test] |
384 | fn completes_deeply_nested_use_tree() { | 307 | fn completes_deeply_nested_use_tree() { |
385 | assert_debug_snapshot!( | 308 | check( |
386 | do_reference_completion( | 309 | r#" |
387 | " | 310 | //- /lib.rs |
388 | //- /lib.rs | 311 | mod foo; |
389 | mod foo; | 312 | pub mod bar { |
390 | pub mod bar { | 313 | pub mod baz { |
391 | pub mod baz { | 314 | pub struct Spam; |
392 | pub struct Spam; | ||
393 | } | ||
394 | } | ||
395 | //- /foo.rs | ||
396 | use crate::{bar::{baz::Sp<|>}}; | ||
397 | " | ||
398 | ), | ||
399 | @r###" | ||
400 | [ | ||
401 | CompletionItem { | ||
402 | label: "Spam", | ||
403 | source_range: 23..25, | ||
404 | delete: 23..25, | ||
405 | insert: "Spam", | ||
406 | kind: Struct, | ||
407 | }, | ||
408 | ] | ||
409 | "### | ||
410 | ); | ||
411 | } | ||
412 | |||
413 | #[test] | ||
414 | fn completes_enum_variant() { | ||
415 | assert_debug_snapshot!( | ||
416 | do_reference_completion( | ||
417 | " | ||
418 | //- /lib.rs | ||
419 | /// An enum | ||
420 | enum E { | ||
421 | /// Foo Variant | ||
422 | Foo, | ||
423 | /// Bar Variant with i32 | ||
424 | Bar(i32) | ||
425 | } | ||
426 | fn foo() { let _ = E::<|> } | ||
427 | " | ||
428 | ), | ||
429 | @r###" | ||
430 | [ | ||
431 | CompletionItem { | ||
432 | label: "Bar(…)", | ||
433 | source_range: 116..116, | ||
434 | delete: 116..116, | ||
435 | insert: "Bar($0)", | ||
436 | kind: EnumVariant, | ||
437 | lookup: "Bar", | ||
438 | detail: "(i32)", | ||
439 | documentation: Documentation( | ||
440 | "Bar Variant with i32", | ||
441 | ), | ||
442 | trigger_call_info: true, | ||
443 | }, | ||
444 | CompletionItem { | ||
445 | label: "Foo", | ||
446 | source_range: 116..116, | ||
447 | delete: 116..116, | ||
448 | insert: "Foo", | ||
449 | kind: EnumVariant, | ||
450 | detail: "()", | ||
451 | documentation: Documentation( | ||
452 | "Foo Variant", | ||
453 | ), | ||
454 | }, | ||
455 | ] | ||
456 | "### | ||
457 | ); | ||
458 | } | ||
459 | |||
460 | #[test] | ||
461 | fn completes_enum_variant_with_details() { | ||
462 | assert_debug_snapshot!( | ||
463 | do_reference_completion( | ||
464 | " | ||
465 | //- /lib.rs | ||
466 | struct S { field: u32 } | ||
467 | /// An enum | ||
468 | enum E { | ||
469 | /// Foo Variant (empty) | ||
470 | Foo, | ||
471 | /// Bar Variant with i32 and u32 | ||
472 | Bar(i32, u32), | ||
473 | /// | ||
474 | S(S), | ||
475 | } | ||
476 | fn foo() { let _ = E::<|> } | ||
477 | " | ||
478 | ), | ||
479 | @r###" | ||
480 | [ | ||
481 | CompletionItem { | ||
482 | label: "Bar(…)", | ||
483 | source_range: 180..180, | ||
484 | delete: 180..180, | ||
485 | insert: "Bar($0)", | ||
486 | kind: EnumVariant, | ||
487 | lookup: "Bar", | ||
488 | detail: "(i32, u32)", | ||
489 | documentation: Documentation( | ||
490 | "Bar Variant with i32 and u32", | ||
491 | ), | ||
492 | trigger_call_info: true, | ||
493 | }, | ||
494 | CompletionItem { | ||
495 | label: "Foo", | ||
496 | source_range: 180..180, | ||
497 | delete: 180..180, | ||
498 | insert: "Foo", | ||
499 | kind: EnumVariant, | ||
500 | detail: "()", | ||
501 | documentation: Documentation( | ||
502 | "Foo Variant (empty)", | ||
503 | ), | ||
504 | }, | ||
505 | CompletionItem { | ||
506 | label: "S(…)", | ||
507 | source_range: 180..180, | ||
508 | delete: 180..180, | ||
509 | insert: "S($0)", | ||
510 | kind: EnumVariant, | ||
511 | lookup: "S", | ||
512 | detail: "(S)", | ||
513 | documentation: Documentation( | ||
514 | "", | ||
515 | ), | ||
516 | trigger_call_info: true, | ||
517 | }, | ||
518 | ] | ||
519 | "### | ||
520 | ); | ||
521 | } | 315 | } |
522 | 316 | } | |
523 | #[test] | 317 | //- /foo.rs |
524 | fn completes_struct_associated_method() { | 318 | use crate::{bar::{baz::Sp<|>}}; |
525 | assert_debug_snapshot!( | 319 | "#, |
526 | do_reference_completion( | 320 | expect![[r#" |
527 | " | 321 | st Spam |
528 | //- /lib.rs | 322 | "#]], |
529 | /// A Struct | ||
530 | struct S; | ||
531 | |||
532 | impl S { | ||
533 | /// An associated method | ||
534 | fn m() { } | ||
535 | } | ||
536 | |||
537 | fn foo() { let _ = S::<|> } | ||
538 | " | ||
539 | ), | ||
540 | @r###" | ||
541 | [ | ||
542 | CompletionItem { | ||
543 | label: "m()", | ||
544 | source_range: 102..102, | ||
545 | delete: 102..102, | ||
546 | insert: "m()$0", | ||
547 | kind: Function, | ||
548 | lookup: "m", | ||
549 | detail: "fn m()", | ||
550 | documentation: Documentation( | ||
551 | "An associated method", | ||
552 | ), | ||
553 | }, | ||
554 | ] | ||
555 | "### | ||
556 | ); | 323 | ); |
557 | } | 324 | } |
558 | 325 | ||
559 | #[test] | 326 | #[test] |
560 | fn completes_struct_associated_method_with_self() { | 327 | fn completes_enum_variant() { |
561 | assert_debug_snapshot!( | 328 | check( |
562 | do_reference_completion( | 329 | r#" |
563 | " | 330 | enum E { Foo, Bar(i32) } |
564 | //- /lib.rs | 331 | fn foo() { let _ = E::<|> } |
565 | /// A Struct | 332 | "#, |
566 | struct S; | 333 | expect![[r#" |
567 | 334 | ev Bar(…) (i32) | |
568 | impl S { | 335 | ev Foo () |
569 | /// An associated method | 336 | "#]], |
570 | fn m(&self) { } | ||
571 | } | ||
572 | |||
573 | fn foo() { let _ = S::<|> } | ||
574 | " | ||
575 | ), | ||
576 | @r###" | ||
577 | [ | ||
578 | CompletionItem { | ||
579 | label: "m()", | ||
580 | source_range: 107..107, | ||
581 | delete: 107..107, | ||
582 | insert: "m()$0", | ||
583 | kind: Method, | ||
584 | lookup: "m", | ||
585 | detail: "fn m(&self)", | ||
586 | documentation: Documentation( | ||
587 | "An associated method", | ||
588 | ), | ||
589 | }, | ||
590 | ] | ||
591 | "### | ||
592 | ); | 337 | ); |
593 | } | 338 | } |
594 | 339 | ||
595 | #[test] | 340 | #[test] |
596 | fn completes_struct_associated_const() { | 341 | fn completes_struct_associated_items() { |
597 | assert_debug_snapshot!( | 342 | check( |
598 | do_reference_completion( | 343 | r#" |
599 | " | 344 | //- /lib.rs |
600 | //- /lib.rs | 345 | struct S; |
601 | /// A Struct | 346 | |
602 | struct S; | 347 | impl S { |
603 | 348 | fn a() {} | |
604 | impl S { | 349 | fn b(&self) {} |
605 | /// An associated const | 350 | const C: i32 = 42; |
606 | const C: i32 = 42; | 351 | type T = i32; |
607 | } | 352 | } |
608 | 353 | ||
609 | fn foo() { let _ = S::<|> } | 354 | fn foo() { let _ = S::<|> } |
610 | " | 355 | "#, |
611 | ), | 356 | expect![[r#" |
612 | @r###" | 357 | ct C const C: i32 = 42; |
613 | [ | 358 | ta T type T = i32; |
614 | CompletionItem { | 359 | fn a() fn a() |
615 | label: "C", | 360 | me b() fn b(&self) |
616 | source_range: 109..109, | 361 | "#]], |
617 | delete: 109..109, | ||
618 | insert: "C", | ||
619 | kind: Const, | ||
620 | detail: "const C: i32 = 42;", | ||
621 | documentation: Documentation( | ||
622 | "An associated const", | ||
623 | ), | ||
624 | }, | ||
625 | ] | ||
626 | "### | ||
627 | ); | 362 | ); |
628 | } | 363 | } |
629 | 364 | ||
630 | #[test] | 365 | #[test] |
631 | fn completes_struct_associated_type() { | 366 | fn associated_item_visibility() { |
632 | assert_debug_snapshot!( | 367 | check( |
633 | do_reference_completion( | 368 | r#" |
634 | " | 369 | struct S; |
635 | //- /lib.rs | ||
636 | /// A Struct | ||
637 | struct S; | ||
638 | |||
639 | impl S { | ||
640 | /// An associated type | ||
641 | type T = i32; | ||
642 | } | ||
643 | 370 | ||
644 | fn foo() { let _ = S::<|> } | 371 | mod m { |
645 | " | 372 | impl super::S { |
646 | ), | 373 | pub(super) fn public_method() { } |
647 | @r###" | 374 | fn private_method() { } |
648 | [ | 375 | pub(super) type PublicType = u32; |
649 | CompletionItem { | 376 | type PrivateType = u32; |
650 | label: "T", | 377 | pub(super) const PUBLIC_CONST: u32 = 1; |
651 | source_range: 103..103, | 378 | const PRIVATE_CONST: u32 = 1; |
652 | delete: 103..103, | ||
653 | insert: "T", | ||
654 | kind: TypeAlias, | ||
655 | detail: "type T = i32;", | ||
656 | documentation: Documentation( | ||
657 | "An associated type", | ||
658 | ), | ||
659 | }, | ||
660 | ] | ||
661 | "### | ||
662 | ); | ||
663 | } | 379 | } |
380 | } | ||
664 | 381 | ||
665 | #[test] | 382 | fn foo() { let _ = S::<|> } |
666 | fn associated_item_visibility() { | 383 | "#, |
667 | assert_debug_snapshot!( | 384 | expect![[r#" |
668 | do_reference_completion( | 385 | ct PUBLIC_CONST pub(super) const PUBLIC_CONST: u32 = 1; |
669 | " | 386 | ta PublicType pub(super) type PublicType = u32; |
670 | //- /lib.rs | 387 | fn public_method() pub(super) fn public_method() |
671 | struct S; | 388 | "#]], |
672 | |||
673 | mod m { | ||
674 | impl super::S { | ||
675 | pub(super) fn public_method() { } | ||
676 | fn private_method() { } | ||
677 | pub(super) type PublicType = u32; | ||
678 | type PrivateType = u32; | ||
679 | pub(super) const PUBLIC_CONST: u32 = 1; | ||
680 | const PRIVATE_CONST: u32 = 1; | ||
681 | } | ||
682 | } | ||
683 | |||
684 | fn foo() { let _ = S::<|> } | ||
685 | " | ||
686 | ), | ||
687 | @r###" | ||
688 | [ | ||
689 | CompletionItem { | ||
690 | label: "PUBLIC_CONST", | ||
691 | source_range: 304..304, | ||
692 | delete: 304..304, | ||
693 | insert: "PUBLIC_CONST", | ||
694 | kind: Const, | ||
695 | detail: "pub(super) const PUBLIC_CONST: u32 = 1;", | ||
696 | }, | ||
697 | CompletionItem { | ||
698 | label: "PublicType", | ||
699 | source_range: 304..304, | ||
700 | delete: 304..304, | ||
701 | insert: "PublicType", | ||
702 | kind: TypeAlias, | ||
703 | detail: "pub(super) type PublicType = u32;", | ||
704 | }, | ||
705 | CompletionItem { | ||
706 | label: "public_method()", | ||
707 | source_range: 304..304, | ||
708 | delete: 304..304, | ||
709 | insert: "public_method()$0", | ||
710 | kind: Function, | ||
711 | lookup: "public_method", | ||
712 | detail: "pub(super) fn public_method()", | ||
713 | }, | ||
714 | ] | ||
715 | "### | ||
716 | ); | 389 | ); |
717 | } | 390 | } |
718 | 391 | ||
719 | #[test] | 392 | #[test] |
720 | fn completes_enum_associated_method() { | 393 | fn completes_enum_associated_method() { |
721 | assert_debug_snapshot!( | 394 | check( |
722 | do_reference_completion( | 395 | r#" |
723 | " | 396 | enum E {}; |
724 | //- /lib.rs | 397 | impl E { fn m() { } } |
725 | /// An enum | 398 | |
726 | enum S {}; | 399 | fn foo() { let _ = E::<|> } |
727 | 400 | "#, | |
728 | impl S { | 401 | expect![[r#" |
729 | /// An associated method | 402 | fn m() fn m() |
730 | fn m() { } | 403 | "#]], |
731 | } | ||
732 | |||
733 | fn foo() { let _ = S::<|> } | ||
734 | " | ||
735 | ), | ||
736 | @r###" | ||
737 | [ | ||
738 | CompletionItem { | ||
739 | label: "m()", | ||
740 | source_range: 102..102, | ||
741 | delete: 102..102, | ||
742 | insert: "m()$0", | ||
743 | kind: Function, | ||
744 | lookup: "m", | ||
745 | detail: "fn m()", | ||
746 | documentation: Documentation( | ||
747 | "An associated method", | ||
748 | ), | ||
749 | }, | ||
750 | ] | ||
751 | "### | ||
752 | ); | 404 | ); |
753 | } | 405 | } |
754 | 406 | ||
755 | #[test] | 407 | #[test] |
756 | fn completes_union_associated_method() { | 408 | fn completes_union_associated_method() { |
757 | assert_debug_snapshot!( | 409 | check( |
758 | do_reference_completion( | 410 | r#" |
759 | " | 411 | union U {}; |
760 | //- /lib.rs | 412 | impl U { fn m() { } } |
761 | /// A union | 413 | |
762 | union U {}; | 414 | fn foo() { let _ = U::<|> } |
763 | 415 | "#, | |
764 | impl U { | 416 | expect![[r#" |
765 | /// An associated method | 417 | fn m() fn m() |
766 | fn m() { } | 418 | "#]], |
767 | } | ||
768 | |||
769 | fn foo() { let _ = U::<|> } | ||
770 | " | ||
771 | ), | ||
772 | @r###" | ||
773 | [ | ||
774 | CompletionItem { | ||
775 | label: "m()", | ||
776 | source_range: 103..103, | ||
777 | delete: 103..103, | ||
778 | insert: "m()$0", | ||
779 | kind: Function, | ||
780 | lookup: "m", | ||
781 | detail: "fn m()", | ||
782 | documentation: Documentation( | ||
783 | "An associated method", | ||
784 | ), | ||
785 | }, | ||
786 | ] | ||
787 | "### | ||
788 | ); | 419 | ); |
789 | } | 420 | } |
790 | 421 | ||
791 | #[test] | 422 | #[test] |
792 | fn completes_use_paths_across_crates() { | 423 | fn completes_use_paths_across_crates() { |
793 | assert_debug_snapshot!( | 424 | check( |
794 | do_reference_completion( | 425 | r#" |
795 | " | 426 | //- /main.rs |
796 | //- /main.rs | 427 | use foo::<|>; |
797 | use foo::<|>; | 428 | |
798 | 429 | //- /foo/lib.rs | |
799 | //- /foo/lib.rs | 430 | pub mod bar { pub struct S; } |
800 | pub mod bar { | 431 | "#, |
801 | pub struct S; | 432 | expect![[r#" |
802 | } | 433 | md bar |
803 | " | 434 | "#]], |
804 | ), | ||
805 | @r###" | ||
806 | [ | ||
807 | CompletionItem { | ||
808 | label: "bar", | ||
809 | source_range: 9..9, | ||
810 | delete: 9..9, | ||
811 | insert: "bar", | ||
812 | kind: Module, | ||
813 | }, | ||
814 | ] | ||
815 | "### | ||
816 | ); | 435 | ); |
817 | } | 436 | } |
818 | 437 | ||
819 | #[test] | 438 | #[test] |
820 | fn completes_trait_associated_method_1() { | 439 | fn completes_trait_associated_method_1() { |
821 | assert_debug_snapshot!( | 440 | check( |
822 | do_reference_completion( | 441 | r#" |
823 | " | 442 | trait Trait { fn m(); } |
824 | //- /lib.rs | ||
825 | trait Trait { | ||
826 | /// A trait method | ||
827 | fn m(); | ||
828 | } | ||
829 | 443 | ||
830 | fn foo() { let _ = Trait::<|> } | 444 | fn foo() { let _ = Trait::<|> } |
831 | " | 445 | "#, |
832 | ), | 446 | expect![[r#" |
833 | @r###" | 447 | fn m() fn m() |
834 | [ | 448 | "#]], |
835 | CompletionItem { | ||
836 | label: "m()", | ||
837 | source_range: 74..74, | ||
838 | delete: 74..74, | ||
839 | insert: "m()$0", | ||
840 | kind: Function, | ||
841 | lookup: "m", | ||
842 | detail: "fn m()", | ||
843 | documentation: Documentation( | ||
844 | "A trait method", | ||
845 | ), | ||
846 | }, | ||
847 | ] | ||
848 | "### | ||
849 | ); | 449 | ); |
850 | } | 450 | } |
851 | 451 | ||
852 | #[test] | 452 | #[test] |
853 | fn completes_trait_associated_method_2() { | 453 | fn completes_trait_associated_method_2() { |
854 | assert_debug_snapshot!( | 454 | check( |
855 | do_reference_completion( | 455 | r#" |
856 | " | 456 | trait Trait { fn m(); } |
857 | //- /lib.rs | 457 | |
858 | trait Trait { | 458 | struct S; |
859 | /// A trait method | 459 | impl Trait for S {} |
860 | fn m(); | ||
861 | } | ||
862 | 460 | ||
863 | struct S; | 461 | fn foo() { let _ = S::<|> } |
864 | impl Trait for S {} | 462 | "#, |
865 | 463 | expect![[r#" | |
866 | fn foo() { let _ = S::<|> } | 464 | fn m() fn m() |
867 | " | 465 | "#]], |
868 | ), | ||
869 | @r###" | ||
870 | [ | ||
871 | CompletionItem { | ||
872 | label: "m()", | ||
873 | source_range: 101..101, | ||
874 | delete: 101..101, | ||
875 | insert: "m()$0", | ||
876 | kind: Function, | ||
877 | lookup: "m", | ||
878 | detail: "fn m()", | ||
879 | documentation: Documentation( | ||
880 | "A trait method", | ||
881 | ), | ||
882 | }, | ||
883 | ] | ||
884 | "### | ||
885 | ); | 466 | ); |
886 | } | 467 | } |
887 | 468 | ||
888 | #[test] | 469 | #[test] |
889 | fn completes_trait_associated_method_3() { | 470 | fn completes_trait_associated_method_3() { |
890 | assert_debug_snapshot!( | 471 | check( |
891 | do_reference_completion( | 472 | r#" |
892 | " | 473 | trait Trait { fn m(); } |
893 | //- /lib.rs | ||
894 | trait Trait { | ||
895 | /// A trait method | ||
896 | fn m(); | ||
897 | } | ||
898 | 474 | ||
899 | struct S; | 475 | struct S; |
900 | impl Trait for S {} | 476 | impl Trait for S {} |
901 | 477 | ||
902 | fn foo() { let _ = <S as Trait>::<|> } | 478 | fn foo() { let _ = <S as Trait>::<|> } |
903 | " | 479 | "#, |
904 | ), | 480 | expect![[r#" |
905 | @r###" | 481 | fn m() fn m() |
906 | [ | 482 | "#]], |
907 | CompletionItem { | ||
908 | label: "m()", | ||
909 | source_range: 112..112, | ||
910 | delete: 112..112, | ||
911 | insert: "m()$0", | ||
912 | kind: Function, | ||
913 | lookup: "m", | ||
914 | detail: "fn m()", | ||
915 | documentation: Documentation( | ||
916 | "A trait method", | ||
917 | ), | ||
918 | }, | ||
919 | ] | ||
920 | "### | ||
921 | ); | 483 | ); |
922 | } | 484 | } |
923 | 485 | ||
924 | #[test] | 486 | #[test] |
925 | fn completes_ty_param_assoc_ty() { | 487 | fn completes_ty_param_assoc_ty() { |
926 | assert_debug_snapshot!( | 488 | check( |
927 | do_reference_completion( | 489 | r#" |
928 | " | 490 | trait Super { |
929 | //- /lib.rs | 491 | type Ty; |
930 | trait Super { | 492 | const CONST: u8; |
931 | type Ty; | 493 | fn func() {} |
932 | const CONST: u8; | 494 | fn method(&self) {} |
933 | fn func() {} | 495 | } |
934 | fn method(&self) {} | ||
935 | } | ||
936 | 496 | ||
937 | trait Sub: Super { | 497 | trait Sub: Super { |
938 | type SubTy; | 498 | type SubTy; |
939 | const C2: (); | 499 | const C2: (); |
940 | fn subfunc() {} | 500 | fn subfunc() {} |
941 | fn submethod(&self) {} | 501 | fn submethod(&self) {} |
942 | } | 502 | } |
943 | 503 | ||
944 | fn foo<T: Sub>() { | 504 | fn foo<T: Sub>() { T::<|> } |
945 | T::<|> | 505 | "#, |
946 | } | 506 | expect![[r#" |
947 | " | 507 | ct C2 const C2: (); |
948 | ), | 508 | ct CONST const CONST: u8; |
949 | @r###" | 509 | ta SubTy type SubTy; |
950 | [ | 510 | ta Ty type Ty; |
951 | CompletionItem { | 511 | fn func() fn func() |
952 | label: "C2", | 512 | me method() fn method(&self) |
953 | source_range: 221..221, | 513 | fn subfunc() fn subfunc() |
954 | delete: 221..221, | 514 | me submethod() fn submethod(&self) |
955 | insert: "C2", | 515 | "#]], |
956 | kind: Const, | ||
957 | detail: "const C2: ();", | ||
958 | }, | ||
959 | CompletionItem { | ||
960 | label: "CONST", | ||
961 | source_range: 221..221, | ||
962 | delete: 221..221, | ||
963 | insert: "CONST", | ||
964 | kind: Const, | ||
965 | detail: "const CONST: u8;", | ||
966 | }, | ||
967 | CompletionItem { | ||
968 | label: "SubTy", | ||
969 | source_range: 221..221, | ||
970 | delete: 221..221, | ||
971 | insert: "SubTy", | ||
972 | kind: TypeAlias, | ||
973 | detail: "type SubTy;", | ||
974 | }, | ||
975 | CompletionItem { | ||
976 | label: "Ty", | ||
977 | source_range: 221..221, | ||
978 | delete: 221..221, | ||
979 | insert: "Ty", | ||
980 | kind: TypeAlias, | ||
981 | detail: "type Ty;", | ||
982 | }, | ||
983 | CompletionItem { | ||
984 | label: "func()", | ||
985 | source_range: 221..221, | ||
986 | delete: 221..221, | ||
987 | insert: "func()$0", | ||
988 | kind: Function, | ||
989 | lookup: "func", | ||
990 | detail: "fn func()", | ||
991 | }, | ||
992 | CompletionItem { | ||
993 | label: "method()", | ||
994 | source_range: 221..221, | ||
995 | delete: 221..221, | ||
996 | insert: "method()$0", | ||
997 | kind: Method, | ||
998 | lookup: "method", | ||
999 | detail: "fn method(&self)", | ||
1000 | }, | ||
1001 | CompletionItem { | ||
1002 | label: "subfunc()", | ||
1003 | source_range: 221..221, | ||
1004 | delete: 221..221, | ||
1005 | insert: "subfunc()$0", | ||
1006 | kind: Function, | ||
1007 | lookup: "subfunc", | ||
1008 | detail: "fn subfunc()", | ||
1009 | }, | ||
1010 | CompletionItem { | ||
1011 | label: "submethod()", | ||
1012 | source_range: 221..221, | ||
1013 | delete: 221..221, | ||
1014 | insert: "submethod()$0", | ||
1015 | kind: Method, | ||
1016 | lookup: "submethod", | ||
1017 | detail: "fn submethod(&self)", | ||
1018 | }, | ||
1019 | ] | ||
1020 | "### | ||
1021 | ); | 516 | ); |
1022 | } | 517 | } |
1023 | 518 | ||
1024 | #[test] | 519 | #[test] |
1025 | fn completes_self_param_assoc_ty() { | 520 | fn completes_self_param_assoc_ty() { |
1026 | assert_debug_snapshot!( | 521 | check( |
1027 | do_reference_completion( | 522 | r#" |
1028 | " | 523 | trait Super { |
1029 | //- /lib.rs | 524 | type Ty; |
1030 | trait Super { | 525 | const CONST: u8 = 0; |
1031 | type Ty; | 526 | fn func() {} |
1032 | const CONST: u8 = 0; | 527 | fn method(&self) {} |
1033 | fn func() {} | 528 | } |
1034 | fn method(&self) {} | ||
1035 | } | ||
1036 | 529 | ||
1037 | trait Sub: Super { | 530 | trait Sub: Super { |
1038 | type SubTy; | 531 | type SubTy; |
1039 | const C2: () = (); | 532 | const C2: () = (); |
1040 | fn subfunc() {} | 533 | fn subfunc() {} |
1041 | fn submethod(&self) {} | 534 | fn submethod(&self) {} |
1042 | } | 535 | } |
1043 | 536 | ||
1044 | struct Wrap<T>(T); | 537 | struct Wrap<T>(T); |
1045 | impl<T> Super for Wrap<T> {} | 538 | impl<T> Super for Wrap<T> {} |
1046 | impl<T> Sub for Wrap<T> { | 539 | impl<T> Sub for Wrap<T> { |
1047 | fn subfunc() { | 540 | fn subfunc() { |
1048 | // Should be able to assume `Self: Sub + Super` | 541 | // Should be able to assume `Self: Sub + Super` |
1049 | Self::<|> | 542 | Self::<|> |
1050 | } | 543 | } |
1051 | } | 544 | } |
1052 | " | 545 | "#, |
1053 | ), | 546 | expect![[r#" |
1054 | @r###" | 547 | ct C2 const C2: () = (); |
1055 | [ | 548 | ct CONST const CONST: u8 = 0; |
1056 | CompletionItem { | 549 | ta SubTy type SubTy; |
1057 | label: "C2", | 550 | ta Ty type Ty; |
1058 | source_range: 367..367, | 551 | fn func() fn func() |
1059 | delete: 367..367, | 552 | me method() fn method(&self) |
1060 | insert: "C2", | 553 | fn subfunc() fn subfunc() |
1061 | kind: Const, | 554 | me submethod() fn submethod(&self) |
1062 | detail: "const C2: () = ();", | 555 | "#]], |
1063 | }, | ||
1064 | CompletionItem { | ||
1065 | label: "CONST", | ||
1066 | source_range: 367..367, | ||
1067 | delete: 367..367, | ||
1068 | insert: "CONST", | ||
1069 | kind: Const, | ||
1070 | detail: "const CONST: u8 = 0;", | ||
1071 | }, | ||
1072 | CompletionItem { | ||
1073 | label: "SubTy", | ||
1074 | source_range: 367..367, | ||
1075 | delete: 367..367, | ||
1076 | insert: "SubTy", | ||
1077 | kind: TypeAlias, | ||
1078 | detail: "type SubTy;", | ||
1079 | }, | ||
1080 | CompletionItem { | ||
1081 | label: "Ty", | ||
1082 | source_range: 367..367, | ||
1083 | delete: 367..367, | ||
1084 | insert: "Ty", | ||
1085 | kind: TypeAlias, | ||
1086 | detail: "type Ty;", | ||
1087 | }, | ||
1088 | CompletionItem { | ||
1089 | label: "func()", | ||
1090 | source_range: 367..367, | ||
1091 | delete: 367..367, | ||
1092 | insert: "func()$0", | ||
1093 | kind: Function, | ||
1094 | lookup: "func", | ||
1095 | detail: "fn func()", | ||
1096 | }, | ||
1097 | CompletionItem { | ||
1098 | label: "method()", | ||
1099 | source_range: 367..367, | ||
1100 | delete: 367..367, | ||
1101 | insert: "method()$0", | ||
1102 | kind: Method, | ||
1103 | lookup: "method", | ||
1104 | detail: "fn method(&self)", | ||
1105 | }, | ||
1106 | CompletionItem { | ||
1107 | label: "subfunc()", | ||
1108 | source_range: 367..367, | ||
1109 | delete: 367..367, | ||
1110 | insert: "subfunc()$0", | ||
1111 | kind: Function, | ||
1112 | lookup: "subfunc", | ||
1113 | detail: "fn subfunc()", | ||
1114 | }, | ||
1115 | CompletionItem { | ||
1116 | label: "submethod()", | ||
1117 | source_range: 367..367, | ||
1118 | delete: 367..367, | ||
1119 | insert: "submethod()$0", | ||
1120 | kind: Method, | ||
1121 | lookup: "submethod", | ||
1122 | detail: "fn submethod(&self)", | ||
1123 | }, | ||
1124 | ] | ||
1125 | "### | ||
1126 | ); | 556 | ); |
1127 | } | 557 | } |
1128 | 558 | ||
1129 | #[test] | 559 | #[test] |
1130 | fn completes_type_alias() { | 560 | fn completes_type_alias() { |
1131 | assert_debug_snapshot!( | 561 | check( |
1132 | do_reference_completion( | 562 | r#" |
1133 | " | 563 | struct S; |
1134 | struct S; | 564 | impl S { fn foo() {} } |
1135 | impl S { fn foo() {} } | 565 | type T = S; |
1136 | type T = S; | 566 | impl T { fn bar() {} } |
1137 | impl T { fn bar() {} } | 567 | |
1138 | 568 | fn main() { T::<|>; } | |
1139 | fn main() { | 569 | "#, |
1140 | T::<|>; | 570 | expect![[r#" |
1141 | } | 571 | fn bar() fn bar() |
1142 | " | 572 | fn foo() fn foo() |
1143 | ), | 573 | "#]], |
1144 | @r###" | ||
1145 | [ | ||
1146 | CompletionItem { | ||
1147 | label: "bar()", | ||
1148 | source_range: 88..88, | ||
1149 | delete: 88..88, | ||
1150 | insert: "bar()$0", | ||
1151 | kind: Function, | ||
1152 | lookup: "bar", | ||
1153 | detail: "fn bar()", | ||
1154 | }, | ||
1155 | CompletionItem { | ||
1156 | label: "foo()", | ||
1157 | source_range: 88..88, | ||
1158 | delete: 88..88, | ||
1159 | insert: "foo()$0", | ||
1160 | kind: Function, | ||
1161 | lookup: "foo", | ||
1162 | detail: "fn foo()", | ||
1163 | }, | ||
1164 | ] | ||
1165 | "### | ||
1166 | ); | 574 | ); |
1167 | } | 575 | } |
1168 | 576 | ||
1169 | #[test] | 577 | #[test] |
1170 | fn completes_qualified_macros() { | 578 | fn completes_qualified_macros() { |
1171 | assert_debug_snapshot!( | 579 | check( |
1172 | do_reference_completion( | 580 | r#" |
1173 | " | 581 | #[macro_export] |
1174 | #[macro_export] | 582 | macro_rules! foo { () => {} } |
1175 | macro_rules! foo { | 583 | |
1176 | () => {} | 584 | fn main() { let _ = crate::<|> } |
1177 | } | 585 | "#, |
1178 | 586 | expect![[r##" | |
1179 | fn main() { | 587 | ma foo!(…) #[macro_export] |
1180 | let _ = crate::<|> | 588 | macro_rules! foo |
1181 | } | 589 | fn main() fn main() |
1182 | " | 590 | "##]], |
1183 | ), | ||
1184 | @r###" | ||
1185 | [ | ||
1186 | CompletionItem { | ||
1187 | label: "foo!(…)", | ||
1188 | source_range: 82..82, | ||
1189 | delete: 82..82, | ||
1190 | insert: "foo!($0)", | ||
1191 | kind: Macro, | ||
1192 | lookup: "foo!", | ||
1193 | detail: "#[macro_export]\nmacro_rules! foo", | ||
1194 | }, | ||
1195 | CompletionItem { | ||
1196 | label: "main()", | ||
1197 | source_range: 82..82, | ||
1198 | delete: 82..82, | ||
1199 | insert: "main()$0", | ||
1200 | kind: Function, | ||
1201 | lookup: "main", | ||
1202 | detail: "fn main()", | ||
1203 | }, | ||
1204 | ] | ||
1205 | "### | ||
1206 | ); | 591 | ); |
1207 | } | 592 | } |
1208 | 593 | ||
1209 | #[test] | 594 | #[test] |
1210 | fn test_super_super_completion() { | 595 | fn test_super_super_completion() { |
1211 | assert_debug_snapshot!( | 596 | check( |
1212 | do_reference_completion( | 597 | r#" |
1213 | r" | 598 | mod a { |
1214 | mod a { | 599 | const A: usize = 0; |
1215 | const A: usize = 0; | 600 | mod b { |
1216 | 601 | const B: usize = 0; | |
1217 | mod b { | 602 | mod c { use super::super::<|> } |
1218 | const B: usize = 0; | 603 | } |
1219 | 604 | } | |
1220 | mod c { | 605 | "#, |
1221 | use super::super::<|> | 606 | expect![[r#" |
1222 | } | 607 | ct A |
1223 | } | 608 | md b |
1224 | } | 609 | "#]], |
1225 | ", | ||
1226 | ), | ||
1227 | @r###" | ||
1228 | [ | ||
1229 | CompletionItem { | ||
1230 | label: "A", | ||
1231 | source_range: 120..120, | ||
1232 | delete: 120..120, | ||
1233 | insert: "A", | ||
1234 | kind: Const, | ||
1235 | }, | ||
1236 | CompletionItem { | ||
1237 | label: "b", | ||
1238 | source_range: 120..120, | ||
1239 | delete: 120..120, | ||
1240 | insert: "b", | ||
1241 | kind: Module, | ||
1242 | }, | ||
1243 | ] | ||
1244 | "### | ||
1245 | ); | 610 | ); |
1246 | } | 611 | } |
1247 | 612 | ||
1248 | #[test] | 613 | #[test] |
1249 | fn completes_reexported_items_under_correct_name() { | 614 | fn completes_reexported_items_under_correct_name() { |
1250 | assert_debug_snapshot!( | 615 | check( |
1251 | do_reference_completion( | 616 | r#" |
1252 | r" | 617 | fn foo() { self::m::<|> } |
1253 | fn foo() { | ||
1254 | self::m::<|> | ||
1255 | } | ||
1256 | 618 | ||
1257 | mod m { | 619 | mod m { |
1258 | pub use super::p::wrong_fn as right_fn; | 620 | pub use super::p::wrong_fn as right_fn; |
1259 | pub use super::p::WRONG_CONST as RIGHT_CONST; | 621 | pub use super::p::WRONG_CONST as RIGHT_CONST; |
1260 | pub use super::p::WrongType as RightType; | 622 | pub use super::p::WrongType as RightType; |
1261 | } | 623 | } |
1262 | mod p { | 624 | mod p { |
1263 | fn wrong_fn() {} | 625 | fn wrong_fn() {} |
1264 | const WRONG_CONST: u32 = 1; | 626 | const WRONG_CONST: u32 = 1; |
1265 | struct WrongType {}; | 627 | struct WrongType {}; |
1266 | } | 628 | } |
1267 | " | 629 | "#, |
1268 | ), | 630 | expect![[r#" |
1269 | @r###" | 631 | ct RIGHT_CONST |
1270 | [ | 632 | st RightType |
1271 | CompletionItem { | 633 | fn right_fn() fn wrong_fn() |
1272 | label: "RIGHT_CONST", | 634 | "#]], |
1273 | source_range: 24..24, | 635 | ); |
1274 | delete: 24..24, | 636 | |
1275 | insert: "RIGHT_CONST", | 637 | check_edit( |
1276 | kind: Const, | 638 | "RightType", |
1277 | }, | 639 | r#" |
1278 | CompletionItem { | 640 | fn foo() { self::m::<|> } |
1279 | label: "RightType", | 641 | |
1280 | source_range: 24..24, | 642 | mod m { |
1281 | delete: 24..24, | 643 | pub use super::p::wrong_fn as right_fn; |
1282 | insert: "RightType", | 644 | pub use super::p::WRONG_CONST as RIGHT_CONST; |
1283 | kind: Struct, | 645 | pub use super::p::WrongType as RightType; |
1284 | }, | 646 | } |
1285 | CompletionItem { | 647 | mod p { |
1286 | label: "right_fn()", | 648 | fn wrong_fn() {} |
1287 | source_range: 24..24, | 649 | const WRONG_CONST: u32 = 1; |
1288 | delete: 24..24, | 650 | struct WrongType {}; |
1289 | insert: "right_fn()$0", | 651 | } |
1290 | kind: Function, | 652 | "#, |
1291 | lookup: "right_fn", | 653 | r#" |
1292 | detail: "fn wrong_fn()", | 654 | fn foo() { self::m::RightType } |
1293 | }, | 655 | |
1294 | ] | 656 | mod m { |
1295 | "### | 657 | pub use super::p::wrong_fn as right_fn; |
658 | pub use super::p::WRONG_CONST as RIGHT_CONST; | ||
659 | pub use super::p::WrongType as RightType; | ||
660 | } | ||
661 | mod p { | ||
662 | fn wrong_fn() {} | ||
663 | const WRONG_CONST: u32 = 1; | ||
664 | struct WrongType {}; | ||
665 | } | ||
666 | "#, | ||
1296 | ); | 667 | ); |
1297 | } | 668 | } |
1298 | 669 | ||
1299 | #[test] | 670 | #[test] |
1300 | fn completes_in_simple_macro_call() { | 671 | fn completes_in_simple_macro_call() { |
1301 | let completions = do_reference_completion( | 672 | check( |
1302 | r#" | 673 | r#" |
1303 | macro_rules! m { ($e:expr) => { $e } } | 674 | macro_rules! m { ($e:expr) => { $e } } |
1304 | fn main() { m!(self::f<|>); } | 675 | fn main() { m!(self::f<|>); } |
1305 | fn foo() {} | 676 | fn foo() {} |
1306 | "#, | 677 | "#, |
678 | expect![[r#" | ||
679 | fn foo() fn foo() | ||
680 | fn main() fn main() | ||
681 | "#]], | ||
1307 | ); | 682 | ); |
1308 | assert_debug_snapshot!(completions, @r###" | ||
1309 | [ | ||
1310 | CompletionItem { | ||
1311 | label: "foo()", | ||
1312 | source_range: 60..61, | ||
1313 | delete: 60..61, | ||
1314 | insert: "foo()$0", | ||
1315 | kind: Function, | ||
1316 | lookup: "foo", | ||
1317 | detail: "fn foo()", | ||
1318 | }, | ||
1319 | CompletionItem { | ||
1320 | label: "main()", | ||
1321 | source_range: 60..61, | ||
1322 | delete: 60..61, | ||
1323 | insert: "main()$0", | ||
1324 | kind: Function, | ||
1325 | lookup: "main", | ||
1326 | detail: "fn main()", | ||
1327 | }, | ||
1328 | ] | ||
1329 | "###); | ||
1330 | } | 683 | } |
1331 | 684 | ||
1332 | #[test] | 685 | #[test] |
1333 | fn function_mod_share_name() { | 686 | fn function_mod_share_name() { |
1334 | assert_debug_snapshot!( | 687 | check( |
1335 | do_reference_completion( | 688 | r#" |
1336 | r" | 689 | fn foo() { self::m::<|> } |
1337 | fn foo() { | ||
1338 | self::m::<|> | ||
1339 | } | ||
1340 | 690 | ||
1341 | mod m { | 691 | mod m { |
1342 | pub mod z {} | 692 | pub mod z {} |
1343 | pub fn z() {} | 693 | pub fn z() {} |
1344 | } | 694 | } |
1345 | ", | 695 | "#, |
1346 | ), | 696 | expect![[r#" |
1347 | @r###" | 697 | md z |
1348 | [ | 698 | fn z() pub fn z() |
1349 | CompletionItem { | 699 | "#]], |
1350 | label: "z", | ||
1351 | source_range: 24..24, | ||
1352 | delete: 24..24, | ||
1353 | insert: "z", | ||
1354 | kind: Module, | ||
1355 | }, | ||
1356 | CompletionItem { | ||
1357 | label: "z()", | ||
1358 | source_range: 24..24, | ||
1359 | delete: 24..24, | ||
1360 | insert: "z()$0", | ||
1361 | kind: Function, | ||
1362 | lookup: "z", | ||
1363 | detail: "pub fn z()", | ||
1364 | }, | ||
1365 | ] | ||
1366 | "### | ||
1367 | ); | 700 | ); |
1368 | } | 701 | } |
1369 | 702 | ||
1370 | #[test] | 703 | #[test] |
1371 | fn completes_hashmap_new() { | 704 | fn completes_hashmap_new() { |
1372 | assert_debug_snapshot!( | 705 | check( |
1373 | do_reference_completion( | 706 | r#" |
1374 | r" | 707 | struct RandomState; |
1375 | struct RandomState; | 708 | struct HashMap<K, V, S = RandomState> {} |
1376 | struct HashMap<K, V, S = RandomState> {} | 709 | |
1377 | 710 | impl<K, V> HashMap<K, V, RandomState> { | |
1378 | impl<K, V> HashMap<K, V, RandomState> { | 711 | pub fn new() -> HashMap<K, V, RandomState> { } |
1379 | pub fn new() -> HashMap<K, V, RandomState> { } | 712 | } |
1380 | } | 713 | fn foo() { |
1381 | fn foo() { | 714 | HashMap::<|> |
1382 | HashMap::<|> | 715 | } |
1383 | } | 716 | "#, |
1384 | " | 717 | expect![[r#" |
1385 | ), | 718 | fn new() pub fn new() -> HashMap<K, V, RandomState> |
1386 | @r###" | 719 | "#]], |
1387 | [ | ||
1388 | CompletionItem { | ||
1389 | label: "new()", | ||
1390 | source_range: 179..179, | ||
1391 | delete: 179..179, | ||
1392 | insert: "new()$0", | ||
1393 | kind: Function, | ||
1394 | lookup: "new", | ||
1395 | detail: "pub fn new() -> HashMap<K, V, RandomState>", | ||
1396 | }, | ||
1397 | ] | ||
1398 | "### | ||
1399 | ); | 720 | ); |
1400 | } | 721 | } |
1401 | 722 | ||
1402 | #[test] | 723 | #[test] |
1403 | fn dont_complete_attr() { | 724 | fn dont_complete_attr() { |
1404 | assert_debug_snapshot!( | 725 | check( |
1405 | do_reference_completion( | 726 | r#" |
1406 | r" | 727 | mod foo { pub struct Foo; } |
1407 | mod foo { pub struct Foo; } | 728 | #[foo::<|>] |
1408 | #[foo::<|>] | 729 | fn f() {} |
1409 | fn f() {} | 730 | "#, |
1410 | " | 731 | expect![[""]], |
1411 | ), | 732 | ); |
1412 | @r###"[]"### | ||
1413 | ) | ||
1414 | } | 733 | } |
1415 | } | 734 | } |
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index 52aaa70f0..28d8f7876 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs | |||
@@ -70,95 +70,47 @@ fn ${1:feature}() { | |||
70 | 70 | ||
71 | #[cfg(test)] | 71 | #[cfg(test)] |
72 | mod tests { | 72 | mod tests { |
73 | use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; | 73 | use expect::{expect, Expect}; |
74 | use insta::assert_debug_snapshot; | ||
75 | 74 | ||
76 | fn do_snippet_completion(code: &str) -> Vec<CompletionItem> { | 75 | use crate::completion::{test_utils::completion_list, CompletionKind}; |
77 | do_completion(code, CompletionKind::Snippet) | 76 | |
77 | fn check(ra_fixture: &str, expect: Expect) { | ||
78 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
79 | expect.assert_eq(&actual) | ||
78 | } | 80 | } |
79 | 81 | ||
80 | #[test] | 82 | #[test] |
81 | fn completes_snippets_in_expressions() { | 83 | fn completes_snippets_in_expressions() { |
82 | assert_debug_snapshot!( | 84 | check( |
83 | do_snippet_completion(r"fn foo(x: i32) { <|> }"), | 85 | r#"fn foo(x: i32) { <|> }"#, |
84 | @r###" | 86 | expect![[r#" |
85 | [ | 87 | sn pd |
86 | CompletionItem { | 88 | sn ppd |
87 | label: "pd", | 89 | "#]], |
88 | source_range: 17..17, | 90 | ); |
89 | delete: 17..17, | ||
90 | insert: "eprintln!(\"$0 = {:?}\", $0);", | ||
91 | kind: Snippet, | ||
92 | }, | ||
93 | CompletionItem { | ||
94 | label: "ppd", | ||
95 | source_range: 17..17, | ||
96 | delete: 17..17, | ||
97 | insert: "eprintln!(\"$0 = {:#?}\", $0);", | ||
98 | kind: Snippet, | ||
99 | }, | ||
100 | ] | ||
101 | "### | ||
102 | ); | ||
103 | } | 91 | } |
104 | 92 | ||
105 | #[test] | 93 | #[test] |
106 | fn should_not_complete_snippets_in_path() { | 94 | fn should_not_complete_snippets_in_path() { |
107 | assert_debug_snapshot!( | 95 | check(r#"fn foo(x: i32) { ::foo<|> }"#, expect![[""]]); |
108 | do_snippet_completion(r"fn foo(x: i32) { ::foo<|> }"), | 96 | check(r#"fn foo(x: i32) { ::<|> }"#, expect![[""]]); |
109 | @"[]" | ||
110 | ); | ||
111 | assert_debug_snapshot!( | ||
112 | do_snippet_completion(r"fn foo(x: i32) { ::<|> }"), | ||
113 | @"[]" | ||
114 | ); | ||
115 | } | 97 | } |
116 | 98 | ||
117 | #[test] | 99 | #[test] |
118 | fn completes_snippets_in_items() { | 100 | fn completes_snippets_in_items() { |
119 | assert_debug_snapshot!( | 101 | check( |
120 | do_snippet_completion( | 102 | r#" |
121 | r" | 103 | #[cfg(test)] |
122 | #[cfg(test)] | 104 | mod tests { |
123 | mod tests { | 105 | <|> |
124 | <|> | 106 | } |
125 | } | 107 | "#, |
126 | " | 108 | expect![[r#" |
127 | ), | 109 | sn Test function |
128 | @r###" | 110 | sn Test module |
129 | [ | 111 | sn macro_rules |
130 | CompletionItem { | 112 | sn pub(crate) |
131 | label: "Test function", | 113 | "#]], |
132 | source_range: 29..29, | 114 | ) |
133 | delete: 29..29, | ||
134 | insert: "#[test]\nfn ${1:feature}() {\n $0\n}", | ||
135 | kind: Snippet, | ||
136 | lookup: "tfn", | ||
137 | }, | ||
138 | CompletionItem { | ||
139 | label: "Test module", | ||
140 | source_range: 29..29, | ||
141 | delete: 29..29, | ||
142 | insert: "#[cfg(test)]\nmod tests {\n use super::*;\n\n #[test]\n fn ${1:test_name}() {\n $0\n }\n}", | ||
143 | kind: Snippet, | ||
144 | lookup: "tmod", | ||
145 | }, | ||
146 | CompletionItem { | ||
147 | label: "macro_rules", | ||
148 | source_range: 29..29, | ||
149 | delete: 29..29, | ||
150 | insert: "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}", | ||
151 | kind: Snippet, | ||
152 | }, | ||
153 | CompletionItem { | ||
154 | label: "pub(crate)", | ||
155 | source_range: 29..29, | ||
156 | delete: 29..29, | ||
157 | insert: "pub(crate) $0", | ||
158 | kind: Snippet, | ||
159 | }, | ||
160 | ] | ||
161 | "### | ||
162 | ); | ||
163 | } | 115 | } |
164 | } | 116 | } |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 946bbef7c..bfa7e08be 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -683,6 +683,57 @@ impl S { | |||
683 | }, | 683 | }, |
684 | ] | 684 | ] |
685 | "#]], | 685 | "#]], |
686 | ); | ||
687 | |||
688 | check( | ||
689 | r#" | ||
690 | use self::my<|>; | ||
691 | |||
692 | /// mod docs | ||
693 | mod my { } | ||
694 | |||
695 | /// enum docs | ||
696 | enum E { | ||
697 | /// variant docs | ||
698 | V | ||
699 | } | ||
700 | use self::E::*; | ||
701 | "#, | ||
702 | expect![[r#" | ||
703 | [ | ||
704 | CompletionItem { | ||
705 | label: "E", | ||
706 | source_range: 10..12, | ||
707 | delete: 10..12, | ||
708 | insert: "E", | ||
709 | kind: Enum, | ||
710 | documentation: Documentation( | ||
711 | "enum docs", | ||
712 | ), | ||
713 | }, | ||
714 | CompletionItem { | ||
715 | label: "V", | ||
716 | source_range: 10..12, | ||
717 | delete: 10..12, | ||
718 | insert: "V", | ||
719 | kind: EnumVariant, | ||
720 | detail: "()", | ||
721 | documentation: Documentation( | ||
722 | "variant docs", | ||
723 | ), | ||
724 | }, | ||
725 | CompletionItem { | ||
726 | label: "my", | ||
727 | source_range: 10..12, | ||
728 | delete: 10..12, | ||
729 | insert: "my", | ||
730 | kind: Module, | ||
731 | documentation: Documentation( | ||
732 | "mod docs", | ||
733 | ), | ||
734 | }, | ||
735 | ] | ||
736 | "#]], | ||
686 | ) | 737 | ) |
687 | } | 738 | } |
688 | 739 | ||
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs index cbae1da85..c2be23697 100644 --- a/crates/ra_ide/src/completion/test_utils.rs +++ b/crates/ra_ide/src/completion/test_utils.rs | |||
@@ -43,12 +43,21 @@ pub(crate) fn completion_list_with_config( | |||
43 | .filter(|c| c.completion_kind == kind) | 43 | .filter(|c| c.completion_kind == kind) |
44 | .collect(); | 44 | .collect(); |
45 | kind_completions.sort_by_key(|c| c.label().to_owned()); | 45 | kind_completions.sort_by_key(|c| c.label().to_owned()); |
46 | let label_width = kind_completions | ||
47 | .iter() | ||
48 | .map(|it| monospace_width(it.label())) | ||
49 | .max() | ||
50 | .unwrap_or_default() | ||
51 | .min(16); | ||
46 | kind_completions | 52 | kind_completions |
47 | .into_iter() | 53 | .into_iter() |
48 | .map(|it| { | 54 | .map(|it| { |
49 | let mut buf = format!("{} {}", it.kind().unwrap().tag(), it.label()); | 55 | let tag = it.kind().unwrap().tag(); |
56 | let var_name = format!("{} {}", tag, it.label()); | ||
57 | let mut buf = var_name; | ||
50 | if let Some(detail) = it.detail() { | 58 | if let Some(detail) = it.detail() { |
51 | format_to!(buf, " {}", detail); | 59 | let width = label_width.saturating_sub(monospace_width(it.label())); |
60 | format_to!(buf, "{:width$} {}", "", detail, width = width); | ||
52 | } | 61 | } |
53 | format_to!(buf, "\n"); | 62 | format_to!(buf, "\n"); |
54 | buf | 63 | buf |
@@ -56,6 +65,10 @@ pub(crate) fn completion_list_with_config( | |||
56 | .collect() | 65 | .collect() |
57 | } | 66 | } |
58 | 67 | ||
68 | fn monospace_width(s: &str) -> usize { | ||
69 | s.chars().count() | ||
70 | } | ||
71 | |||
59 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 72 | pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
60 | check_edit_with_config(what, ra_fixture_before, ra_fixture_after, &CompletionConfig::default()) | 73 | check_edit_with_config(what, ra_fixture_before, ra_fixture_after, &CompletionConfig::default()) |
61 | } | 74 | } |