From cbe67339df2bbcb17e12ad74e8b8cd53baffb9f7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 21 Dec 2018 20:55:00 +0300 Subject: more completion components --- .../ra_analysis/src/completion/complete_keyword.rs | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 crates/ra_analysis/src/completion/complete_keyword.rs (limited to 'crates/ra_analysis/src/completion/complete_keyword.rs') 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 @@ +use ra_syntax::{ + algo::visit::{visitor, Visitor}, + AstNode, + ast::{self, LoopBodyOwner}, + SyntaxKind::*, SyntaxNodeRef, +}; + +use crate::{ + completion::{SyntaxContext, CompletionItem, Completions, CompletionKind::*}, +}; + +pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &SyntaxContext) { + if !ctx.is_trivial_path { + return; + } + let fn_def = match ctx.enclosing_fn { + Some(it) => it, + None => return, + }; + acc.add(keyword("if", "if $0 {}")); + acc.add(keyword("match", "match $0 {}")); + acc.add(keyword("while", "while $0 {}")); + acc.add(keyword("loop", "loop {$0}")); + + if ctx.after_if { + acc.add(keyword("else", "else {$0}")); + acc.add(keyword("else if", "else if $0 {}")); + } + if is_in_loop_body(ctx.leaf) { + acc.add(keyword("continue", "continue")); + acc.add(keyword("break", "break")); + } + acc.add_all(complete_return(fn_def, ctx.is_stmt)); +} + +fn is_in_loop_body(leaf: SyntaxNodeRef) -> bool { + for node in leaf.ancestors() { + if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { + break; + } + let loop_body = visitor() + .visit::(LoopBodyOwner::loop_body) + .visit::(LoopBodyOwner::loop_body) + .visit::(LoopBodyOwner::loop_body) + .accept(node); + if let Some(Some(body)) = loop_body { + if leaf.range().is_subrange(&body.syntax().range()) { + return true; + } + } + } + false +} + +fn complete_return(fn_def: ast::FnDef, is_stmt: bool) -> Option { + let snip = match (is_stmt, fn_def.ret_type().is_some()) { + (true, true) => "return $0;", + (true, false) => "return;", + (false, true) => "return $0", + (false, false) => "return", + }; + Some(keyword("return", snip)) +} + +fn keyword(kw: &str, snippet: &str) -> CompletionItem { + CompletionItem::new(kw) + .kind(Keyword) + .snippet(snippet) + .build() +} + +#[cfg(test)] +mod tests { + use crate::completion::{CompletionKind, check_completion}; + fn check_keyword_completion(code: &str, expected_completions: &str) { + check_completion(code, expected_completions, CompletionKind::Keyword); + } + + #[test] + fn test_completion_kewords() { + check_keyword_completion( + r" + fn quux() { + <|> + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + return "return" + "#, + ); + } + + #[test] + fn test_completion_else() { + check_keyword_completion( + r" + fn quux() { + if true { + () + } <|> + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + else "else {$0}" + else if "else if $0 {}" + return "return" + "#, + ); + } + + #[test] + fn test_completion_return_value() { + check_keyword_completion( + r" + fn quux() -> i32 { + <|> + 92 + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + return "return $0;" + "#, + ); + check_keyword_completion( + r" + fn quux() { + <|> + 92 + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + return "return;" + "#, + ); + } + + #[test] + fn test_completion_return_no_stmt() { + check_keyword_completion( + r" + fn quux() -> i32 { + match () { + () => <|> + } + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + return "return $0" + "#, + ); + } + + #[test] + fn test_continue_break_completion() { + check_keyword_completion( + r" + fn quux() -> i32 { + loop { <|> } + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + continue "continue" + break "break" + return "return $0" + "#, + ); + check_keyword_completion( + r" + fn quux() -> i32 { + loop { || { <|> } } + } + ", + r#" + if "if $0 {}" + match "match $0 {}" + while "while $0 {}" + loop "loop {$0}" + return "return $0" + "#, + ); + } +} -- cgit v1.2.3 From a8e04a702827c454f5336c82262b0963df7fe484 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 22 Dec 2018 01:01:40 +0300 Subject: docs --- crates/ra_analysis/src/completion/complete_keyword.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_analysis/src/completion/complete_keyword.rs') diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs index d0a6ec19e..2ee36430e 100644 --- a/crates/ra_analysis/src/completion/complete_keyword.rs +++ b/crates/ra_analysis/src/completion/complete_keyword.rs @@ -6,10 +6,10 @@ use ra_syntax::{ }; use crate::{ - completion::{SyntaxContext, CompletionItem, Completions, CompletionKind::*}, + completion::{CompletionContext, CompletionItem, Completions, CompletionKind::*}, }; -pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &SyntaxContext) { +pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.is_trivial_path { return; } -- cgit v1.2.3 From 2ae87ffc9afe67945e2ad655c3577b589ff640ab Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 22 Dec 2018 01:02:43 +0300 Subject: cleanup --- crates/ra_analysis/src/completion/complete_keyword.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'crates/ra_analysis/src/completion/complete_keyword.rs') diff --git a/crates/ra_analysis/src/completion/complete_keyword.rs b/crates/ra_analysis/src/completion/complete_keyword.rs index 2ee36430e..dead15bb6 100644 --- a/crates/ra_analysis/src/completion/complete_keyword.rs +++ b/crates/ra_analysis/src/completion/complete_keyword.rs @@ -5,9 +5,7 @@ use ra_syntax::{ SyntaxKind::*, SyntaxNodeRef, }; -use crate::{ - completion::{CompletionContext, CompletionItem, Completions, CompletionKind::*}, -}; +use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind::*}; pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.is_trivial_path { -- cgit v1.2.3