Better label for macros completion
This commit is contained in:
parent
44e6c2cb54
commit
62e08fa53d
@ -41,7 +41,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo!(…)",
|
||||
source_range: [46; 46),
|
||||
delete: [46; 46),
|
||||
insert: "foo!($0)",
|
||||
@ -81,7 +81,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "vec!",
|
||||
label: "vec![…]",
|
||||
source_range: [280; 280),
|
||||
delete: [280; 280),
|
||||
insert: "vec![$0]",
|
||||
@ -118,7 +118,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo! {…}",
|
||||
source_range: [163; 163),
|
||||
delete: [163; 163),
|
||||
insert: "foo! {$0}",
|
||||
|
@ -125,7 +125,7 @@ mod tests {
|
||||
kind: Enum,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "m!",
|
||||
label: "m!(…)",
|
||||
source_range: [151; 151),
|
||||
delete: [151; 151),
|
||||
insert: "m!($0)",
|
||||
|
@ -869,7 +869,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo!(…)",
|
||||
source_range: [179; 179),
|
||||
delete: [179; 179),
|
||||
insert: "foo!($0)",
|
||||
|
@ -733,7 +733,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "bar!",
|
||||
label: "bar!(…)",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "bar!($0)",
|
||||
@ -741,7 +741,7 @@ mod tests {
|
||||
detail: "macro_rules! bar",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "baz!",
|
||||
label: "baz!(…)",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "baz!($0)",
|
||||
@ -749,7 +749,7 @@ mod tests {
|
||||
detail: "#[macro_export]\nmacro_rules! baz",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo!(…)",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "foo!($0)",
|
||||
@ -802,7 +802,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo!(…)",
|
||||
source_range: [49; 49),
|
||||
delete: [49; 49),
|
||||
insert: "foo!($0)",
|
||||
@ -841,7 +841,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo!(…)",
|
||||
source_range: [57; 57),
|
||||
delete: [57; 57),
|
||||
insert: "foo!($0)",
|
||||
@ -880,7 +880,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo!",
|
||||
label: "foo!(…)",
|
||||
source_range: [50; 50),
|
||||
delete: [50; 50),
|
||||
insert: "foo!($0)",
|
||||
@ -953,7 +953,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "m!",
|
||||
label: "m!(…)",
|
||||
source_range: [145; 145),
|
||||
delete: [145; 145),
|
||||
insert: "m!($0)",
|
||||
@ -1006,7 +1006,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "m!",
|
||||
label: "m!(…)",
|
||||
source_range: [145; 146),
|
||||
delete: [145; 146),
|
||||
insert: "m!($0)",
|
||||
@ -1059,7 +1059,7 @@ mod tests {
|
||||
@r###"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "m!",
|
||||
label: "m!(…)",
|
||||
source_range: [145; 146),
|
||||
delete: [145; 146),
|
||||
insert: "m!($0)",
|
||||
|
@ -133,29 +133,6 @@ impl Completions {
|
||||
completion_item.kind(kind).set_documentation(docs).add_to(self)
|
||||
}
|
||||
|
||||
fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str {
|
||||
let mut votes = [0, 0, 0];
|
||||
for (idx, s) in docs.match_indices(¯o_name) {
|
||||
let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
|
||||
// Ensure to match the full word
|
||||
if after.starts_with('!')
|
||||
&& !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
|
||||
{
|
||||
// It may have spaces before the braces like `foo! {}`
|
||||
match after[1..].chars().find(|&c| !c.is_whitespace()) {
|
||||
Some('{') => votes[0] += 1,
|
||||
Some('[') => votes[1] += 1,
|
||||
Some('(') => votes[2] += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a space before `{}`.
|
||||
// We prefer the last one when some votes equal.
|
||||
*votes.iter().zip(&[" {$0}", "[$0]", "($0)"]).max_by_key(|&(&vote, _)| vote).unwrap().1
|
||||
}
|
||||
|
||||
pub(crate) fn add_macro(
|
||||
&mut self,
|
||||
ctx: &CompletionContext,
|
||||
@ -177,21 +154,27 @@ impl Completions {
|
||||
let detail = macro_label(&ast_node);
|
||||
|
||||
let docs = macro_.docs(ctx.db);
|
||||
let macro_declaration = format!("{}!", name);
|
||||
|
||||
let mut builder =
|
||||
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration)
|
||||
.kind(CompletionItemKind::Macro)
|
||||
.set_documentation(docs.clone())
|
||||
.set_deprecated(is_deprecated(macro_, ctx.db))
|
||||
.detail(detail);
|
||||
let mut builder = CompletionItem::new(
|
||||
CompletionKind::Reference,
|
||||
ctx.source_range(),
|
||||
&format!("{}!", name),
|
||||
)
|
||||
.kind(CompletionItemKind::Macro)
|
||||
.set_documentation(docs.clone())
|
||||
.set_deprecated(is_deprecated(macro_, ctx.db))
|
||||
.detail(detail);
|
||||
|
||||
let needs_bang = ctx.use_item_syntax.is_none() && !ctx.is_macro_call;
|
||||
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)
|
||||
Some(cap) if needs_bang => {
|
||||
let docs = docs.as_ref().map_or("", |s| s.as_str());
|
||||
let (bra, ket) = guess_macro_braces(&name, docs);
|
||||
builder
|
||||
.insert_snippet(cap, format!("{}!{}$0{}", name, bra, ket))
|
||||
.label(format!("{}!{}…{}", name, bra, ket))
|
||||
}
|
||||
None if needs_bang => builder.insert_text(format!("{}!", name)),
|
||||
_ => {
|
||||
tested_by!(dont_insert_macro_call_parens_unncessary);
|
||||
builder.insert_text(name)
|
||||
@ -404,6 +387,34 @@ fn is_deprecated(node: impl HasAttrs, db: &RootDatabase) -> bool {
|
||||
node.attrs(db).by_key("deprecated").exists()
|
||||
}
|
||||
|
||||
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
|
||||
let mut votes = [0, 0, 0];
|
||||
for (idx, s) in docs.match_indices(¯o_name) {
|
||||
let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
|
||||
// Ensure to match the full word
|
||||
if after.starts_with('!')
|
||||
&& !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
|
||||
{
|
||||
// It may have spaces before the braces like `foo! {}`
|
||||
match after[1..].chars().find(|&c| !c.is_whitespace()) {
|
||||
Some('{') => votes[0] += 1,
|
||||
Some('[') => votes[1] += 1,
|
||||
Some('(') => votes[2] += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a space before `{}`.
|
||||
// We prefer the last one when some votes equal.
|
||||
let (_vote, (bra, ket)) = votes
|
||||
.iter()
|
||||
.zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
|
||||
.max_by_key(|&(&vote, _)| vote)
|
||||
.unwrap();
|
||||
(*bra, *ket)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_debug_snapshot;
|
||||
|
Loading…
x
Reference in New Issue
Block a user