Skip to content

Commit d6a708b

Browse files
bors[bot]matklad
andauthored
Merge #7281
7281: Insert `;` when completing keywords in let r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents 054e206 + f2ba204 commit d6a708b

File tree

2 files changed

+89
-35
lines changed

2 files changed

+89
-35
lines changed

crates/completion/src/completions/keyword.rs

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Completes keywords.
22
3-
use syntax::{ast, SyntaxKind};
3+
use syntax::SyntaxKind;
44
use test_utils::mark;
55

66
use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
@@ -86,8 +86,8 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
8686
add_keyword(ctx, acc, "match", "match $0 {}");
8787
add_keyword(ctx, acc, "while", "while $0 {}");
8888
add_keyword(ctx, acc, "loop", "loop {$0}");
89-
add_keyword(ctx, acc, "if", "if ");
90-
add_keyword(ctx, acc, "if let", "if let ");
89+
add_keyword(ctx, acc, "if", "if $0 {}");
90+
add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
9191
}
9292

9393
if ctx.if_is_prev || ctx.block_expr_parent {
@@ -143,47 +143,49 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
143143
Some(it) => it,
144144
None => return,
145145
};
146-
acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
147-
}
148-
149-
fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
150-
let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
151-
.kind(CompletionItemKind::Keyword);
152146

153-
match ctx.config.snippet_cap {
154-
Some(cap) => res.insert_snippet(cap, snippet),
155-
_ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
156-
}
157-
.build()
147+
add_keyword(
148+
ctx,
149+
acc,
150+
"return",
151+
match (ctx.can_be_stmt, fn_def.ret_type().is_some()) {
152+
(true, true) => "return $0;",
153+
(true, false) => "return;",
154+
(false, true) => "return $0",
155+
(false, false) => "return",
156+
},
157+
)
158158
}
159159

160160
fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
161-
acc.add(keyword(ctx, kw, snippet));
162-
}
163-
164-
fn complete_return(
165-
ctx: &CompletionContext,
166-
fn_def: &ast::Fn,
167-
can_be_stmt: bool,
168-
) -> Option<CompletionItem> {
169-
let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
170-
(true, true) => "return $0;",
171-
(true, false) => "return;",
172-
(false, true) => "return $0",
173-
(false, false) => "return",
161+
let builder = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
162+
.kind(CompletionItemKind::Keyword);
163+
let builder = match ctx.config.snippet_cap {
164+
Some(cap) => {
165+
let tmp;
166+
let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
167+
mark::hit!(let_semi);
168+
tmp = format!("{};", snippet);
169+
&tmp
170+
} else {
171+
snippet
172+
};
173+
builder.insert_snippet(cap, snippet)
174+
}
175+
None => builder.insert_text(if snippet.contains('$') { kw } else { snippet }),
174176
};
175-
Some(keyword(ctx, "return", snip))
177+
acc.add(builder.build());
176178
}
177179

178180
#[cfg(test)]
179181
mod tests {
180182
use expect_test::{expect, Expect};
183+
use test_utils::mark;
181184

182185
use crate::{
183186
test_utils::{check_edit, completion_list},
184187
CompletionKind,
185188
};
186-
use test_utils::mark;
187189

188190
fn check(ra_fixture: &str, expect: Expect) {
189191
let actual = completion_list(ra_fixture, CompletionKind::Keyword);
@@ -609,4 +611,50 @@ fn foo() {
609611
"#]],
610612
);
611613
}
614+
615+
#[test]
616+
fn let_semi() {
617+
mark::check!(let_semi);
618+
check_edit(
619+
"match",
620+
r#"
621+
fn main() { let x = $0 }
622+
"#,
623+
r#"
624+
fn main() { let x = match $0 {}; }
625+
"#,
626+
);
627+
628+
check_edit(
629+
"if",
630+
r#"
631+
fn main() {
632+
let x = $0
633+
let y = 92;
634+
}
635+
"#,
636+
r#"
637+
fn main() {
638+
let x = if $0 {};
639+
let y = 92;
640+
}
641+
"#,
642+
);
643+
644+
check_edit(
645+
"loop",
646+
r#"
647+
fn main() {
648+
let x = $0
649+
bar();
650+
}
651+
"#,
652+
r#"
653+
fn main() {
654+
let x = loop {$0};
655+
bar();
656+
}
657+
"#,
658+
);
659+
}
612660
}

crates/completion/src/context.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub(crate) struct CompletionContext<'a> {
9292
pub(super) has_item_list_or_source_file_parent: bool,
9393
pub(super) for_is_prev2: bool,
9494
pub(super) fn_is_prev: bool,
95+
pub(super) incomplete_let: bool,
9596
pub(super) locals: Vec<(String, Local)>,
9697
}
9798

@@ -132,9 +133,9 @@ impl<'a> CompletionContext<'a> {
132133
scope,
133134
db,
134135
config,
136+
position,
135137
original_token,
136138
token,
137-
position,
138139
krate,
139140
expected_type: None,
140141
name_ref_syntax: None,
@@ -155,30 +156,31 @@ impl<'a> CompletionContext<'a> {
155156
is_expr: false,
156157
is_new_item: false,
157158
dot_receiver: None,
159+
dot_receiver_is_ambiguous_float_literal: false,
158160
is_call: false,
159161
is_pattern_call: false,
160162
is_macro_call: false,
161163
is_path_type: false,
162164
has_type_args: false,
163-
dot_receiver_is_ambiguous_float_literal: false,
164165
attribute_under_caret: None,
165166
mod_declaration_under_caret: None,
166167
unsafe_is_prev: false,
167-
in_loop_body: false,
168-
ref_pat_parent: false,
169-
bind_pat_parent: false,
168+
if_is_prev: false,
170169
block_expr_parent: false,
170+
bind_pat_parent: false,
171+
ref_pat_parent: false,
172+
in_loop_body: false,
171173
has_trait_parent: false,
172174
has_impl_parent: false,
173175
inside_impl_trait_block: false,
174176
has_field_list_parent: false,
175177
trait_as_prev_sibling: false,
176178
impl_as_prev_sibling: false,
177-
if_is_prev: false,
178179
is_match_arm: false,
179180
has_item_list_or_source_file_parent: false,
180181
for_is_prev2: false,
181182
fn_is_prev: false,
183+
incomplete_let: false,
182184
locals,
183185
};
184186

@@ -270,6 +272,10 @@ impl<'a> CompletionContext<'a> {
270272
.filter(|module| module.item_list().is_none());
271273
self.for_is_prev2 = for_is_prev2(syntax_element.clone());
272274
self.fn_is_prev = fn_is_prev(syntax_element.clone());
275+
self.incomplete_let =
276+
syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
277+
it.syntax().text_range().end() == syntax_element.text_range().end()
278+
});
273279
}
274280

275281
fn fill(

0 commit comments

Comments
 (0)