aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/completion/complete_keyword.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-12-21 17:55:00 +0000
committerAleksey Kladov <[email protected]>2018-12-21 17:55:00 +0000
commitcbe67339df2bbcb17e12ad74e8b8cd53baffb9f7 (patch)
tree633f0e84927f8747b1349ac345e606654cb7a572 /crates/ra_analysis/src/completion/complete_keyword.rs
parentc2bf174e9c3f994d83e7e72b6e15c9b26c5b31a2 (diff)
more completion components
Diffstat (limited to 'crates/ra_analysis/src/completion/complete_keyword.rs')
-rw-r--r--crates/ra_analysis/src/completion/complete_keyword.rs206
1 files changed, 206 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs
new file mode 100644
index 000000000..d0a6ec19e
--- /dev/null
+++ b/crates/ra_analysis/src/completion/complete_keyword.rs
@@ -0,0 +1,206 @@
1use ra_syntax::{
2 algo::visit::{visitor, Visitor},
3 AstNode,
4 ast::{self, LoopBodyOwner},
5 SyntaxKind::*, SyntaxNodeRef,
6};
7
8use crate::{
9 completion::{SyntaxContext, CompletionItem, Completions, CompletionKind::*},
10};
11
12pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &SyntaxContext) {
13 if !ctx.is_trivial_path {
14 return;
15 }
16 let fn_def = match ctx.enclosing_fn {
17 Some(it) => it,
18 None => return,
19 };
20 acc.add(keyword("if", "if $0 {}"));
21 acc.add(keyword("match", "match $0 {}"));
22 acc.add(keyword("while", "while $0 {}"));
23 acc.add(keyword("loop", "loop {$0}"));
24
25 if ctx.after_if {
26 acc.add(keyword("else", "else {$0}"));
27 acc.add(keyword("else if", "else if $0 {}"));
28 }
29 if is_in_loop_body(ctx.leaf) {
30 acc.add(keyword("continue", "continue"));
31 acc.add(keyword("break", "break"));
32 }
33 acc.add_all(complete_return(fn_def, ctx.is_stmt));
34}
35
36fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool {
37 for node in leaf.ancestors() {
38 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
39 break;
40 }
41 let loop_body = visitor()
42 .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body)
43 .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body)
44 .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
45 .accept(node);
46 if let Some(Some(body)) = loop_body {
47 if leaf.range().is_subrange(&body.syntax().range()) {
48 return true;
49 }
50 }
51 }
52 false
53}
54
55fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option<CompletionItem> {
56 let snip = match (is_stmt, fn_def.ret_type().is_some()) {
57 (true, true) => "return $0;",
58 (true, false) => "return;",
59 (false, true) => "return $0",
60 (false, false) => "return",
61 };
62 Some(keyword("return", snip))
63}
64
65fn keyword(kw: &str, snippet: &str) -> CompletionItem {
66 CompletionItem::new(kw)
67 .kind(Keyword)
68 .snippet(snippet)
69 .build()
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::completion::{CompletionKind, check_completion};
75 fn check_keyword_completion(code: &str, expected_completions: &str) {
76 check_completion(code, expected_completions, CompletionKind::Keyword);
77 }
78
79 #[test]
80 fn test_completion_kewords() {
81 check_keyword_completion(
82 r"
83 fn quux() {
84 <|>
85 }
86 ",
87 r#"
88 if "if $0 {}"
89 match "match $0 {}"
90 while "while $0 {}"
91 loop "loop {$0}"
92 return "return"
93 "#,
94 );
95 }
96
97 #[test]
98 fn test_completion_else() {
99 check_keyword_completion(
100 r"
101 fn quux() {
102 if true {
103 ()
104 } <|>
105 }
106 ",
107 r#"
108 if "if $0 {}"
109 match "match $0 {}"
110 while "while $0 {}"
111 loop "loop {$0}"
112 else "else {$0}"
113 else if "else if $0 {}"
114 return "return"
115 "#,
116 );
117 }
118
119 #[test]
120 fn test_completion_return_value() {
121 check_keyword_completion(
122 r"
123 fn quux() -> i32 {
124 <|>
125 92
126 }
127 ",
128 r#"
129 if "if $0 {}"
130 match "match $0 {}"
131 while "while $0 {}"
132 loop "loop {$0}"
133 return "return $0;"
134 "#,
135 );
136 check_keyword_completion(
137 r"
138 fn quux() {
139 <|>
140 92
141 }
142 ",
143 r#"
144 if "if $0 {}"
145 match "match $0 {}"
146 while "while $0 {}"
147 loop "loop {$0}"
148 return "return;"
149 "#,
150 );
151 }
152
153 #[test]
154 fn test_completion_return_no_stmt() {
155 check_keyword_completion(
156 r"
157 fn quux() -> i32 {
158 match () {
159 () => <|>
160 }
161 }
162 ",
163 r#"
164 if "if $0 {}"
165 match "match $0 {}"
166 while "while $0 {}"
167 loop "loop {$0}"
168 return "return $0"
169 "#,
170 );
171 }
172
173 #[test]
174 fn test_continue_break_completion() {
175 check_keyword_completion(
176 r"
177 fn quux() -> i32 {
178 loop { <|> }
179 }
180 ",
181 r#"
182 if "if $0 {}"
183 match "match $0 {}"
184 while "while $0 {}"
185 loop "loop {$0}"
186 continue "continue"
187 break "break"
188 return "return $0"
189 "#,
190 );
191 check_keyword_completion(
192 r"
193 fn quux() -> i32 {
194 loop { || { <|> } }
195 }
196 ",
197 r#"
198 if "if $0 {}"
199 match "match $0 {}"
200 while "while $0 {}"
201 loop "loop {$0}"
202 return "return $0"
203 "#,
204 );
205 }
206}