Migrate generate_delegate_methods assist to use SyntaxEditor

This commit is contained in:
Hmikihiro 2025-08-02 19:13:07 +09:00
parent 68e7ec90bf
commit 85f7112c0e
6 changed files with 40 additions and 35 deletions

View file

@ -183,13 +183,11 @@ fn add_missing_impl_members_inner(
.clone() .clone()
.into_iter() .into_iter()
.chain(other_items.iter().cloned()) .chain(other_items.iter().cloned())
.map(either::Either::Right)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut editor = edit.make_editor(impl_def.syntax()); let mut editor = edit.make_editor(impl_def.syntax());
if let Some(assoc_item_list) = impl_def.assoc_item_list() { if let Some(assoc_item_list) = impl_def.assoc_item_list() {
let items = new_assoc_items.into_iter().filter_map(either::Either::right).collect(); assoc_item_list.add_items(&mut editor, new_assoc_items);
assoc_item_list.add_items(&mut editor, items);
} else { } else {
let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update(); let assoc_item_list = make::assoc_item_list(Some(new_assoc_items)).clone_for_update();
editor.insert_all( editor.insert_all(

View file

@ -2,9 +2,11 @@ use hir::{HasCrate, HasVisibility};
use ide_db::{FxHashSet, path_transform::PathTransform}; use ide_db::{FxHashSet, path_transform::PathTransform};
use syntax::{ use syntax::{
ast::{ ast::{
self, AstNode, HasGenericParams, HasName, HasVisibility as _, edit_in_place::Indent, make, self, AstNode, HasGenericParams, HasName, HasVisibility as _,
edit::{AstNodeEdit, IndentLevel},
make,
}, },
ted, syntax_editor::Position,
}; };
use crate::{ use crate::{
@ -165,54 +167,66 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
is_unsafe, is_unsafe,
is_gen, is_gen,
) )
.clone_for_update(); .indent(IndentLevel(1));
let item = ast::AssocItem::Fn(f.clone());
// Get the impl to update, or create one if we need to. let mut editor = edit.make_editor(strukt.syntax());
let impl_def = match impl_def { let fn_: Option<ast::AssocItem> = match impl_def {
Some(impl_def) => edit.make_mut(impl_def), Some(impl_def) => match impl_def.assoc_item_list() {
Some(assoc_item_list) => {
let item = item.indent(IndentLevel::from_node(impl_def.syntax()));
assoc_item_list.add_items(&mut editor, vec![item.clone()]);
Some(item)
}
None => {
let assoc_item_list = make::assoc_item_list(Some(vec![item]));
editor.insert(
Position::last_child_of(impl_def.syntax()),
assoc_item_list.syntax(),
);
assoc_item_list.assoc_items().next()
}
},
None => { None => {
let name = &strukt_name.to_string(); let name = &strukt_name.to_string();
let ty_params = strukt.generic_param_list(); let ty_params = strukt.generic_param_list();
let ty_args = ty_params.as_ref().map(|it| it.to_generic_args()); let ty_args = ty_params.as_ref().map(|it| it.to_generic_args());
let where_clause = strukt.where_clause(); let where_clause = strukt.where_clause();
let assoc_item_list = make::assoc_item_list(Some(vec![item]));
let impl_def = make::impl_( let impl_def = make::impl_(
ty_params, ty_params,
ty_args, ty_args,
make::ty_path(make::ext::ident_path(name)), make::ty_path(make::ext::ident_path(name)),
where_clause, where_clause,
None, Some(assoc_item_list),
) )
.clone_for_update(); .clone_for_update();
// Fixup impl_def indentation // Fixup impl_def indentation
let indent = strukt.indent_level(); let indent = strukt.indent_level();
impl_def.reindent_to(indent); let impl_def = impl_def.indent(indent);
// Insert the impl block. // Insert the impl block.
let strukt = edit.make_mut(strukt.clone()); let strukt = edit.make_mut(strukt.clone());
ted::insert_all( editor.insert_all(
ted::Position::after(strukt.syntax()), Position::after(strukt.syntax()),
vec![ vec![
make::tokens::whitespace(&format!("\n\n{indent}")).into(), make::tokens::whitespace(&format!("\n\n{indent}")).into(),
impl_def.syntax().clone().into(), impl_def.syntax().clone().into(),
], ],
); );
impl_def.assoc_item_list().and_then(|list| list.assoc_items().next())
impl_def
} }
}; };
// Fixup function indentation. if let Some(cap) = ctx.config.snippet_cap
// FIXME: Should really be handled by `AssocItemList::add_item` && let Some(fn_) = fn_
f.reindent_to(impl_def.indent_level() + 1); {
let tabstop = edit.make_tabstop_before(cap);
let assoc_items = impl_def.get_or_create_assoc_item_list(); editor.add_annotation(fn_.syntax(), tabstop);
assoc_items.add_item(f.clone().into());
if let Some(cap) = ctx.config.snippet_cap {
edit.add_tabstop_before(cap, f)
} }
edit.add_file_edits(ctx.vfs_file_id(), editor);
}, },
)?; )?;
} }

