diff --git a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs index af949a064989..1837ce1ae023 100644 --- a/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs +++ b/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs @@ -1,7 +1,10 @@ use ide_db::{RootDatabase, famous_defs::FamousDefs}; -use syntax::ast::{self, AstNode, HasName}; +use syntax::ast::{self, AstNode, HasName, edit::AstNodeEdit}; -use crate::{AssistContext, AssistId, Assists, utils::generate_trait_impl_text_intransitive}; +use crate::{ + AssistContext, AssistId, Assists, + utils::{generate_trait_impl_text_intransitive, indent_string}, +}; // Assist: generate_from_impl_for_enum // @@ -71,7 +74,7 @@ pub(crate) fn generate_from_impl_for_enum( ) }; let from_impl = generate_trait_impl_text_intransitive(&enum_, &from_trait, &impl_code); - edit.insert(start_offset, from_impl); + edit.insert(start_offset, indent_string(&from_impl, enum_.indent_level())); }, ) } @@ -295,6 +298,54 @@ impl<'a> From<&'a i32> for Generic<'a> { Self::One(v) } } +"#, + ); + } + + #[test] + fn test_non_zero_indent() { + check_assist( + generate_from_impl_for_enum, + r#" +//- minicore: from +mod foo { + enum Generic<'a> { $0One(&'a i32) } +} +"#, + r#" +mod foo { + enum Generic<'a> { One(&'a i32) } + + impl<'a> From<&'a i32> for Generic<'a> { + fn from(v: &'a i32) -> Self { + Self::One(v) + } + } +} +"#, + ); + check_assist( + generate_from_impl_for_enum, + r#" +//- minicore: from +mod foo { + mod bar { + enum Generic<'a> { $0One(&'a i32) } + } +} +"#, + r#" +mod foo { + mod bar { + enum Generic<'a> { One(&'a i32) } + + impl<'a> From<&'a i32> for Generic<'a> { + fn from(v: &'a i32) -> Self { + Self::One(v) + } + } + } +} "#, ); } diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index ef6914fda1d5..83b36f1efdd3 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -1,5 +1,7 @@ //! Assorted functions shared by several assists. +use std::borrow::Cow; + pub(crate) use gen_trait_fn_body::gen_trait_fn_body; use hir::{ DisplayTarget, HasAttrs as HirHasAttrs, HirDisplay, InFile, ModuleDef, PathResolution, @@ -250,6 +252,35 @@ pub fn add_trait_assoc_items_to_impl( first_item.unwrap() } +pub(crate) fn indent_string(mut s: &str, indent_level: IndentLevel) -> Cow<'_, str> { + if indent_level.is_zero() || s.is_empty() { + return s.into(); + } + let level = indent_level.0 as usize; + + let indent = indent_level.to_string(); + let mut buf = String::with_capacity(s.len() + level * 3 * 4); + + if !s.starts_with('\n') { + buf.push_str(&indent); + } + + while let Some((line, rest)) = s.split_once('\n') { + buf.push_str(line); + buf.push('\n'); + + if !rest.split_once('\n').map_or(rest, |s| s.0).is_empty() { + buf.push_str(&indent); + } + + s = rest; + } + + buf.push_str(s); + + buf.into() +} + pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { node.children_with_tokens() .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))