Auto merge of #17982 - IvarWithoutBones:generate-impl-indent, r=Veykril

fix: consider indentation in the "Generate impl" and "Generate trait impl" assists

This makes the generated impl's indentation match the ADT it targets, improving formatting when using nested modules inside of the same file or when defining types inside of a function. See the added tests for an example.

At first I tried to call some of the convenient helpers that delegate to `IndentLevel::increase_indent` on the generated impl, but as the comment on that function notes it does not indent the first token, making it inapplicable here. I hope the solution in this PR is acceptable, please let me know if I missed something :)
This commit is contained in:
bors 2024-08-30 05:38:59 +00:00
commit 16a29ced15

View File

@ -1,10 +1,22 @@
use syntax::{
ast::{self, make, AstNode, HasName},
ast::{self, edit_in_place::Indent, make, AstNode, HasName},
ted,
};
use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
fn insert_impl(impl_: ast::Impl, nominal: &ast::Adt) {
let indent = nominal.indent_level();
ted::insert_all_raw(
ted::Position::after(nominal.syntax()),
vec![
// Add a blank line after the ADT, and indentation for the impl to match the ADT
make::tokens::whitespace(&format!("\n\n{indent}")).into(),
impl_.syntax().clone().into(),
],
);
}
// Assist: generate_impl
//
// Adds a new inherent impl for a type.
@ -46,12 +58,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
}
}
// Add the impl after the adt
let nominal = edit.make_mut(nominal);
ted::insert_all_raw(
ted::Position::after(nominal.syntax()),
vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()],
);
insert_impl(impl_, &edit.make_mut(nominal));
},
)
}
@ -97,12 +104,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
}
}
// Add the impl after the adt
let nominal = edit.make_mut(nominal);
ted::insert_all_raw(
ted::Position::after(nominal.syntax()),
vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()],
);
insert_impl(impl_, &edit.make_mut(nominal));
},
)
}
@ -418,4 +420,65 @@ struct Foo$0<'a, T: Foo<'a>> {}
"/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}",
);
}
#[test]
fn add_impl_with_indent() {
check_assist(
generate_impl,
r#"
mod foo {
struct Bar$0 {}
}
"#,
r#"
mod foo {
struct Bar {}
impl Bar {$0}
}
"#,
);
}
#[test]
fn add_impl_with_multiple_indent() {
check_assist(
generate_impl,
r#"
mod foo {
fn bar() {
struct Baz$0 {}
}
}
"#,
r#"
mod foo {
fn bar() {
struct Baz {}
impl Baz {$0}
}
}
"#,
);
}
#[test]
fn add_trait_impl_with_indent() {
check_assist(
generate_trait_impl,
r#"
mod foo {
struct Bar$0 {}
}
"#,
r#"
mod foo {
struct Bar {}
impl ${0:_} for Bar {}
}
"#,
);
}
}