From b2abe1bca187929949ad4155c34ebd0308880fa4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 10 May 2022 15:00:58 +0200 Subject: [PATCH] Move keyword expressions to expr completions module --- crates/ide-completion/src/completions/expr.rs | 78 ++++++++++++++++--- .../src/completions/fn_param.rs | 1 + .../ide-completion/src/completions/keyword.rs | 73 +---------------- .../src/completions/trait_impl.rs | 1 + crates/ide-completion/src/completions/vis.rs | 2 +- crates/ide-completion/src/context.rs | 15 ++-- crates/ide-completion/src/lib.rs | 2 +- crates/ide-completion/src/tests/record.rs | 11 --- 8 files changed, 84 insertions(+), 99 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index a2a17d92185..87fae18f4cd 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -2,6 +2,7 @@ use hir::ScopeDef; use ide_db::FxHashSet; +use syntax::T; use crate::{ context::{PathCompletionCtx, PathKind, PathQualifierCtx}, @@ -14,15 +15,16 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext) return; } - let (&is_absolute_path, qualifier) = match ctx.path_context() { - Some(PathCompletionCtx { - kind: PathKind::Expr { .. }, - is_absolute_path, - qualifier, - .. - }) => (is_absolute_path, qualifier), - _ => return, - }; + let (is_absolute_path, qualifier, in_block_expr, in_loop_body, in_functional_update) = + match ctx.path_context() { + Some(&PathCompletionCtx { + kind: PathKind::Expr { in_block_expr, in_loop_body, in_functional_update }, + is_absolute_path, + ref qualifier, + .. + }) => (is_absolute_path, qualifier, in_block_expr, in_loop_body, in_functional_update), + _ => return, + }; let scope_def_applicable = |def| { use hir::{GenericParam::*, ModuleDef::*}; @@ -162,6 +164,64 @@ pub(crate) fn complete_expr_path(acc: &mut Completions, ctx: &CompletionContext) acc.add_resolution(ctx, name, def); } }); + + if !in_functional_update { + let mut add_keyword = + |kw, snippet| super::keyword::add_keyword(acc, ctx, kw, snippet); + + if ctx.expects_expression() { + if !in_block_expr { + add_keyword("unsafe", "unsafe {\n $0\n}"); + } + add_keyword("match", "match $1 {\n $0\n}"); + add_keyword("while", "while $1 {\n $0\n}"); + add_keyword("while let", "while let $1 = $2 {\n $0\n}"); + add_keyword("loop", "loop {\n $0\n}"); + add_keyword("if", "if $1 {\n $0\n}"); + add_keyword("if let", "if let $1 = $2 {\n $0\n}"); + add_keyword("for", "for $1 in $2 {\n $0\n}"); + add_keyword("true", "true"); + add_keyword("false", "false"); + } + + if ctx.previous_token_is(T![if]) + || ctx.previous_token_is(T![while]) + || in_block_expr + { + add_keyword("let", "let"); + } + + if ctx.after_if() { + add_keyword("else", "else {\n $0\n}"); + add_keyword("else if", "else if $1 {\n $0\n}"); + } + + if ctx.expects_ident_ref_expr() { + add_keyword("mut", "mut "); + } + + if in_loop_body { + if in_block_expr { + add_keyword("continue", "continue;"); + add_keyword("break", "break;"); + } else { + add_keyword("continue", "continue"); + add_keyword("break", "break"); + } + } + + if let Some(fn_def) = &ctx.function_def { + add_keyword( + "return", + match (in_block_expr, fn_def.ret_type().is_some()) { + (true, true) => "return ;", + (true, false) => "return;", + (false, true) => "return $0", + (false, false) => "return", + }, + ); + } + } } } } diff --git a/crates/ide-completion/src/completions/fn_param.rs b/crates/ide-completion/src/completions/fn_param.rs index 47cead7d570..0cdb8ee1190 100644 --- a/crates/ide-completion/src/completions/fn_param.rs +++ b/crates/ide-completion/src/completions/fn_param.rs @@ -13,6 +13,7 @@ use crate::{ CompletionContext, CompletionItem, CompletionItemKind, Completions, }; +// FIXME: Make this a submodule of [`pattern`] /// Complete repeated parameters, both name and type. For example, if all /// functions in a file have a `spam: &mut Spam` parameter, a completion with /// `spam: &mut Spam` insert text/label will be suggested. diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs index b34545414ec..14211f86baa 100644 --- a/crates/ide-completion/src/completions/keyword.rs +++ b/crates/ide-completion/src/completions/keyword.rs @@ -5,9 +5,8 @@ use syntax::T; use crate::{ - context::{PathCompletionCtx, PathKind}, - patterns::ImmediateLocation, - CompletionContext, CompletionItem, CompletionItemKind, Completions, + context::PathKind, patterns::ImmediateLocation, CompletionContext, CompletionItem, + CompletionItemKind, Completions, }; pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { @@ -83,75 +82,9 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte add_keyword("struct", "struct $0"); add_keyword("union", "union $1 {\n $0\n}"); } - - if ctx.expects_type() { - return; - } - - if ctx.expects_expression() { - if !has_block_expr_parent { - add_keyword("unsafe", "unsafe {\n $0\n}"); - } - add_keyword("match", "match $1 {\n $0\n}"); - add_keyword("while", "while $1 {\n $0\n}"); - add_keyword("while let", "while let $1 = $2 {\n $0\n}"); - add_keyword("loop", "loop {\n $0\n}"); - add_keyword("if", "if $1 {\n $0\n}"); - add_keyword("if let", "if let $1 = $2 {\n $0\n}"); - add_keyword("for", "for $1 in $2 {\n $0\n}"); - add_keyword("true", "true"); - add_keyword("false", "false"); - } - - if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent { - add_keyword("let", "let"); - } - - if ctx.after_if() { - add_keyword("else", "else {\n $0\n}"); - add_keyword("else if", "else if $1 {\n $0\n}"); - } - - if ctx.expects_ident_ref_expr() { - add_keyword("mut", "mut "); - } - - let (can_be_stmt, in_loop_body) = match ctx.path_context() { - Some(&PathCompletionCtx { - is_absolute_path: false, - kind: PathKind::Expr { in_block_expr, in_loop_body, .. }, - .. - }) => (in_block_expr, in_loop_body), - _ => return, - }; - - if in_loop_body { - if can_be_stmt { - add_keyword("continue", "continue;"); - add_keyword("break", "break;"); - } else { - add_keyword("continue", "continue"); - add_keyword("break", "break"); - } - } - - let fn_def = match &ctx.function_def { - Some(it) => it, - None => return, - }; - - add_keyword( - "return", - match (can_be_stmt, fn_def.ret_type().is_some()) { - (true, true) => "return $0;", - (true, false) => "return;", - (false, true) => "return $0", - (false, false) => "return", - }, - ) } -fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) { +pub(super) fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) { let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); match ctx.config.snippet_cap { diff --git a/crates/ide-completion/src/completions/trait_impl.rs b/crates/ide-completion/src/completions/trait_impl.rs index e3c15038d07..61c5d126493 100644 --- a/crates/ide-completion/src/completions/trait_impl.rs +++ b/crates/ide-completion/src/completions/trait_impl.rs @@ -52,6 +52,7 @@ enum ImplCompletionKind { Const, } +// FIXME: Make this a submodule of [`item_list`] pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { if let Some((kind, replacement_range, impl_def)) = completion_match(ctx) { if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs index b5e86b62d1a..d538f1879e7 100644 --- a/crates/ide-completion/src/completions/vis.rs +++ b/crates/ide-completion/src/completions/vis.rs @@ -7,7 +7,7 @@ use crate::{ Completions, }; -pub(crate) fn complete_vis(acc: &mut Completions, ctx: &CompletionContext) { +pub(crate) fn complete_vis_path(acc: &mut Completions, ctx: &CompletionContext) { let (&is_absolute_path, qualifier, &has_in_token) = match ctx.path_context() { Some(PathCompletionCtx { kind: PathKind::Vis { has_in_token }, diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index f6b8962df63..4a058ac2619 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -48,6 +48,7 @@ pub(super) enum PathKind { Expr { in_block_expr: bool, in_loop_body: bool, + in_functional_update: bool, }, Type, Attr { @@ -392,10 +393,6 @@ impl<'a> CompletionContext<'a> { matches!(self.path_context(), Some(PathCompletionCtx { kind: PathKind::Expr { .. }, .. })) } - pub(crate) fn expects_type(&self) -> bool { - matches!(self.path_context(), Some(PathCompletionCtx { kind: PathKind::Type, .. })) - } - pub(crate) fn is_non_trivial_path(&self) -> bool { matches!( self.path_context(), @@ -1104,6 +1101,9 @@ impl<'a> CompletionContext<'a> { }) .unwrap_or(false) }; + let is_in_func_update = |it: &SyntaxNode| { + it.parent().map_or(false, |it| ast::RecordExprFieldList::can_cast(it.kind())) + }; let kind = path.syntax().ancestors().find_map(|it| { // using Option> as extra controlflow @@ -1114,8 +1114,8 @@ impl<'a> CompletionContext<'a> { path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind())); let in_block_expr = is_in_block(it.syntax()); let in_loop_body = is_in_loop_body(it.syntax()); - - Some(PathKind::Expr { in_block_expr, in_loop_body }) + let in_functional_update = is_in_func_update(it.syntax()); + Some(PathKind::Expr { in_block_expr, in_loop_body, in_functional_update }) }, ast::TupleStructPat(it) => { path_ctx.has_call_parens = true; @@ -1149,7 +1149,8 @@ impl<'a> CompletionContext<'a> { return Some(parent.and_then(ast::MacroExpr::cast).map(|it| { let in_loop_body = is_in_loop_body(it.syntax()); let in_block_expr = is_in_block(it.syntax()); - PathKind::Expr { in_block_expr, in_loop_body } + let in_functional_update = is_in_func_update(it.syntax()); + PathKind::Expr { in_block_expr, in_loop_body, in_functional_update } })); }, } diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 6695fcdc192..7789c967070 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -173,7 +173,7 @@ pub fn completions( completions::r#type::complete_type_path(acc, ctx); completions::r#type::complete_inferred_type(acc, ctx); completions::use_::complete_use_tree(acc, ctx); - completions::vis::complete_vis(acc, ctx); + completions::vis::complete_vis_path(acc, ctx); } Some(acc) diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs index a0f8b248672..2c497617484 100644 --- a/crates/ide-completion/src/tests/record.rs +++ b/crates/ide-completion/src/tests/record.rs @@ -168,19 +168,8 @@ fn main() { tt Sized bt u32 kw crate:: - kw false - kw for - kw if - kw if let - kw loop - kw match - kw return kw self:: kw super:: - kw true - kw unsafe - kw while - kw while let "#]], ); check(