aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/generate_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists/src/handlers/generate_impl.rs')
-rw-r--r--crates/assists/src/handlers/generate_impl.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs
new file mode 100644
index 000000000..9989109b5
--- /dev/null
+++ b/crates/assists/src/handlers/generate_impl.rs
@@ -0,0 +1,110 @@
1use itertools::Itertools;
2use stdx::format_to;
3use syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner};
4
5use crate::{AssistContext, AssistId, AssistKind, Assists};
6
7// Assist: generate_impl
8//
9// Adds a new inherent impl for a type.
10//
11// ```
12// struct Ctx<T: Clone> {
13// data: T,<|>
14// }
15// ```
16// ->
17// ```
18// struct Ctx<T: Clone> {
19// data: T,
20// }
21//
22// impl<T: Clone> Ctx<T> {
23// $0
24// }
25// ```
26pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
27 let nominal = ctx.find_node_at_offset::<ast::AdtDef>()?;
28 let name = nominal.name()?;
29 let target = nominal.syntax().text_range();
30 acc.add(
31 AssistId("generate_impl", AssistKind::Generate),
32 format!("Generate impl for `{}`", name),
33 target,
34 |edit| {
35 let type_params = nominal.generic_param_list();
36 let start_offset = nominal.syntax().text_range().end();
37 let mut buf = String::new();
38 buf.push_str("\n\nimpl");
39 if let Some(type_params) = &type_params {
40 format_to!(buf, "{}", type_params.syntax());
41 }
42 buf.push_str(" ");
43 buf.push_str(name.text().as_str());
44 if let Some(type_params) = type_params {
45 let lifetime_params = type_params
46 .lifetime_params()
47 .filter_map(|it| it.lifetime_token())
48 .map(|it| it.text().clone());
49 let type_params = type_params
50 .type_params()
51 .filter_map(|it| it.name())
52 .map(|it| it.text().clone());
53
54 let generic_params = lifetime_params.chain(type_params).format(", ");
55 format_to!(buf, "<{}>", generic_params)
56 }
57 match ctx.config.snippet_cap {
58 Some(cap) => {
59 buf.push_str(" {\n $0\n}");
60 edit.insert_snippet(cap, start_offset, buf);
61 }
62 None => {
63 buf.push_str(" {\n}");
64 edit.insert(start_offset, buf);
65 }
66 }
67 },
68 )
69}
70
71#[cfg(test)]
72mod tests {
73 use crate::tests::{check_assist, check_assist_target};
74
75 use super::*;
76
77 #[test]
78 fn test_add_impl() {
79 check_assist(
80 generate_impl,
81 "struct Foo {<|>}\n",
82 "struct Foo {}\n\nimpl Foo {\n $0\n}\n",
83 );
84 check_assist(
85 generate_impl,
86 "struct Foo<T: Clone> {<|>}",
87 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}",
88 );
89 check_assist(
90 generate_impl,
91 "struct Foo<'a, T: Foo<'a>> {<|>}",
92 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
93 );
94 }
95
96 #[test]
97 fn add_impl_target() {
98 check_assist_target(
99 generate_impl,
100 "
101struct SomeThingIrrelevant;
102/// Has a lifetime parameter
103struct Foo<'a, T: Foo<'a>> {<|>}
104struct EvenMoreIrrelevant;
105",
106 "/// Has a lifetime parameter
107struct Foo<'a, T: Foo<'a>> {}",
108 );
109 }
110}