aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/complete_postfix.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/complete_postfix.rs')
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs282
1 files changed, 282 insertions, 0 deletions
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
new file mode 100644
index 000000000..646a30c76
--- /dev/null
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -0,0 +1,282 @@
1//! FIXME: write short doc here
2
3use ra_syntax::{ast::AstNode, TextRange, TextUnit};
4use ra_text_edit::TextEdit;
5
6use crate::{
7 completion::{
8 completion_context::CompletionContext,
9 completion_item::{Builder, CompletionKind, Completions},
10 },
11 CompletionItem,
12};
13
14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
15 if ctx.db.feature_flags.get("completion.enable-postfix") == false {
16 return;
17 }
18
19 let dot_receiver = match &ctx.dot_receiver {
20 Some(it) => it,
21 None => return,
22 };
23
24 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
25 let text = dot_receiver.syntax().text();
26 let without_dot = ..text.len() - TextUnit::of_char('.');
27 text.slice(without_dot).to_string()
28 } else {
29 dot_receiver.syntax().text().to_string()
30 };
31
32 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) {
33 Some(it) => it,
34 None => return,
35 };
36
37 if receiver_ty.is_bool() || receiver_ty.is_unknown() {
38 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
39 .add_to(acc);
40 postfix_snippet(
41 ctx,
42 "while",
43 "while expr {}",
44 &format!("while {} {{\n$0\n}}", receiver_text),
45 )
46 .add_to(acc);
47 }
48
49 postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
50
51 postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
52 postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
53
54 postfix_snippet(
55 ctx,
56 "match",
57 "match expr {}",
58 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text),
59 )
60 .add_to(acc);
61
62 postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
63
64 postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
65 .add_to(acc);
66}
67
68fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
69 let edit = {
70 let receiver_range =
71 ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range();
72 let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
73 TextEdit::replace(delete_range, snippet.to_string())
74 };
75 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
76 .detail(detail)
77 .snippet_edit(edit)
78}
79
80#[cfg(test)]
81mod tests {
82 use insta::assert_debug_snapshot;
83
84 use crate::completion::{do_completion, CompletionItem, CompletionKind};
85
86 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
87 do_completion(code, CompletionKind::Postfix)
88 }
89
90 #[test]
91 fn postfix_completion_works_for_trivial_path_expression() {
92 assert_debug_snapshot!(
93 do_postfix_completion(
94 r#"
95 fn main() {
96 let bar = true;
97 bar.<|>
98 }
99 "#,
100 ),
101 @r###"
102 [
103 CompletionItem {
104 label: "box",
105 source_range: [89; 89),
106 delete: [85; 89),
107 insert: "Box::new(bar)",
108 detail: "Box::new(expr)",
109 },
110 CompletionItem {
111 label: "dbg",
112 source_range: [89; 89),
113 delete: [85; 89),
114 insert: "dbg!(bar)",
115 detail: "dbg!(expr)",
116 },
117 CompletionItem {
118 label: "if",
119 source_range: [89; 89),
120 delete: [85; 89),
121 insert: "if bar {$0}",
122 detail: "if expr {}",
123 },
124 CompletionItem {
125 label: "match",
126 source_range: [89; 89),
127 delete: [85; 89),
128 insert: "match bar {\n ${1:_} => {$0\\},\n}",
129 detail: "match expr {}",
130 },
131 CompletionItem {
132 label: "not",
133 source_range: [89; 89),
134 delete: [85; 89),
135 insert: "!bar",
136 detail: "!expr",
137 },
138 CompletionItem {
139 label: "ref",
140 source_range: [89; 89),
141 delete: [85; 89),
142 insert: "&bar",
143 detail: "&expr",
144 },
145 CompletionItem {
146 label: "refm",
147 source_range: [89; 89),
148 delete: [85; 89),
149 insert: "&mut bar",
150 detail: "&mut expr",
151 },
152 CompletionItem {
153 label: "while",
154 source_range: [89; 89),
155 delete: [85; 89),
156 insert: "while bar {\n$0\n}",
157 detail: "while expr {}",
158 },
159 ]
160 "###
161 );
162 }
163
164 #[test]
165 fn some_postfix_completions_ignored() {
166 assert_debug_snapshot!(
167 do_postfix_completion(
168 r#"
169 fn main() {
170 let bar: u8 = 12;
171 bar.<|>
172 }
173 "#,
174 ),
175 @r###"
176 [
177 CompletionItem {
178 label: "box",
179 source_range: [91; 91),
180 delete: [87; 91),
181 insert: "Box::new(bar)",
182 detail: "Box::new(expr)",
183 },
184 CompletionItem {
185 label: "dbg",
186 source_range: [91; 91),
187 delete: [87; 91),
188 insert: "dbg!(bar)",
189 detail: "dbg!(expr)",
190 },
191 CompletionItem {
192 label: "match",
193 source_range: [91; 91),
194 delete: [87; 91),
195 insert: "match bar {\n ${1:_} => {$0\\},\n}",
196 detail: "match expr {}",
197 },
198 CompletionItem {
199 label: "not",
200 source_range: [91; 91),
201 delete: [87; 91),
202 insert: "!bar",
203 detail: "!expr",
204 },
205 CompletionItem {
206 label: "ref",
207 source_range: [91; 91),
208 delete: [87; 91),
209 insert: "&bar",
210 detail: "&expr",
211 },
212 CompletionItem {
213 label: "refm",
214 source_range: [91; 91),
215 delete: [87; 91),
216 insert: "&mut bar",
217 detail: "&mut expr",
218 },
219 ]
220 "###
221 );
222 }
223
224 #[test]
225 fn postfix_completion_works_for_ambiguous_float_literal() {
226 assert_debug_snapshot!(
227 do_postfix_completion(
228 r#"
229 fn main() {
230 42.<|>
231 }
232 "#,
233 ),
234 @r###"
235 [
236 CompletionItem {
237 label: "box",
238 source_range: [52; 52),
239 delete: [49; 52),
240 insert: "Box::new(42)",
241 detail: "Box::new(expr)",
242 },
243 CompletionItem {
244 label: "dbg",
245 source_range: [52; 52),
246 delete: [49; 52),
247 insert: "dbg!(42)",
248 detail: "dbg!(expr)",
249 },
250 CompletionItem {
251 label: "match",
252 source_range: [52; 52),
253 delete: [49; 52),
254 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
255 detail: "match expr {}",
256 },
257 CompletionItem {
258 label: "not",
259 source_range: [52; 52),
260 delete: [49; 52),
261 insert: "!42",
262 detail: "!expr",
263 },
264 CompletionItem {
265 label: "ref",
266 source_range: [52; 52),
267 delete: [49; 52),
268 insert: "&42",
269 detail: "&expr",
270 },
271 CompletionItem {
272 label: "refm",
273 source_range: [52; 52),
274 delete: [49; 52),
275 insert: "&mut 42",
276 detail: "&mut expr",
277 },
278 ]
279 "###
280 );
281 }
282}