From bd3b2393903de2fc98a50426f36d14dc7e86d8da Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 24 Apr 2020 02:01:23 +0200 Subject: Move CompletionConfig to a separate module --- crates/ra_ide/src/completion.rs | 23 ++++------------------- crates/ra_ide/src/completion/completion_config.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 19 deletions(-) create mode 100644 crates/ra_ide/src/completion/completion_config.rs (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index 19bc4321c..f0e02180b 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -1,5 +1,6 @@ //! FIXME: write short doc here +mod completion_config; mod completion_item; mod completion_context; mod presentation; @@ -28,27 +29,11 @@ use crate::{ FilePosition, }; -pub use crate::completion::completion_item::{ - CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, +pub use crate::completion::{ + completion_config::CompletionConfig, + completion_item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat}, }; -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CompletionConfig { - pub enable_postfix_completions: bool, - pub add_call_parenthesis: bool, - pub add_call_argument_snippets: bool, -} - -impl Default for CompletionConfig { - fn default() -> Self { - CompletionConfig { - enable_postfix_completions: true, - add_call_parenthesis: true, - add_call_argument_snippets: true, - } - } -} - /// Main entry point for completion. We run completion as a two-phase process. /// /// First, we look at the position and collect a so-called `CompletionContext. diff --git a/crates/ra_ide/src/completion/completion_config.rs b/crates/ra_ide/src/completion/completion_config.rs new file mode 100644 index 000000000..c01a8f608 --- /dev/null +++ b/crates/ra_ide/src/completion/completion_config.rs @@ -0,0 +1,16 @@ +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CompletionConfig { + pub enable_postfix_completions: bool, + pub add_call_parenthesis: bool, + pub add_call_argument_snippets: bool, +} + +impl Default for CompletionConfig { + fn default() -> Self { + CompletionConfig { + enable_postfix_completions: true, + add_call_parenthesis: true, + add_call_argument_snippets: true, + } + } +} -- cgit v1.2.3 From b3050bded1e7a874da265d94dc32c4a98bc98390 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 24 Apr 2020 02:06:12 +0200 Subject: Introduce internal snippet cap --- crates/ra_ide/src/completion/completion_config.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion/completion_config.rs b/crates/ra_ide/src/completion/completion_config.rs index c01a8f608..6cf7ed6e4 100644 --- a/crates/ra_ide/src/completion/completion_config.rs +++ b/crates/ra_ide/src/completion/completion_config.rs @@ -1,8 +1,20 @@ +//! Settings for tweaking completion. +//! +//! The fun thing here is `SnippetCap` -- this type can only be created in this +//! module, and we use to statically check that we only produce snippet +//! completions if we are allowed to. + #[derive(Clone, Debug, PartialEq, Eq)] pub struct CompletionConfig { pub enable_postfix_completions: bool, pub add_call_parenthesis: bool, pub add_call_argument_snippets: bool, + pub snippet_cap: Option, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SnippetCap { + _private: (), } impl Default for CompletionConfig { @@ -11,6 +23,7 @@ impl Default for CompletionConfig { enable_postfix_completions: true, add_call_parenthesis: true, add_call_argument_snippets: true, + snippet_cap: Some(SnippetCap { _private: () }), } } } -- cgit v1.2.3 From 5fd5de4061362aa1066cb9a47aa9cb79eab38e47 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 24 Apr 2020 02:26:38 +0200 Subject: Make sure that adding a snippet requires corresponding capability --- crates/ra_ide/src/completion/complete_keyword.rs | 12 ++++-- crates/ra_ide/src/completion/complete_postfix.rs | 39 +++++++++++++++--- crates/ra_ide/src/completion/complete_snippet.rs | 26 ++++++++---- .../ra_ide/src/completion/complete_trait_impl.rs | 18 ++++++--- crates/ra_ide/src/completion/completion_item.rs | 9 ++++- crates/ra_ide/src/completion/presentation.rs | 47 +++++++++++++--------- 6 files changed, 107 insertions(+), 44 deletions(-) (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 38f9c34e7..adefb290e 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs @@ -42,10 +42,14 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC } fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem { - CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw) - .kind(CompletionItemKind::Keyword) - .insert_snippet(snippet) - .build() + let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw) + .kind(CompletionItemKind::Keyword); + + match ctx.config.snippet_cap { + Some(cap) => res.insert_snippet(cap, snippet), + _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }), + } + .build() } pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 29c2881c6..8d397b0fe 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs @@ -6,6 +6,7 @@ use ra_syntax::{ }; use ra_text_edit::TextEdit; +use super::completion_config::SnippetCap; use crate::{ completion::{ completion_context::CompletionContext, @@ -32,9 +33,15 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { None => return, }; + let cap = match ctx.config.snippet_cap { + Some(it) => it, + None => return, + }; + if receiver_ty.is_bool() || receiver_ty.is_unknown() { postfix_snippet( ctx, + cap, &dot_receiver, "if", "if expr {}", @@ -43,6 +50,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { .add_to(acc); postfix_snippet( ctx, + cap, &dot_receiver, "while", "while expr {}", @@ -52,11 +60,20 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { } // !&&&42 is a compiler error, ergo process it before considering the references - postfix_snippet(ctx, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); + postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) + .add_to(acc); - postfix_snippet(ctx, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); - postfix_snippet(ctx, &dot_receiver, "refm", "&mut expr", &format!("&mut {}", receiver_text)) + postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) .add_to(acc); + postfix_snippet( + ctx, + cap, + &dot_receiver, + "refm", + "&mut expr", + &format!("&mut {}", receiver_text), + ) + .add_to(acc); // The rest of the postfix completions create an expression that moves an argument, // so it's better to consider references now to avoid breaking the compilation @@ -66,6 +83,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { postfix_snippet( ctx, + cap, &dot_receiver, "match", "match expr {}", @@ -75,6 +93,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { postfix_snippet( ctx, + cap, &dot_receiver, "box", "Box::new(expr)", @@ -82,8 +101,15 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { ) .add_to(acc); - postfix_snippet(ctx, &dot_receiver, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)) - .add_to(acc); + postfix_snippet( + ctx, + cap, + &dot_receiver, + "dbg", + "dbg!(expr)", + &format!("dbg!({})", receiver_text), + ) + .add_to(acc); } fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { @@ -108,6 +134,7 @@ fn include_references(initial_element: &ast::Expr) -> ast::Expr { fn postfix_snippet( ctx: &CompletionContext, + cap: SnippetCap, receiver: &ast::Expr, label: &str, detail: &str, @@ -121,7 +148,7 @@ fn postfix_snippet( }; CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) .detail(detail) - .snippet_edit(edit) + .snippet_edit(cap, edit) } #[cfg(test)] diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index f731e9b9a..4bccfbfed 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs @@ -1,13 +1,13 @@ //! FIXME: write short doc here use crate::completion::{ - completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, - CompletionKind, Completions, + completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem, + CompletionItemKind, CompletionKind, Completions, }; -fn snippet(ctx: &CompletionContext, label: &str, snippet: &str) -> Builder { +fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label) - .insert_snippet(snippet) + .insert_snippet(cap, snippet) .kind(CompletionItemKind::Snippet) } @@ -15,17 +15,27 @@ pub(super) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) { return; } + let cap = match ctx.config.snippet_cap { + Some(it) => it, + None => return, + }; - snippet(ctx, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); - snippet(ctx, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); + snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); + snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); } pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) { if !ctx.is_new_item { return; } + let cap = match ctx.config.snippet_cap { + Some(it) => it, + None => return, + }; + snippet( ctx, + cap, "Test function", "\ #[test] @@ -36,8 +46,8 @@ fn ${1:feature}() { .lookup_by("tfn") .add_to(acc); - snippet(ctx, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}").add_to(acc); - snippet(ctx, "pub(crate)", "pub(crate) $0").add_to(acc); + snippet(ctx, cap, "macro_rules", "macro_rules! $1 {\n\t($2) => {\n\t\t$0\n\t};\n}").add_to(acc); + snippet(ctx, cap, "pub(crate)", "pub(crate) $0").add_to(acc); } #[cfg(test)] diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 2ec0e7ce9..c39943252 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -122,7 +122,7 @@ fn add_function_impl( ctx: &CompletionContext, func: &hir::Function, ) { - let display = FunctionSignature::from_hir(ctx.db, *func); + let signature = FunctionSignature::from_hir(ctx.db, *func); let fn_name = func.name(ctx.db).to_string(); @@ -141,12 +141,20 @@ fn add_function_impl( } else { CompletionItemKind::Function }; - - let snippet = format!("{} {{\n $0\n}}", display); - let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); - builder.snippet_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); + match ctx.config.snippet_cap { + Some(cap) => { + let snippet = format!("{} {{\n $0\n}}", signature); + builder.snippet_edit(cap, TextEdit::replace(range, snippet)) + } + None => { + let header = format!("{} {{", signature); + builder.text_edit(TextEdit::replace(range, header)) + } + } + .kind(completion_kind) + .add_to(acc); } fn add_type_alias_impl( diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index edbf4a5b7..fb06cc125 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs @@ -2,6 +2,7 @@ use std::fmt; +use super::completion_config::SnippetCap; use hir::Documentation; use ra_syntax::TextRange; use ra_text_edit::TextEdit; @@ -270,7 +271,11 @@ impl Builder { self.insert_text = Some(insert_text.into()); self } - pub(crate) fn insert_snippet(mut self, snippet: impl Into) -> Builder { + pub(crate) fn insert_snippet( + mut self, + _cap: SnippetCap, + snippet: impl Into, + ) -> Builder { self.insert_text_format = InsertTextFormat::Snippet; self.insert_text(snippet) } @@ -282,7 +287,7 @@ impl Builder { self.text_edit = Some(edit); self } - pub(crate) fn snippet_edit(mut self, edit: TextEdit) -> Builder { + pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder { self.insert_text_format = InsertTextFormat::Snippet; self.text_edit(edit) } diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 78df9cbdb..5e2b8b920 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -114,17 +114,19 @@ impl Completions { // Add `<>` for generic types if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { - let has_non_default_type_params = match resolution { - ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), - ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), - _ => false, - }; - if has_non_default_type_params { - tested_by!(inserts_angle_brackets_for_generics); - completion_item = completion_item - .lookup_by(local_name.clone()) - .label(format!("{}<…>", local_name)) - .insert_snippet(format!("{}<$0>", local_name)); + if let Some(cap) = ctx.config.snippet_cap { + let has_non_default_type_params = match resolution { + ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), + ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), + _ => false, + }; + if has_non_default_type_params { + tested_by!(inserts_angle_brackets_for_generics); + completion_item = completion_item + .lookup_by(local_name.clone()) + .label(format!("{}<…>", local_name)) + .insert_snippet(cap, format!("{}<$0>", local_name)); + } } } @@ -184,13 +186,16 @@ impl Completions { .set_deprecated(is_deprecated(macro_, ctx.db)) .detail(detail); - builder = if ctx.use_item_syntax.is_some() || ctx.is_macro_call { - tested_by!(dont_insert_macro_call_parens_unncessary); - builder.insert_text(name) - } else { - let macro_braces_to_insert = - self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); - builder.insert_snippet(macro_declaration + macro_braces_to_insert) + builder = match ctx.config.snippet_cap { + Some(cap) if ctx.use_item_syntax.is_none() && !ctx.is_macro_call => { + let macro_braces_to_insert = + self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); + builder.insert_snippet(cap, macro_declaration + macro_braces_to_insert) + } + _ => { + tested_by!(dont_insert_macro_call_parens_unncessary); + builder.insert_text(name) + } }; self.add(builder); @@ -366,6 +371,10 @@ impl Builder { if ctx.use_item_syntax.is_some() || ctx.is_call { return self; } + let cap = match ctx.config.snippet_cap { + Some(it) => it, + None => return self, + }; // If not an import, add parenthesis automatically. tested_by!(inserts_parens_for_function_calls); @@ -387,7 +396,7 @@ impl Builder { (snippet, format!("{}(…)", name)) }; - self.lookup_by(name).label(label).insert_snippet(snippet) + self.lookup_by(name).label(label).insert_snippet(cap, snippet) } } -- cgit v1.2.3