Skip to content

Commit 1f49c24

Browse files
committed
migrate generate_enum_is_method to syntax editor
1 parent 251df51 commit 1f49c24

1 file changed

Lines changed: 58 additions & 20 deletions

File tree

crates/ide-assists/src/handlers/generate_enum_is_method.rs

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use ide_db::assists::GroupLabel;
2-
use itertools::Itertools;
32
use stdx::to_lower_snake_case;
4-
use syntax::ast::HasVisibility;
5-
use syntax::ast::{self, AstNode, HasName};
3+
use syntax::{
4+
AstNode, Edition,
5+
ast::{self, HasName, HasVisibility, edit::AstNodeEdit},
6+
syntax_editor::Position,
7+
};
68

79
use crate::{
810
AssistContext, AssistId, Assists,
9-
utils::{add_method_to_adt, find_struct_impl, is_selected},
11+
utils::{find_struct_impl, generate_impl_with_item, is_selected},
1012
};
1113

1214
// Assist: generate_enum_is_method
@@ -64,27 +66,63 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_>
6466
target,
6567
|builder| {
6668
let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{v} "));
67-
let method = methods
69+
70+
let fn_items: Vec<ast::AssocItem> = methods
6871
.iter()
69-
.map(|Method { pattern_suffix, fn_name, variant_name }| {
70-
format!(
71-
" \
72-
/// Returns `true` if the {enum_lowercase_name} is [`{variant_name}`].
73-
///
74-
/// [`{variant_name}`]: {enum_name}::{variant_name}
75-
#[must_use]
76-
{vis}fn {fn_name}(&self) -> bool {{
77-
matches!(self, Self::{variant_name}{pattern_suffix})
78-
}}",
79-
)
80-
})
81-
.join("\n\n");
82-
83-
add_method_to_adt(builder, &parent_enum, impl_def, &method);
72+
.map(|method| build_fn_item(method, &enum_lowercase_name, &enum_name, &vis))
73+
.collect();
74+
75+
if let Some(impl_def) = &impl_def {
76+
let editor = builder.make_editor(impl_def.syntax());
77+
impl_def.assoc_item_list().unwrap().add_items(&editor, fn_items);
78+
builder.add_file_edits(ctx.vfs_file_id(), editor);
79+
return;
80+
}
81+
82+
let editor = builder.make_editor(parent_enum.syntax());
83+
let make = editor.make();
84+
let indent = parent_enum.indent_level();
85+
let assoc_list = make.assoc_item_list(fn_items);
86+
let new_impl = generate_impl_with_item(make, &parent_enum, Some(assoc_list));
87+
editor.insert_all(
88+
Position::after(parent_enum.syntax()),
89+
vec![
90+
make.whitespace(&format!("\n\n{indent}")).into(),
91+
new_impl.syntax().clone().into(),
92+
],
93+
);
94+
builder.add_file_edits(ctx.vfs_file_id(), editor);
8495
},
8596
)
8697
}
8798

99+
fn build_fn_item(
100+
method: &Method,
101+
enum_lowercase_name: &str,
102+
enum_name: &ast::Name,
103+
vis: &str,
104+
) -> ast::AssocItem {
105+
let Method { pattern_suffix, fn_name, variant_name } = method;
106+
let fn_text = format!(
107+
"/// Returns `true` if the {enum_lowercase_name} is [`{variant_name}`].
108+
///
109+
/// [`{variant_name}`]: {enum_name}::{variant_name}
110+
#[must_use]
111+
{vis}fn {fn_name}(&self) -> bool {{
112+
matches!(self, Self::{variant_name}{pattern_suffix})
113+
}}"
114+
);
115+
let wrapped = format!("impl X {{ {fn_text} }}");
116+
let parse = syntax::SourceFile::parse(&wrapped, Edition::CURRENT);
117+
let fn_ = parse
118+
.tree()
119+
.syntax()
120+
.descendants()
121+
.find_map(ast::Fn::cast)
122+
.expect("fn text must produce a valid fn node");
123+
ast::AssocItem::Fn(fn_.indent(1.into()))
124+
}
125+
88126
struct Method {
89127
pattern_suffix: &'static str,
90128
fn_name: String,

0 commit comments

Comments
 (0)