Skip to content

Commit 29ecaa1

Browse files
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.
1 parent 28142e4 commit 29ecaa1

File tree

1 file changed

+76
-13
lines changed

1 file changed

+76
-13
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
use syntax::{
2-
ast::{self, make, AstNode, HasName},
2+
ast::{self, edit_in_place::Indent, make, AstNode, HasName},
33
ted,
44
};
55

66
use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
77

8+
fn insert_impl(impl_: ast::Impl, nominal: &ast::Adt) {
9+
let indent = nominal.indent_level();
10+
ted::insert_all_raw(
11+
ted::Position::after(nominal.syntax()),
12+
vec![
13+
// Add a blank line after the ADT, and indentation for the impl to match the ADT
14+
make::tokens::whitespace(&format!("\n\n{indent}")).into(),
15+
impl_.syntax().clone().into(),
16+
],
17+
);
18+
}
19+
820
// Assist: generate_impl
921
//
1022
// Adds a new inherent impl for a type.
@@ -46,12 +58,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
4658
}
4759
}
4860

49-
// Add the impl after the adt
50-
let nominal = edit.make_mut(nominal);
51-
ted::insert_all_raw(
52-
ted::Position::after(nominal.syntax()),
53-
vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()],
54-
);
61+
insert_impl(impl_, &edit.make_mut(nominal));
5562
},
5663
)
5764
}
@@ -97,12 +104,7 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
97104
}
98105
}
99106

100-
// Add the impl after the adt
101-
let nominal = edit.make_mut(nominal);
102-
ted::insert_all_raw(
103-
ted::Position::after(nominal.syntax()),
104-
vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()],
105-
);
107+
insert_impl(impl_, &edit.make_mut(nominal));
106108
},
107109
)
108110
}
@@ -418,4 +420,65 @@ mod tests {
418420
"/// Has a lifetime parameter\nstruct Foo<'a, T: Foo<'a>> {}",
419421
);
420422
}
423+
424+
#[test]
425+
fn add_impl_with_indent() {
426+
check_assist(
427+
generate_impl,
428+
r#"
429+
mod foo {
430+
struct Bar$0 {}
431+
}
432+
"#,
433+
r#"
434+
mod foo {
435+
struct Bar {}
436+
437+
impl Bar {$0}
438+
}
439+
"#,
440+
);
441+
}
442+
443+
#[test]
444+
fn add_impl_with_multiple_indent() {
445+
check_assist(
446+
generate_impl,
447+
r#"
448+
mod foo {
449+
fn bar() {
450+
struct Baz$0 {}
451+
}
452+
}
453+
"#,
454+
r#"
455+
mod foo {
456+
fn bar() {
457+
struct Baz {}
458+
459+
impl Baz {$0}
460+
}
461+
}
462+
"#,
463+
);
464+
}
465+
466+
#[test]
467+
fn add_trait_impl_with_indent() {
468+
check_assist(
469+
generate_trait_impl,
470+
r#"
471+
mod foo {
472+
struct Bar$0 {}
473+
}
474+
"#,
475+
r#"
476+
mod foo {
477+
struct Bar {}
478+
479+
impl ${0:_} for Bar {}
480+
}
481+
"#,
482+
);
483+
}
421484
}

0 commit comments

Comments
 (0)