aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/add_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/add_impl.rs')
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs94
1 files changed, 94 insertions, 0 deletions
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
new file mode 100644
index 000000000..241b085fd
--- /dev/null
+++ b/crates/ra_assists/src/handlers/add_impl.rs
@@ -0,0 +1,94 @@
1use format_buf::format;
2
3use join_to_string::join;
4use ra_syntax::{
5 ast::{self, AstNode, NameOwner, TypeParamsOwner},
6 TextUnit,
7};
8
9use crate::{Assist, AssistCtx, AssistId};
10
11// Assist: add_impl
12//
13// Adds a new inherent impl for a type.
14//
15// ```
16// struct Ctx<T: Clone> {
17// data: T,<|>
18// }
19// ```
20// ->
21// ```
22// struct Ctx<T: Clone> {
23// data: T,
24// }
25//
26// impl<T: Clone> Ctx<T> {
27//
28// }
29// ```
30pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
31 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
32 let name = nominal.name()?;
33 ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| {
34 edit.target(nominal.syntax().text_range());
35 let type_params = nominal.type_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!(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 =
50 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
51 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
52 }
53 buf.push_str(" {\n");
54 edit.set_cursor(start_offset + TextUnit::of_str(&buf));
55 buf.push_str("\n}");
56 edit.insert(start_offset, buf);
57 })
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use crate::helpers::{check_assist, check_assist_target};
64
65 #[test]
66 fn test_add_impl() {
67 check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n");
68 check_assist(
69 add_impl,
70 "struct Foo<T: Clone> {<|>}",
71 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
72 );
73 check_assist(
74 add_impl,
75 "struct Foo<'a, T: Foo<'a>> {<|>}",
76 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}",
77 );
78 }
79
80 #[test]
81 fn add_impl_target() {
82 check_assist_target(
83 add_impl,
84 "
85struct SomeThingIrrelevant;
86/// Has a lifetime parameter
87struct Foo<'a, T: Foo<'a>> {<|>}
88struct EvenMoreIrrelevant;
89",
90 "/// Has a lifetime parameter
91struct Foo<'a, T: Foo<'a>> {}",
92 );
93 }
94}