mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-17 02:08:30 +00:00
Merge #2039
2039: Guess macro braces from docs r=matklad a=oxalica Instead of hard-code `vec` to have snippet with bracket `vec![]`, we try to find the "most common used brace kind" from documentation of the macro, which usually contains some example code. It also works better with extern macros. We can suggest braces for `thread_local! {}` now. Co-authored-by: oxalica <oxalicc@pm.me>
This commit is contained in:
commit
e4810a302b
2 changed files with 91 additions and 7 deletions
|
@ -56,6 +56,16 @@ mod tests {
|
|||
do_reference_completion(
|
||||
"
|
||||
//- /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 {
|
||||
() => {}
|
||||
}
|
||||
|
@ -68,13 +78,61 @@ mod tests {
|
|||
@r##"[
|
||||
CompletionItem {
|
||||
label: "vec!",
|
||||
source_range: [46; 46),
|
||||
delete: [46; 46),
|
||||
source_range: [280; 280),
|
||||
delete: [280; 280),
|
||||
insert: "vec![$0]",
|
||||
kind: Macro,
|
||||
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)
|
||||
}
|
||||
|
||||
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(
|
||||
&mut self,
|
||||
ctx: &CompletionContext,
|
||||
|
@ -141,10 +168,9 @@ impl Completions {
|
|||
if let Some(name) = name {
|
||||
let detail = macro_label(&ast_node);
|
||||
|
||||
let macro_braces_to_insert = match name.as_str() {
|
||||
"vec" => "[$0]",
|
||||
_ => "($0)",
|
||||
};
|
||||
let docs = macro_.docs(ctx.db);
|
||||
let macro_braces_to_insert =
|
||||
self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str()));
|
||||
let macro_declaration = name + "!";
|
||||
|
||||
let builder = CompletionItem::new(
|
||||
|
@ -153,7 +179,7 @@ impl Completions {
|
|||
¯o_declaration,
|
||||
)
|
||||
.kind(CompletionItemKind::Macro)
|
||||
.set_documentation(macro_.docs(ctx.db))
|
||||
.set_documentation(docs)
|
||||
.detail(detail)
|
||||
.insert_snippet(macro_declaration + macro_braces_to_insert);
|
||||
|
||||
|
|
Loading…
Reference in a new issue