mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Migrate add_turbo_fish
to SyntaxEditor
This commit is contained in:
parent
a2bb014914
commit
6aa5ea5411
2 changed files with 77 additions and 24 deletions
|
@ -1,8 +1,9 @@
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use ide_db::defs::{Definition, NameRefClass};
|
use ide_db::defs::{Definition, NameRefClass};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, HasArgList, HasGenericArgs},
|
ast::{self, make, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs},
|
||||||
ted, AstNode,
|
syntax_editor::Position,
|
||||||
|
AstNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
||||||
AssistId("add_type_ascription", AssistKind::RefactorRewrite),
|
AssistId("add_type_ascription", AssistKind::RefactorRewrite),
|
||||||
"Add `: _` before assignment operator",
|
"Add `: _` before assignment operator",
|
||||||
ident.text_range(),
|
ident.text_range(),
|
||||||
|edit| {
|
|builder| {
|
||||||
let let_stmt = edit.make_mut(let_stmt);
|
let mut editor = builder.make_editor(let_stmt.syntax());
|
||||||
|
|
||||||
if let_stmt.semicolon_token().is_none() {
|
if let_stmt.semicolon_token().is_none() {
|
||||||
ted::append_child(let_stmt.syntax(), make::tokens::semicolon());
|
editor.insert(
|
||||||
|
Position::last_child_of(let_stmt.syntax()),
|
||||||
|
make::tokens::semicolon(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let placeholder_ty = make::ty_placeholder().clone_for_update();
|
let placeholder_ty = make::ty_placeholder().clone_for_update();
|
||||||
|
|
||||||
let_stmt.set_ty(Some(placeholder_ty.clone()));
|
if let Some(pat) = let_stmt.pat() {
|
||||||
|
let elements = vec![
|
||||||
if let Some(cap) = ctx.config.snippet_cap {
|
make::token(syntax::SyntaxKind::COLON).into(),
|
||||||
edit.add_placeholder_snippet(cap, placeholder_ty);
|
make::token(syntax::SyntaxKind::WHITESPACE).into(),
|
||||||
|
placeholder_ty.syntax().clone().into(),
|
||||||
|
];
|
||||||
|
editor.insert_all(Position::after(pat.syntax()), elements);
|
||||||
|
if let Some(cap) = ctx.config.snippet_cap {
|
||||||
|
editor.add_annotation(
|
||||||
|
placeholder_ty.syntax(),
|
||||||
|
builder.make_placeholder_snippet(cap),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)?
|
)?
|
||||||
} else {
|
} else {
|
||||||
|
@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
||||||
AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
|
AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
|
||||||
"Add `::<>`",
|
"Add `::<>`",
|
||||||
ident.text_range(),
|
ident.text_range(),
|
||||||
|edit| {
|
|builder| {
|
||||||
edit.trigger_parameter_hints();
|
builder.trigger_parameter_hints();
|
||||||
|
|
||||||
let new_arg_list = match turbofish_target {
|
let make = SyntaxFactory::new();
|
||||||
|
let mut editor = match &turbofish_target {
|
||||||
|
Either::Left(it) => builder.make_editor(it.syntax()),
|
||||||
|
Either::Right(it) => builder.make_editor(it.syntax()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let fish_head = get_fish_head(&make, number_of_arguments);
|
||||||
|
|
||||||
|
match turbofish_target {
|
||||||
Either::Left(path_segment) => {
|
Either::Left(path_segment) => {
|
||||||
edit.make_mut(path_segment).get_or_create_generic_arg_list()
|
if let Some(generic_arg_list) = path_segment.generic_arg_list() {
|
||||||
|
editor.replace(generic_arg_list.syntax(), fish_head.syntax());
|
||||||
|
} else {
|
||||||
|
editor.insert(
|
||||||
|
Position::last_child_of(path_segment.syntax()),
|
||||||
|
fish_head.syntax(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Either::Right(method_call) => {
|
Either::Right(method_call) => {
|
||||||
edit.make_mut(method_call).get_or_create_generic_arg_list()
|
if let Some(generic_arg_list) = method_call.generic_arg_list() {
|
||||||
|
editor.replace(generic_arg_list.syntax(), fish_head.syntax());
|
||||||
|
} else {
|
||||||
|
let position = if let Some(arg_list) = method_call.arg_list() {
|
||||||
|
Position::before(arg_list.syntax())
|
||||||
|
} else {
|
||||||
|
Position::last_child_of(method_call.syntax())
|
||||||
|
};
|
||||||
|
editor.insert(position, fish_head.syntax());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let fish_head = get_fish_head(number_of_arguments).clone_for_update();
|
|
||||||
|
|
||||||
// Note: we need to replace the `new_arg_list` instead of being able to use something like
|
|
||||||
// `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list`
|
|
||||||
// always creates a non-turbofish form generic arg list.
|
|
||||||
ted::replace(new_arg_list.syntax(), fish_head.syntax());
|
|
||||||
|
|
||||||
if let Some(cap) = ctx.config.snippet_cap {
|
if let Some(cap) = ctx.config.snippet_cap {
|
||||||
for arg in fish_head.generic_args() {
|
for arg in fish_head.generic_args() {
|
||||||
edit.add_placeholder_snippet(cap, arg)
|
editor.add_annotation(arg.syntax(), builder.make_placeholder_snippet(cap));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor.add_mappings(make.finish_with_mappings());
|
||||||
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will create a turbofish generic arg list corresponding to the number of arguments
|
/// This will create a turbofish generic arg list corresponding to the number of arguments
|
||||||
fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList {
|
fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList {
|
||||||
let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into());
|
let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into());
|
||||||
make::turbofish_generic_arg_list(args)
|
make.turbofish_generic_arg_list(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -107,4 +107,22 @@ impl SyntaxFactory {
|
||||||
|
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn turbofish_generic_arg_list(
|
||||||
|
&self,
|
||||||
|
args: impl IntoIterator<Item = ast::GenericArg> + Clone,
|
||||||
|
) -> ast::GenericArgList {
|
||||||
|
let ast = make::turbofish_generic_arg_list(args.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(
|
||||||
|
args.into_iter().map(|arg| arg.syntax().clone()),
|
||||||
|
ast.generic_args().map(|arg| arg.syntax().clone()),
|
||||||
|
);
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue