diff options
Diffstat (limited to 'crates/completion/src/render/builder_ext.rs')
-rw-r--r-- | crates/completion/src/render/builder_ext.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs new file mode 100644 index 000000000..37b0d0459 --- /dev/null +++ b/crates/completion/src/render/builder_ext.rs | |||
@@ -0,0 +1,94 @@ | |||
1 | //! Extensions for `Builder` structure required for item rendering. | ||
2 | |||
3 | use itertools::Itertools; | ||
4 | use test_utils::mark; | ||
5 | |||
6 | use crate::{item::Builder, CompletionContext}; | ||
7 | |||
8 | pub(super) enum Params { | ||
9 | Named(Vec<String>), | ||
10 | Anonymous(usize), | ||
11 | } | ||
12 | |||
13 | impl Params { | ||
14 | pub(super) fn len(&self) -> usize { | ||
15 | match self { | ||
16 | Params::Named(xs) => xs.len(), | ||
17 | Params::Anonymous(len) => *len, | ||
18 | } | ||
19 | } | ||
20 | |||
21 | pub(super) fn is_empty(&self) -> bool { | ||
22 | self.len() == 0 | ||
23 | } | ||
24 | } | ||
25 | |||
26 | impl Builder { | ||
27 | pub(super) fn should_add_parems(&self, ctx: &CompletionContext) -> bool { | ||
28 | if !ctx.config.add_call_parenthesis { | ||
29 | return false; | ||
30 | } | ||
31 | if ctx.use_item_syntax.is_some() { | ||
32 | mark::hit!(no_parens_in_use_item); | ||
33 | return false; | ||
34 | } | ||
35 | if ctx.is_pattern_call { | ||
36 | mark::hit!(dont_duplicate_pattern_parens); | ||
37 | return false; | ||
38 | } | ||
39 | if ctx.is_call { | ||
40 | return false; | ||
41 | } | ||
42 | |||
43 | // Don't add parentheses if the expected type is some function reference. | ||
44 | if let Some(ty) = &ctx.expected_type { | ||
45 | if ty.is_fn() { | ||
46 | mark::hit!(no_call_parens_if_fn_ptr_needed); | ||
47 | return false; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | // Nothing prevents us from adding parentheses | ||
52 | true | ||
53 | } | ||
54 | |||
55 | pub(super) fn add_call_parens( | ||
56 | mut self, | ||
57 | ctx: &CompletionContext, | ||
58 | name: String, | ||
59 | params: Params, | ||
60 | ) -> Builder { | ||
61 | if !self.should_add_parems(ctx) { | ||
62 | return self; | ||
63 | } | ||
64 | |||
65 | let cap = match ctx.config.snippet_cap { | ||
66 | Some(it) => it, | ||
67 | None => return self, | ||
68 | }; | ||
69 | // If not an import, add parenthesis automatically. | ||
70 | mark::hit!(inserts_parens_for_function_calls); | ||
71 | |||
72 | let (snippet, label) = if params.is_empty() { | ||
73 | (format!("{}()$0", name), format!("{}()", name)) | ||
74 | } else { | ||
75 | self = self.trigger_call_info(); | ||
76 | let snippet = match (ctx.config.add_call_argument_snippets, params) { | ||
77 | (true, Params::Named(params)) => { | ||
78 | let function_params_snippet = | ||
79 | params.iter().enumerate().format_with(", ", |(index, param_name), f| { | ||
80 | f(&format_args!("${{{}:{}}}", index + 1, param_name)) | ||
81 | }); | ||
82 | format!("{}({})$0", name, function_params_snippet) | ||
83 | } | ||
84 | _ => { | ||
85 | mark::hit!(suppress_arg_snippets); | ||
86 | format!("{}($0)", name) | ||
87 | } | ||
88 | }; | ||
89 | |||
90 | (snippet, format!("{}(…)", name)) | ||
91 | }; | ||
92 | self.lookup_by(name).label(label).insert_snippet(cap, snippet) | ||
93 | } | ||
94 | } | ||