aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/render/pattern.rs
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-12-20 17:19:23 +0000
committerLukas Wirth <[email protected]>2020-12-20 17:19:23 +0000
commitb184bfad7a2dc6a9bf6654a7eec6c68a27c49f70 (patch)
treea9d35d8053e13d22561156c760e0996323040169 /crates/completion/src/render/pattern.rs
parentf3125555a8de6fad4529408436800a6b1243a442 (diff)
Add completions for patterns
Diffstat (limited to 'crates/completion/src/render/pattern.rs')
-rw-r--r--crates/completion/src/render/pattern.rs128
1 files changed, 128 insertions, 0 deletions
diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs
new file mode 100644
index 000000000..e20b0027b
--- /dev/null
+++ b/crates/completion/src/render/pattern.rs
@@ -0,0 +1,128 @@
1//! Renderer for patterns.
2
3use hir::{db::HirDatabase, HasVisibility, Name, StructKind};
4use itertools::Itertools;
5
6use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind};
7
8pub(crate) fn render_struct_pat<'a>(
9 ctx: RenderContext<'a>,
10 strukt: hir::Struct,
11 local_name: Option<Name>,
12) -> Option<CompletionItem> {
13 let _p = profile::span("render_struct_pat");
14
15 let module = ctx.completion.scope.module()?;
16 let fields = strukt.fields(ctx.db());
17 let n_fields = fields.len();
18 let fields = fields
19 .into_iter()
20 .filter(|field| field.is_visible_from(ctx.db(), module))
21 .collect::<Vec<_>>();
22
23 if fields.is_empty() {
24 // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields
25 return None;
26 }
27 let fields_omitted = n_fields - fields.len() > 0;
28
29 let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string();
30 let mut pat = match strukt.kind(ctx.db()) {
31 StructKind::Tuple if ctx.snippet_cap().is_some() => {
32 render_tuple_as_pat(&fields, &name, fields_omitted)
33 }
34 StructKind::Record => render_record_as_pat(ctx.db(), &fields, &name, fields_omitted),
35 _ => return None,
36 };
37
38 if ctx.completion.is_param {
39 pat.push(':');
40 pat.push(' ');
41 pat.push_str(&name);
42 }
43 if ctx.snippet_cap().is_some() {
44 pat.push_str("$0");
45 }
46
47 let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name)
48 .kind(CompletionItemKind::Binding)
49 .set_documentation(ctx.docs(strukt))
50 .set_deprecated(ctx.is_deprecated(strukt))
51 .detail(&pat);
52 if let Some(snippet_cap) = ctx.snippet_cap() {
53 completion = completion.insert_snippet(snippet_cap, pat);
54 } else {
55 completion = completion.insert_text(pat);
56 }
57 Some(completion.build())
58}
59
60pub(crate) fn render_variant_pat<'a>(
61 ctx: RenderContext<'a>,
62 variant: hir::Variant,
63 local_name: Option<Name>,
64) -> Option<CompletionItem> {
65 let _p = profile::span("render_variant_pat");
66
67 let module = ctx.completion.scope.module()?;
68 let fields = variant.fields(ctx.db());
69 let n_fields = fields.len();
70 let fields = fields
71 .into_iter()
72 .filter(|field| field.is_visible_from(ctx.db(), module))
73 .collect::<Vec<_>>();
74
75 let fields_omitted = n_fields - fields.len() > 0;
76
77 let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string();
78 let mut pat = match variant.kind(ctx.db()) {
79 StructKind::Tuple if ctx.snippet_cap().is_some() => {
80 render_tuple_as_pat(&fields, &name, fields_omitted)
81 }
82 StructKind::Record => render_record_as_pat(ctx.db(), &fields, &name, fields_omitted),
83 _ => return None,
84 };
85
86 if ctx.completion.is_param {
87 pat.push(':');
88 pat.push(' ');
89 pat.push_str(&name);
90 }
91 if ctx.snippet_cap().is_some() {
92 pat.push_str("$0");
93 }
94 let mut completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name)
95 .kind(CompletionItemKind::Binding)
96 .set_documentation(ctx.docs(variant))
97 .set_deprecated(ctx.is_deprecated(variant))
98 .detail(&pat);
99 if let Some(snippet_cap) = ctx.snippet_cap() {
100 completion = completion.insert_snippet(snippet_cap, pat);
101 } else {
102 completion = completion.insert_text(pat);
103 }
104 Some(completion.build())
105}
106
107fn render_record_as_pat(
108 db: &dyn HirDatabase,
109 fields: &[hir::Field],
110 name: &str,
111 fields_omitted: bool,
112) -> String {
113 format!(
114 "{name} {{ {}{} }}",
115 fields.into_iter().map(|field| field.name(db)).format(", "),
116 if fields_omitted { ", .." } else { "" },
117 name = name
118 )
119}
120
121fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String {
122 format!(
123 "{name}({}{})",
124 fields.into_iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "),
125 if fields_omitted { ", .." } else { "" },
126 name = name
127 )
128}