mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Guess macro braces from docs
This commit is contained in:
parent
6b9bd7bdd2
commit
24d50ebcd1
2 changed files with 91 additions and 7 deletions
|
@ -56,6 +56,16 @@ mod tests {
|
||||||
do_reference_completion(
|
do_reference_completion(
|
||||||
"
|
"
|
||||||
//- /main.rs
|
//- /main.rs
|
||||||
|
/// Creates a [`Vec`] containing the arguments.
|
||||||
|
///
|
||||||
|
/// - Create a [`Vec`] containing a given list of elements:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let v = vec![1, 2, 3];
|
||||||
|
/// assert_eq!(v[0], 1);
|
||||||
|
/// assert_eq!(v[1], 2);
|
||||||
|
/// assert_eq!(v[2], 3);
|
||||||
|
/// ```
|
||||||
macro_rules! vec {
|
macro_rules! vec {
|
||||||
() => {}
|
() => {}
|
||||||
}
|
}
|
||||||
|
@ -68,13 +78,61 @@ mod tests {
|
||||||
@r##"[
|
@r##"[
|
||||||
CompletionItem {
|
CompletionItem {
|
||||||
label: "vec!",
|
label: "vec!",
|
||||||
source_range: [46; 46),
|
source_range: [280; 280),
|
||||||
delete: [46; 46),
|
delete: [280; 280),
|
||||||
insert: "vec![$0]",
|
insert: "vec![$0]",
|
||||||
kind: Macro,
|
kind: Macro,
|
||||||
detail: "macro_rules! vec",
|
detail: "macro_rules! vec",
|
||||||
|
documentation: Documentation(
|
||||||
|
"Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
|
||||||
|
),
|
||||||
},
|
},
|
||||||
]"##
|
]"##
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_macros_braces_guessing() {
|
||||||
|
assert_debug_snapshot!(
|
||||||
|
do_reference_completion(
|
||||||
|
"
|
||||||
|
//- /main.rs
|
||||||
|
/// Foo
|
||||||
|
///
|
||||||
|
/// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
|
||||||
|
/// Call as `let _=foo! { hello world };`
|
||||||
|
macro_rules! foo {
|
||||||
|
() => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
<|>
|
||||||
|
}
|
||||||
|
"
|
||||||
|
),
|
||||||
|
@r###"[
|
||||||
|
CompletionItem {
|
||||||
|
label: "foo!",
|
||||||
|
source_range: [163; 163),
|
||||||
|
delete: [163; 163),
|
||||||
|
insert: "foo! {$0}",
|
||||||
|
kind: Macro,
|
||||||
|
detail: "macro_rules! foo",
|
||||||
|
documentation: Documentation(
|
||||||
|
"Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "main()",
|
||||||
|
source_range: [163; 163),
|
||||||
|
delete: [163; 163),
|
||||||
|
insert: "main()$0",
|
||||||
|
kind: Function,
|
||||||
|
lookup: "main",
|
||||||
|
detail: "fn main()",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,33 @@ impl Completions {
|
||||||
self.add_function_with_name(ctx, None, func)
|
self.add_function_with_name(ctx, None, func)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
.chars()
|
||||||
|
.rev()
|
||||||
|
.next()
|
||||||
|
.map_or(true, |c| 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(
|
pub(crate) fn add_macro(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
@ -141,10 +168,9 @@ impl Completions {
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
let detail = macro_label(&ast_node);
|
let detail = macro_label(&ast_node);
|
||||||
|
|
||||||
let macro_braces_to_insert = match name.as_str() {
|
let docs = macro_.docs(ctx.db);
|
||||||
"vec" => "[$0]",
|
let macro_braces_to_insert =
|
||||||
_ => "($0)",
|
self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str()));
|
||||||
};
|
|
||||||
let macro_declaration = name + "!";
|
let macro_declaration = name + "!";
|
||||||
|
|
||||||
let builder = CompletionItem::new(
|
let builder = CompletionItem::new(
|
||||||
|
@ -153,7 +179,7 @@ impl Completions {
|
||||||
¯o_declaration,
|
¯o_declaration,
|
||||||
)
|
)
|
||||||
.kind(CompletionItemKind::Macro)
|
.kind(CompletionItemKind::Macro)
|
||||||
.set_documentation(macro_.docs(ctx.db))
|
.set_documentation(docs)
|
||||||
.detail(detail)
|
.detail(detail)
|
||||||
.insert_snippet(macro_declaration + macro_braces_to_insert);
|
.insert_snippet(macro_declaration + macro_braces_to_insert);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue