aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists/add_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assists/add_impl.rs')
-rw-r--r--crates/ra_assists/src/assists/add_impl.rs77
1 files changed, 77 insertions, 0 deletions
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs
new file mode 100644
index 000000000..4b61f4031
--- /dev/null
+++ b/crates/ra_assists/src/assists/add_impl.rs
@@ -0,0 +1,77 @@
1use format_buf::format;
2use hir::db::HirDatabase;
3use join_to_string::join;
4use ra_syntax::{
5 ast::{self, AstNode, NameOwner, TypeParamsOwner},
6 TextUnit,
7};
8
9use crate::{Assist, AssistCtx, AssistId};
10
11pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
12 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
13 let name = nominal.name()?;
14 ctx.add_action(AssistId("add_impl"), "add impl", |edit| {
15 edit.target(nominal.syntax().text_range());
16 let type_params = nominal.type_param_list();
17 let start_offset = nominal.syntax().text_range().end();
18 let mut buf = String::new();
19 buf.push_str("\n\nimpl");
20 if let Some(type_params) = &type_params {
21 format!(buf, "{}", type_params.syntax());
22 }
23 buf.push_str(" ");
24 buf.push_str(name.text().as_str());
25 if let Some(type_params) = type_params {
26 let lifetime_params = type_params
27 .lifetime_params()
28 .filter_map(|it| it.lifetime_token())
29 .map(|it| it.text().clone());
30 let type_params =
31 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
32 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
33 }
34 buf.push_str(" {\n");
35 edit.set_cursor(start_offset + TextUnit::of_str(&buf));
36 buf.push_str("\n}");
37 edit.insert(start_offset, buf);
38 });
39
40 ctx.build()
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use crate::helpers::{check_assist, check_assist_target};
47
48 #[test]
49 fn test_add_impl() {
50 check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n");
51 check_assist(
52 add_impl,
53 "struct Foo<T: Clone> {<|>}",
54 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
55 );
56 check_assist(
57 add_impl,
58 "struct Foo<'a, T: Foo<'a>> {<|>}",
59 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}",
60 );
61 }
62
63 #[test]
64 fn add_impl_target() {
65 check_assist_target(
66 add_impl,
67 "
68struct SomeThingIrrelevant;
69/// Has a lifetime parameter
70struct Foo<'a, T: Foo<'a>> {<|>}
71struct EvenMoreIrrelevant;
72",
73 "/// Has a lifetime parameter
74struct Foo<'a, T: Foo<'a>> {}",
75 );
76 }
77}