View file

@ -201,7 +201,6 @@ pub(crate) fn generate_impl_trait(acc: &mut Assists, ctx: &AssistContext<'_>) ->
&impl_, &impl_,
&target_scope, &target_scope,
); );
let assoc_items = assoc_items.into_iter().map(either::Either::Right).collect();
let assoc_item_list = make::assoc_item_list(Some(assoc_items)); let assoc_item_list = make::assoc_item_list(Some(assoc_items));
make_impl_(Some(assoc_item_list)) make_impl_(Some(assoc_item_list))
}; };

View file

@ -168,7 +168,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
); );
fn_.syntax().clone() fn_.syntax().clone()
} else { } else {
let items = vec![either::Either::Right(ast::AssocItem::Fn(fn_))]; let items = vec![ast::AssocItem::Fn(fn_)];
let list = make::assoc_item_list(Some(items)); let list = make::assoc_item_list(Some(items));
editor.insert(Position::after(impl_def.syntax()), list.syntax()); editor.insert(Position::after(impl_def.syntax()), list.syntax());
list.syntax().clone() list.syntax().clone()
@ -176,7 +176,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
} else { } else {
// Generate a new impl to add the method to // Generate a new impl to add the method to
let indent_level = strukt.indent_level(); let indent_level = strukt.indent_level();
let body = vec![either::Either::Right(ast::AssocItem::Fn(fn_))]; let body = vec![ast::AssocItem::Fn(fn_)];
let list = make::assoc_item_list(Some(body)); let list = make::assoc_item_list(Some(body));
let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list)); let impl_def = generate_impl_with_item(&ast::Adt::Struct(strukt.clone()), Some(list));

View file

@ -221,11 +221,7 @@ fn impl_def_from_trait(
} else { } else {
Some(first.clone()) Some(first.clone())
}; };
let items = first_item let items = first_item.into_iter().chain(other.iter().cloned()).collect();
.into_iter()
.chain(other.iter().cloned())
.map(either::Either::Right)
.collect();
make::assoc_item_list(Some(items)) make::assoc_item_list(Some(items))
} else { } else {
make::assoc_item_list(None) make::assoc_item_list(None)

View file

@ -229,9 +229,7 @@ pub fn ty_fn_ptr<I: Iterator<Item = Param>>(
} }
} }
pub fn assoc_item_list( pub fn assoc_item_list(body: Option<Vec<ast::AssocItem>>) -> ast::AssocItemList {
body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
) -> ast::AssocItemList {
let is_break_braces = body.is_some(); let is_break_braces = body.is_some();
let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() }; let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() };
let body_indent = if is_break_braces { " ".to_owned() } else { String::new() }; let body_indent = if is_break_braces { " ".to_owned() } else { String::new() };