Make sure that adding a snippet requires corresponding capability
This commit is contained in:
parent
b3050bded1
commit
5fd5de4061
@ -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 {
|
fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
|
||||||
CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
|
let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
|
||||||
.kind(CompletionItemKind::Keyword)
|
.kind(CompletionItemKind::Keyword);
|
||||||
.insert_snippet(snippet)
|
|
||||||
.build()
|
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) {
|
pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
|
@ -6,6 +6,7 @@ use ra_syntax::{
|
|||||||
};
|
};
|
||||||
use ra_text_edit::TextEdit;
|
use ra_text_edit::TextEdit;
|
||||||
|
|
||||||
|
use super::completion_config::SnippetCap;
|
||||||
use crate::{
|
use crate::{
|
||||||
completion::{
|
completion::{
|
||||||
completion_context::CompletionContext,
|
completion_context::CompletionContext,
|
||||||
@ -32,9 +33,15 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let cap = match ctx.config.snippet_cap {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
if receiver_ty.is_bool() || receiver_ty.is_unknown() {
|
if receiver_ty.is_bool() || receiver_ty.is_unknown() {
|
||||||
postfix_snippet(
|
postfix_snippet(
|
||||||
ctx,
|
ctx,
|
||||||
|
cap,
|
||||||
&dot_receiver,
|
&dot_receiver,
|
||||||
"if",
|
"if",
|
||||||
"if expr {}",
|
"if expr {}",
|
||||||
@ -43,6 +50,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||||||
.add_to(acc);
|
.add_to(acc);
|
||||||
postfix_snippet(
|
postfix_snippet(
|
||||||
ctx,
|
ctx,
|
||||||
|
cap,
|
||||||
&dot_receiver,
|
&dot_receiver,
|
||||||
"while",
|
"while",
|
||||||
"while expr {}",
|
"while expr {}",
|
||||||
@ -52,12 +60,21 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// !&&&42 is a compiler error, ergo process it before considering the references
|
// !&&&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))
|
||||||
|
|
||||||
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))
|
|
||||||
.add_to(acc);
|
.add_to(acc);
|
||||||
|
|
||||||
|
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,
|
// 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
|
// so it's better to consider references now to avoid breaking the compilation
|
||||||
let dot_receiver = include_references(dot_receiver);
|
let dot_receiver = include_references(dot_receiver);
|
||||||
@ -66,6 +83,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||||||
|
|
||||||
postfix_snippet(
|
postfix_snippet(
|
||||||
ctx,
|
ctx,
|
||||||
|
cap,
|
||||||
&dot_receiver,
|
&dot_receiver,
|
||||||
"match",
|
"match",
|
||||||
"match expr {}",
|
"match expr {}",
|
||||||
@ -75,6 +93,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||||||
|
|
||||||
postfix_snippet(
|
postfix_snippet(
|
||||||
ctx,
|
ctx,
|
||||||
|
cap,
|
||||||
&dot_receiver,
|
&dot_receiver,
|
||||||
"box",
|
"box",
|
||||||
"Box::new(expr)",
|
"Box::new(expr)",
|
||||||
@ -82,8 +101,15 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
|||||||
)
|
)
|
||||||
.add_to(acc);
|
.add_to(acc);
|
||||||
|
|
||||||
postfix_snippet(ctx, &dot_receiver, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text))
|
postfix_snippet(
|
||||||
.add_to(acc);
|
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 {
|
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(
|
fn postfix_snippet(
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
cap: SnippetCap,
|
||||||
receiver: &ast::Expr,
|
receiver: &ast::Expr,
|
||||||
label: &str,
|
label: &str,
|
||||||
detail: &str,
|
detail: &str,
|
||||||
@ -121,7 +148,7 @@ fn postfix_snippet(
|
|||||||
};
|
};
|
||||||
CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
|
CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
|
||||||
.detail(detail)
|
.detail(detail)
|
||||||
.snippet_edit(edit)
|
.snippet_edit(cap, edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
|
|
||||||
use crate::completion::{
|
use crate::completion::{
|
||||||
completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
|
completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem,
|
||||||
CompletionKind, Completions,
|
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)
|
CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), label)
|
||||||
.insert_snippet(snippet)
|
.insert_snippet(cap, snippet)
|
||||||
.kind(CompletionItemKind::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()) {
|
if !(ctx.is_trivial_path && ctx.function_syntax.is_some()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let cap = match ctx.config.snippet_cap {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
snippet(ctx, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc);
|
snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc);
|
||||||
snippet(ctx, "ppd", "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) {
|
pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
if !ctx.is_new_item {
|
if !ctx.is_new_item {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let cap = match ctx.config.snippet_cap {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
snippet(
|
snippet(
|
||||||
ctx,
|
ctx,
|
||||||
|
cap,
|
||||||
"Test function",
|
"Test function",
|
||||||
"\
|
"\
|
||||||
#[test]
|
#[test]
|
||||||
@ -36,8 +46,8 @@ fn ${1:feature}() {
|
|||||||
.lookup_by("tfn")
|
.lookup_by("tfn")
|
||||||
.add_to(acc);
|
.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, cap, "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, "pub(crate)", "pub(crate) $0").add_to(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -122,7 +122,7 @@ fn add_function_impl(
|
|||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
func: &hir::Function,
|
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();
|
let fn_name = func.name(ctx.db).to_string();
|
||||||
|
|
||||||
@ -141,12 +141,20 @@ fn add_function_impl(
|
|||||||
} else {
|
} else {
|
||||||
CompletionItemKind::Function
|
CompletionItemKind::Function
|
||||||
};
|
};
|
||||||
|
|
||||||
let snippet = format!("{} {{\n $0\n}}", display);
|
|
||||||
|
|
||||||
let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());
|
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(
|
fn add_type_alias_impl(
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::completion_config::SnippetCap;
|
||||||
use hir::Documentation;
|
use hir::Documentation;
|
||||||
use ra_syntax::TextRange;
|
use ra_syntax::TextRange;
|
||||||
use ra_text_edit::TextEdit;
|
use ra_text_edit::TextEdit;
|
||||||
@ -270,7 +271,11 @@ impl Builder {
|
|||||||
self.insert_text = Some(insert_text.into());
|
self.insert_text = Some(insert_text.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub(crate) fn insert_snippet(mut self, snippet: impl Into<String>) -> Builder {
|
pub(crate) fn insert_snippet(
|
||||||
|
mut self,
|
||||||
|
_cap: SnippetCap,
|
||||||
|
snippet: impl Into<String>,
|
||||||
|
) -> Builder {
|
||||||
self.insert_text_format = InsertTextFormat::Snippet;
|
self.insert_text_format = InsertTextFormat::Snippet;
|
||||||
self.insert_text(snippet)
|
self.insert_text(snippet)
|
||||||
}
|
}
|
||||||
@ -282,7 +287,7 @@ impl Builder {
|
|||||||
self.text_edit = Some(edit);
|
self.text_edit = Some(edit);
|
||||||
self
|
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.insert_text_format = InsertTextFormat::Snippet;
|
||||||
self.text_edit(edit)
|
self.text_edit(edit)
|
||||||
}
|
}
|
||||||
|
@ -114,17 +114,19 @@ impl Completions {
|
|||||||
|
|
||||||
// Add `<>` for generic types
|
// Add `<>` for generic types
|
||||||
if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
|
if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
|
||||||
let has_non_default_type_params = match resolution {
|
if let Some(cap) = ctx.config.snippet_cap {
|
||||||
ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
|
let has_non_default_type_params = match resolution {
|
||||||
ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
|
ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
|
||||||
_ => false,
|
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);
|
if has_non_default_type_params {
|
||||||
completion_item = completion_item
|
tested_by!(inserts_angle_brackets_for_generics);
|
||||||
.lookup_by(local_name.clone())
|
completion_item = completion_item
|
||||||
.label(format!("{}<…>", local_name))
|
.lookup_by(local_name.clone())
|
||||||
.insert_snippet(format!("{}<$0>", local_name));
|
.label(format!("{}<…>", local_name))
|
||||||
|
.insert_snippet(cap, format!("{}<$0>", local_name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,13 +186,16 @@ impl Completions {
|
|||||||
.set_deprecated(is_deprecated(macro_, ctx.db))
|
.set_deprecated(is_deprecated(macro_, ctx.db))
|
||||||
.detail(detail);
|
.detail(detail);
|
||||||
|
|
||||||
builder = if ctx.use_item_syntax.is_some() || ctx.is_macro_call {
|
builder = match ctx.config.snippet_cap {
|
||||||
tested_by!(dont_insert_macro_call_parens_unncessary);
|
Some(cap) if ctx.use_item_syntax.is_none() && !ctx.is_macro_call => {
|
||||||
builder.insert_text(name)
|
let macro_braces_to_insert =
|
||||||
} else {
|
self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str()));
|
||||||
let macro_braces_to_insert =
|
builder.insert_snippet(cap, macro_declaration + 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)
|
_ => {
|
||||||
|
tested_by!(dont_insert_macro_call_parens_unncessary);
|
||||||
|
builder.insert_text(name)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.add(builder);
|
self.add(builder);
|
||||||
@ -366,6 +371,10 @@ impl Builder {
|
|||||||
if ctx.use_item_syntax.is_some() || ctx.is_call {
|
if ctx.use_item_syntax.is_some() || ctx.is_call {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
let cap = match ctx.config.snippet_cap {
|
||||||
|
Some(it) => it,
|
||||||
|
None => return self,
|
||||||
|
};
|
||||||
// If not an import, add parenthesis automatically.
|
// If not an import, add parenthesis automatically.
|
||||||
tested_by!(inserts_parens_for_function_calls);
|
tested_by!(inserts_parens_for_function_calls);
|
||||||
|
|
||||||
@ -387,7 +396,7 @@ impl Builder {
|
|||||||
|
|
||||||
(snippet, format!("{}(…)", name))
|
(snippet, format!("{}(…)", name))
|
||||||
};
|
};
|
||||||
self.lookup_by(name).label(label).insert_snippet(snippet)
|
self.lookup_by(name).label(label).insert_snippet(cap, snippet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user