aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/presentation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r--crates/ra_ide/src/completion/presentation.rs194
1 files changed, 158 insertions, 36 deletions
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 3930316b0..cdfd7bc32 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -57,14 +57,16 @@ impl Completions {
57 let kind = match resolution { 57 let kind = match resolution {
58 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, 58 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
59 ScopeDef::ModuleDef(Function(func)) => { 59 ScopeDef::ModuleDef(Function(func)) => {
60 return self.add_function_with_name(ctx, Some(local_name), *func); 60 return self.add_function(ctx, *func, Some(local_name));
61 } 61 }
62 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, 62 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
63 // FIXME: add CompletionItemKind::Union 63 // FIXME: add CompletionItemKind::Union
64 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, 64 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
65 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, 65 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
66 66
67 ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant, 67 ScopeDef::ModuleDef(EnumVariant(var)) => {
68 return self.add_enum_variant(ctx, *var, Some(local_name));
69 }
68 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, 70 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
69 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, 71 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
70 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, 72 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
@@ -125,10 +127,6 @@ impl Completions {
125 completion_item.kind(kind).set_documentation(docs).add_to(self) 127 completion_item.kind(kind).set_documentation(docs).add_to(self)
126 } 128 }
127 129
128 pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) {
129 self.add_function_with_name(ctx, None, func)
130 }
131
132 fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { 130 fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str {
133 let mut votes = [0, 0, 0]; 131 let mut votes = [0, 0, 0];
134 for (idx, s) in docs.match_indices(&macro_name) { 132 for (idx, s) in docs.match_indices(&macro_name) {
@@ -187,15 +185,15 @@ impl Completions {
187 self.add(builder); 185 self.add(builder);
188 } 186 }
189 187
190 fn add_function_with_name( 188 pub(crate) fn add_function(
191 &mut self, 189 &mut self,
192 ctx: &CompletionContext, 190 ctx: &CompletionContext,
193 name: Option<String>,
194 func: hir::Function, 191 func: hir::Function,
192 local_name: Option<String>,
195 ) { 193 ) {
196 let has_self_param = func.has_self_param(ctx.db); 194 let has_self_param = func.has_self_param(ctx.db);
197 195
198 let name = name.unwrap_or_else(|| func.name(ctx.db).to_string()); 196 let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string());
199 let ast_node = func.source(ctx.db).value; 197 let ast_node = func.source(ctx.db).value;
200 let function_signature = FunctionSignature::from(&ast_node); 198 let function_signature = FunctionSignature::from(&ast_node);
201 199
@@ -217,7 +215,7 @@ impl Completions {
217 .cloned() 215 .cloned()
218 .collect(); 216 .collect();
219 217
220 builder = builder.add_call_parens(ctx, name, params); 218 builder = builder.add_call_parens(ctx, name, Params::Named(params));
221 219
222 self.add(builder) 220 self.add(builder)
223 } 221 }
@@ -254,14 +252,20 @@ impl Completions {
254 .add_to(self); 252 .add_to(self);
255 } 253 }
256 254
257 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { 255 pub(crate) fn add_enum_variant(
256 &mut self,
257 ctx: &CompletionContext,
258 variant: hir::EnumVariant,
259 local_name: Option<String>,
260 ) {
258 let is_deprecated = is_deprecated(variant, ctx.db); 261 let is_deprecated = is_deprecated(variant, ctx.db);
259 let name = variant.name(ctx.db); 262 let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string());
260 let detail_types = variant 263 let detail_types = variant
261 .fields(ctx.db) 264 .fields(ctx.db)
262 .into_iter() 265 .into_iter()
263 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); 266 .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db)));
264 let detail = match variant.kind(ctx.db) { 267 let variant_kind = variant.kind(ctx.db);
268 let detail = match variant_kind {
265 StructKind::Tuple | StructKind::Unit => detail_types 269 StructKind::Tuple | StructKind::Unit => detail_types
266 .map(|(_, t)| t.display(ctx.db).to_string()) 270 .map(|(_, t)| t.display(ctx.db).to_string())
267 .sep_by(", ") 271 .sep_by(", ")
@@ -273,22 +277,42 @@ impl Completions {
273 .surround_with("{ ", " }") 277 .surround_with("{ ", " }")
274 .to_string(), 278 .to_string(),
275 }; 279 };
276 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 280 let mut res =
277 .kind(CompletionItemKind::EnumVariant) 281 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
278 .set_documentation(variant.docs(ctx.db)) 282 .kind(CompletionItemKind::EnumVariant)
279 .set_deprecated(is_deprecated) 283 .set_documentation(variant.docs(ctx.db))
280 .detail(detail) 284 .set_deprecated(is_deprecated)
281 .add_to(self); 285 .detail(detail);
286
287 if variant_kind == StructKind::Tuple {
288 let params = Params::Anonymous(variant.fields(ctx.db).len());
289 res = res.add_call_parens(ctx, name, params)
290 }
291
292 res.add_to(self);
293 }
294}
295
296enum Params {
297 Named(Vec<String>),
298 Anonymous(usize),
299}
300
301impl Params {
302 fn len(&self) -> usize {
303 match self {
304 Params::Named(xs) => xs.len(),
305 Params::Anonymous(len) => *len,
306 }
307 }
308
309 fn is_empty(&self) -> bool {
310 self.len() == 0
282 } 311 }
283} 312}
284 313
285impl Builder { 314impl Builder {
286 fn add_call_parens( 315 fn add_call_parens(mut self, ctx: &CompletionContext, name: String, params: Params) -> Builder {
287 mut self,
288 ctx: &CompletionContext,
289 name: String,
290 params: Vec<String>,
291 ) -> Builder {
292 if !ctx.config.add_call_parenthesis { 316 if !ctx.config.add_call_parenthesis {
293 return self; 317 return self;
294 } 318 }
@@ -302,15 +326,16 @@ impl Builder {
302 (format!("{}()$0", name), format!("{}()", name)) 326 (format!("{}()$0", name), format!("{}()", name))
303 } else { 327 } else {
304 self = self.trigger_call_info(); 328 self = self.trigger_call_info();
305 let snippet = if ctx.config.add_call_argument_snippets { 329 let snippet = match (ctx.config.add_call_argument_snippets, params) {
306 let function_params_snippet = params 330 (true, Params::Named(params)) => {
307 .iter() 331 let function_params_snippet = params
308 .enumerate() 332 .iter()
309 .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name)) 333 .enumerate()
310 .sep_by(", "); 334 .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name))
311 format!("{}({})$0", name, function_params_snippet) 335 .sep_by(", ");
312 } else { 336 format!("{}({})$0", name, function_params_snippet)
313 format!("{}($0)", name) 337 }
338 _ => format!("{}($0)", name),
314 }; 339 };
315 340
316 (snippet, format!("{}(…)", name)) 341 (snippet, format!("{}(…)", name))
@@ -385,12 +410,14 @@ mod tests {
385 @r###" 410 @r###"
386 [ 411 [
387 CompletionItem { 412 CompletionItem {
388 label: "Foo", 413 label: "Foo(…)",
389 source_range: [115; 117), 414 source_range: [115; 117),
390 delete: [115; 117), 415 delete: [115; 117),
391 insert: "Foo", 416 insert: "Foo($0)",
392 kind: EnumVariant, 417 kind: EnumVariant,
418 lookup: "Foo",
393 detail: "(i32, i32)", 419 detail: "(i32, i32)",
420 trigger_call_info: true,
394 }, 421 },
395 ]"### 422 ]"###
396 ); 423 );
@@ -565,6 +592,101 @@ mod tests {
565 } 592 }
566 593
567 #[test] 594 #[test]
595 fn inserts_parens_for_tuple_enums() {
596 assert_debug_snapshot!(
597 do_reference_completion(
598 r"
599 enum Option<T> { Some(T), None }
600 use Option::*;
601 fn main() -> Option<i32> {
602 Som<|>
603 }
604 "
605 ),
606 @r###"
607 [
608 CompletionItem {
609 label: "None",
610 source_range: [144; 147),
611 delete: [144; 147),
612 insert: "None",
613 kind: EnumVariant,
614 detail: "()",
615 },
616 CompletionItem {
617 label: "Option",
618 source_range: [144; 147),
619 delete: [144; 147),
620 insert: "Option",
621 kind: Enum,
622 },
623 CompletionItem {
624 label: "Some(…)",
625 source_range: [144; 147),
626 delete: [144; 147),
627 insert: "Some($0)",
628 kind: EnumVariant,
629 lookup: "Some",
630 detail: "(T)",
631 trigger_call_info: true,
632 },
633 CompletionItem {
634 label: "main()",
635 source_range: [144; 147),
636 delete: [144; 147),
637 insert: "main()$0",
638 kind: Function,
639 lookup: "main",
640 detail: "fn main() -> Option<i32>",
641 },
642 ]
643 "###
644 );
645 assert_debug_snapshot!(
646 do_reference_completion(
647 r"
648 enum Option<T> { Some(T), None }
649 use Option::*;
650 fn main(value: Option<i32>) {
651 match value {
652 Som<|>
653 }
654 }
655 "
656 ),
657 @r###"
658 [
659 CompletionItem {
660 label: "None",
661 source_range: [185; 188),
662 delete: [185; 188),
663 insert: "None",
664 kind: EnumVariant,
665 detail: "()",
666 },
667 CompletionItem {
668 label: "Option",
669 source_range: [185; 188),
670 delete: [185; 188),
671 insert: "Option",
672 kind: Enum,
673 },
674 CompletionItem {
675 label: "Some(…)",
676 source_range: [185; 188),
677 delete: [185; 188),
678 insert: "Some($0)",
679 kind: EnumVariant,
680 lookup: "Some",
681 detail: "(T)",
682 trigger_call_info: true,
683 },
684 ]
685 "###
686 );
687 }
688
689 #[test]
568 fn arg_snippets_for_method_call() { 690 fn arg_snippets_for_method_call() {
569 assert_debug_snapshot!( 691 assert_debug_snapshot!(
570 do_reference_completion( 692 do_reference_completion(