aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/render/enum_variant.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-11-03 07:54:45 +0000
committerGitHub <[email protected]>2020-11-03 07:54:45 +0000
commit07c7f35effe1a4602ba02baf9ff67a4eb214818f (patch)
tree1cf4253dc23366dfd20f36285036d73b168a526e /crates/completion/src/render/enum_variant.rs
parent658e97a39e77bcb978697a66ddccd7e4b58990cf (diff)
parent8efe43245bc64ed27f88c333541b2cb7af2ce44c (diff)
Merge #6430
6430: Move completions rendering into a separate module r=popzxc a=popzxc This PR extracts rendering-related things from `Completions` structure to the new `render` module. `render` module declares a `Render` structure (which is a generic renderer interface), `RenderContext` (interface for data/methods not required for completions generating, but required for rendering), and a bunch of smaller `*Render` structures which encapsulate logic behind rendering a certain item. This is just a step in full separation direction, since the following this are still to be done: - Move some data from `CompletionContext` to the `RenderContext`; - Forbid any kind of rendering outside of `render` module; - Extract score computing into a separate module. This PR is already pretty big, so not to make it even harder to review I decided to split this process into several subsequent PRs. Co-authored-by: Igor Aleksanov <[email protected]>
Diffstat (limited to 'crates/completion/src/render/enum_variant.rs')
-rw-r--r--crates/completion/src/render/enum_variant.rs180
1 files changed, 180 insertions, 0 deletions
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
new file mode 100644
index 000000000..fd412ed0e
--- /dev/null
+++ b/crates/completion/src/render/enum_variant.rs
@@ -0,0 +1,180 @@
1//! Renderer for `enum` variants.
2
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use itertools::Itertools;
5use test_utils::mark;
6
7use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind},
9 render::{builder_ext::Params, RenderContext},
10};
11
12pub(crate) fn render_enum_variant<'a>(
13 ctx: RenderContext<'a>,
14 local_name: Option<String>,
15 variant: hir::EnumVariant,
16 path: Option<ModPath>,
17) -> CompletionItem {
18 EnumVariantRender::new(ctx, local_name, variant, path).render()
19}
20
21#[derive(Debug)]
22struct EnumVariantRender<'a> {
23 ctx: RenderContext<'a>,
24 name: String,
25 variant: hir::EnumVariant,
26 path: Option<ModPath>,
27 qualified_name: String,
28 short_qualified_name: String,
29 variant_kind: StructKind,
30}
31
32impl<'a> EnumVariantRender<'a> {
33 fn new(
34 ctx: RenderContext<'a>,
35 local_name: Option<String>,
36 variant: hir::EnumVariant,
37 path: Option<ModPath>,
38 ) -> EnumVariantRender<'a> {
39 let name = local_name.unwrap_or_else(|| variant.name(ctx.db()).to_string());
40 let variant_kind = variant.kind(ctx.db());
41
42 let (qualified_name, short_qualified_name) = match &path {
43 Some(path) => {
44 let full = path.to_string();
45 let short =
46 path.segments[path.segments.len().saturating_sub(2)..].iter().join("::");
47 (full, short)
48 }
49 None => (name.to_string(), name.to_string()),
50 };
51
52 EnumVariantRender {
53 ctx,
54 name,
55 variant,
56 path,
57 qualified_name,
58 short_qualified_name,
59 variant_kind,
60 }
61 }
62
63 fn render(self) -> CompletionItem {
64 let mut builder = CompletionItem::new(
65 CompletionKind::Reference,
66 self.ctx.source_range(),
67 self.qualified_name.clone(),
68 )
69 .kind(CompletionItemKind::EnumVariant)
70 .set_documentation(self.variant.docs(self.ctx.db()))
71 .set_deprecated(self.ctx.is_deprecated(self.variant))
72 .detail(self.detail());
73
74 if self.variant_kind == StructKind::Tuple {
75 mark::hit!(inserts_parens_for_tuple_enums);
76 let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len());
77 builder =
78 builder.add_call_parens(self.ctx.completion, self.short_qualified_name, params);
79 } else if self.path.is_some() {
80 builder = builder.lookup_by(self.short_qualified_name);
81 }
82
83 builder.build()
84 }
85
86 fn detail(&self) -> String {
87 let detail_types = self
88 .variant
89 .fields(self.ctx.db())
90 .into_iter()
91 .map(|field| (field.name(self.ctx.db()), field.signature_ty(self.ctx.db())));
92
93 match self.variant_kind {
94 StructKind::Tuple | StructKind::Unit => format!(
95 "({})",
96 detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ")
97 ),
98 StructKind::Record => format!(
99 "{{ {} }}",
100 detail_types
101 .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string()))
102 .format(", ")
103 ),
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use test_utils::mark;
111
112 use crate::test_utils::check_edit;
113
114 #[test]
115 fn inserts_parens_for_tuple_enums() {
116 mark::check!(inserts_parens_for_tuple_enums);
117 check_edit(
118 "Some",
119 r#"
120enum Option<T> { Some(T), None }
121use Option::*;
122fn main() -> Option<i32> {
123 Som<|>
124}
125"#,
126 r#"
127enum Option<T> { Some(T), None }
128use Option::*;
129fn main() -> Option<i32> {
130 Some($0)
131}
132"#,
133 );
134 check_edit(
135 "Some",
136 r#"
137enum Option<T> { Some(T), None }
138use Option::*;
139fn main(value: Option<i32>) {
140 match value {
141 Som<|>
142 }
143}
144"#,
145 r#"
146enum Option<T> { Some(T), None }
147use Option::*;
148fn main(value: Option<i32>) {
149 match value {
150 Some($0)
151 }
152}
153"#,
154 );
155 }
156
157 #[test]
158 fn dont_duplicate_pattern_parens() {
159 mark::check!(dont_duplicate_pattern_parens);
160 check_edit(
161 "Var",
162 r#"
163enum E { Var(i32) }
164fn main() {
165 match E::Var(92) {
166 E::<|>(92) => (),
167 }
168}
169"#,
170 r#"
171enum E { Var(i32) }
172fn main() {
173 match E::Var(92) {
174 E::Var(92) => (),
175 }
176}
177"#,
178 );
179 }
180}