4 SyntaxKind::{IDENT, WHITESPACE},
10 assist_context::{AssistContext, Assists},
14 // Assist: add_custom_impl
16 // Adds impl block for derived trait.
19 // #[derive(Deb<|>ug, Display)]
31 pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 let input = ctx.find_node_at_offset::<ast::AttrInput>()?;
33 let attr = input.syntax().parent().and_then(ast::Attr::cast)?;
37 .descendants_with_tokens()
38 .filter(|t| t.kind() == IDENT)
39 .find_map(|i| i.into_token())
40 .filter(|t| *t.text() == "derive")?
45 ctx.token_at_offset().find(|t| t.kind() == IDENT && *t.text() != attr_name)?;
47 let annotated = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?;
48 let annotated_name = annotated.syntax().text().to_string();
49 let start_offset = annotated.syntax().parent()?.text_range().end();
52 format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name);
54 let target = attr.syntax().text_range();
55 acc.add(AssistId("add_custom_impl"), label, target, |builder| {
56 let new_attr_input = input
58 .descendants_with_tokens()
59 .filter(|t| t.kind() == IDENT)
60 .filter_map(|t| t.into_token().map(|t| t.text().clone()))
61 .filter(|t| t != trait_token.text())
62 .collect::<Vec<SmolStr>>();
63 let has_more_derives = !new_attr_input.is_empty();
64 let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
67 builder.replace(input.syntax().text_range(), new_attr_input);
69 let attr_range = attr.syntax().text_range();
70 builder.delete(attr_range);
72 let line_break_range = attr
74 .next_sibling_or_token()
75 .filter(|t| t.kind() == WHITESPACE)
76 .map(|t| t.text_range())
77 .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0)));
78 builder.delete(line_break_range);
81 match ctx.config.snippet_cap {
83 builder.insert_snippet(
86 format!("\n\nimpl {} for {} {{\n $0\n}}", trait_token, annotated_name),
92 format!("\n\nimpl {} for {} {{\n\n}}", trait_token, annotated_name),
101 use crate::tests::{check_assist, check_assist_not_applicable};
106 fn add_custom_impl_for_unique_input() {
128 fn add_custom_impl_for_with_visibility_modifier() {
150 fn add_custom_impl_when_multiple_inputs() {
154 #[derive(Display, Debug<|>, Serialize)]
158 #[derive(Display, Serialize)]
169 fn test_ignore_derive_macro_without_input() {
170 check_assist_not_applicable(
180 fn test_ignore_if_cursor_on_param() {
181 check_assist_not_applicable(
189 check_assist_not_applicable(
199 fn test_ignore_if_not_derive() {
200 check_assist_not_applicable(
203 #[allow(non_camel_<|>case_types)]