mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 13:33:31 +00:00
Merge #4341
4341: Move target to AssistLabel r=matklad a=matklad
Target is used for assists sorting, so we need it before we compute
the action.
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
4de3c3eedc
36 changed files with 288 additions and 252 deletions
|
@ -94,9 +94,10 @@ impl<'a> AssistCtx<'a> {
|
|||
self,
|
||||
id: AssistId,
|
||||
label: impl Into<String>,
|
||||
target: TextRange,
|
||||
f: impl FnOnce(&mut ActionBuilder),
|
||||
) -> Option<Assist> {
|
||||
let label = AssistLabel::new(id, label.into(), None);
|
||||
let label = AssistLabel::new(id, label.into(), None, target);
|
||||
|
||||
let mut info = AssistInfo::new(label);
|
||||
if self.should_compute_edit {
|
||||
|
@ -152,9 +153,10 @@ impl<'a> AssistGroup<'a> {
|
|||
&mut self,
|
||||
id: AssistId,
|
||||
label: impl Into<String>,
|
||||
target: TextRange,
|
||||
f: impl FnOnce(&mut ActionBuilder),
|
||||
) {
|
||||
let label = AssistLabel::new(id, label.into(), Some(self.group.clone()));
|
||||
let label = AssistLabel::new(id, label.into(), Some(self.group.clone()), target);
|
||||
|
||||
let mut info = AssistInfo::new(label).with_group(self.group.clone());
|
||||
if self.ctx.should_compute_edit {
|
||||
|
@ -181,7 +183,6 @@ impl<'a> AssistGroup<'a> {
|
|||
pub(crate) struct ActionBuilder<'a, 'b> {
|
||||
edit: TextEditBuilder,
|
||||
cursor_position: Option<TextSize>,
|
||||
target: Option<TextRange>,
|
||||
file: AssistFile,
|
||||
ctx: &'a AssistCtx<'b>,
|
||||
}
|
||||
|
@ -191,7 +192,6 @@ impl<'a, 'b> ActionBuilder<'a, 'b> {
|
|||
Self {
|
||||
edit: TextEditBuilder::default(),
|
||||
cursor_position: None,
|
||||
target: None,
|
||||
file: AssistFile::default(),
|
||||
ctx,
|
||||
}
|
||||
|
@ -237,14 +237,6 @@ impl<'a, 'b> ActionBuilder<'a, 'b> {
|
|||
self.cursor_position = Some(offset)
|
||||
}
|
||||
|
||||
/// Specify that the assist should be active withing the `target` range.
|
||||
///
|
||||
/// Target ranges are used to sort assists: the smaller the target range,
|
||||
/// the more specific assist is, and so it should be sorted first.
|
||||
pub(crate) fn target(&mut self, target: TextRange) {
|
||||
self.target = Some(target)
|
||||
}
|
||||
|
||||
/// Get access to the raw `TextEditBuilder`.
|
||||
pub(crate) fn text_edit_builder(&mut self) -> &mut TextEditBuilder {
|
||||
&mut self.edit
|
||||
|
@ -267,7 +259,6 @@ impl<'a, 'b> ActionBuilder<'a, 'b> {
|
|||
AssistAction {
|
||||
edit: self.edit.finish(),
|
||||
cursor_position: self.cursor_position,
|
||||
target: self.target,
|
||||
file: self.file,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,9 +48,8 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> {
|
|||
let label =
|
||||
format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name);
|
||||
|
||||
ctx.add_assist(AssistId("add_custom_impl"), label, |edit| {
|
||||
edit.target(attr.syntax().text_range());
|
||||
|
||||
let target = attr.syntax().text_range();
|
||||
ctx.add_assist(AssistId("add_custom_impl"), label, target, |edit| {
|
||||
let new_attr_input = input
|
||||
.syntax()
|
||||
.descendants_with_tokens()
|
||||
|
|
|
@ -27,7 +27,8 @@ use crate::{Assist, AssistCtx, AssistId};
|
|||
pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> {
|
||||
let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
|
||||
let node_start = derive_insertion_offset(&nominal)?;
|
||||
ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", |edit| {
|
||||
let target = nominal.syntax().text_range();
|
||||
ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", target, |edit| {
|
||||
let derive_attr = nominal
|
||||
.attrs()
|
||||
.filter_map(|x| x.as_simple_call())
|
||||
|
@ -41,7 +42,6 @@ pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> {
|
|||
}
|
||||
Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'),
|
||||
};
|
||||
edit.target(nominal.syntax().text_range());
|
||||
edit.set_cursor(offset)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -62,8 +62,8 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> {
|
|||
ctx.add_assist(
|
||||
AssistId("add_explicit_type"),
|
||||
format!("Insert explicit type '{}'", new_type_string),
|
||||
pat_range,
|
||||
|edit| {
|
||||
edit.target(pat_range);
|
||||
if let Some(ascribed_ty) = ascribed_ty {
|
||||
edit.replace(ascribed_ty.syntax().text_range(), new_type_string);
|
||||
} else {
|
||||
|
|
|
@ -47,9 +47,11 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let target = variant.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("add_from_impl_for_enum"),
|
||||
"Add From impl for this enum variant",
|
||||
target,
|
||||
|edit| {
|
||||
let start_offset = variant.parent_enum().syntax().text_range().end();
|
||||
let mut buf = String::new();
|
||||
|
|
|
@ -57,9 +57,9 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
|
|||
|
||||
let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
|
||||
|
||||
ctx.add_assist(AssistId("add_function"), "Add function", |edit| {
|
||||
edit.target(call.syntax().text_range());
|
||||
|
||||
let target = call.syntax().text_range();
|
||||
// TODO: assert here?
|
||||
ctx.add_assist(AssistId("add_function"), "Add function", target, |edit| {
|
||||
if let Some(function_template) = function_builder.render() {
|
||||
edit.set_file(function_template.file);
|
||||
edit.set_cursor(function_template.cursor_offset);
|
||||
|
|
|
@ -28,33 +28,40 @@ use crate::{Assist, AssistCtx, AssistId};
|
|||
pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
|
||||
let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
|
||||
let name = nominal.name()?;
|
||||
ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| {
|
||||
edit.target(nominal.syntax().text_range());
|
||||
let type_params = nominal.type_param_list();
|
||||
let start_offset = nominal.syntax().text_range().end();
|
||||
let mut buf = String::new();
|
||||
buf.push_str("\n\nimpl");
|
||||
if let Some(type_params) = &type_params {
|
||||
format_to!(buf, "{}", type_params.syntax());
|
||||
}
|
||||
buf.push_str(" ");
|
||||
buf.push_str(name.text().as_str());
|
||||
if let Some(type_params) = type_params {
|
||||
let lifetime_params = type_params
|
||||
.lifetime_params()
|
||||
.filter_map(|it| it.lifetime_token())
|
||||
.map(|it| it.text().clone());
|
||||
let type_params =
|
||||
type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
|
||||
let target = nominal.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("add_impl"),
|
||||
format!("Implement {}", name.text().as_str()),
|
||||
target,
|
||||
|edit| {
|
||||
let type_params = nominal.type_param_list();
|
||||
let start_offset = nominal.syntax().text_range().end();
|
||||
let mut buf = String::new();
|
||||
buf.push_str("\n\nimpl");
|
||||
if let Some(type_params) = &type_params {
|
||||
format_to!(buf, "{}", type_params.syntax());
|
||||
}
|
||||
buf.push_str(" ");
|
||||
buf.push_str(name.text().as_str());
|
||||
if let Some(type_params) = type_params {
|
||||
let lifetime_params = type_params
|
||||
.lifetime_params()
|
||||
.filter_map(|it| it.lifetime_token())
|
||||
.map(|it| it.text().clone());
|
||||
let type_params = type_params
|
||||
.type_params()
|
||||
.filter_map(|it| it.name())
|
||||
.map(|it| it.text().clone());
|
||||
|
||||
let generic_params = lifetime_params.chain(type_params).sep_by(", ");
|
||||
format_to!(buf, "<{}>", generic_params)
|
||||
}
|
||||
buf.push_str(" {\n");
|
||||
edit.set_cursor(start_offset + TextSize::of(&buf));
|
||||
buf.push_str("\n}");
|
||||
edit.insert(start_offset, buf);
|
||||
})
|
||||
let generic_params = lifetime_params.chain(type_params).sep_by(", ");
|
||||
format_to!(buf, "<{}>", generic_params)
|
||||
}
|
||||
buf.push_str(" {\n");
|
||||
edit.set_cursor(start_offset + TextSize::of(&buf));
|
||||
buf.push_str("\n}");
|
||||
edit.insert(start_offset, buf);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -107,10 +107,10 @@ fn add_missing_impl_members_inner(
|
|||
label: &'static str,
|
||||
) -> Option<Assist> {
|
||||
let _p = ra_prof::profile("add_missing_impl_members_inner");
|
||||
let impl_node = ctx.find_node_at_offset::<ast::ImplDef>()?;
|
||||
let impl_item_list = impl_node.item_list()?;
|
||||
let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?;
|
||||
let impl_item_list = impl_def.item_list()?;
|
||||
|
||||
let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?;
|
||||
let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
|
||||
|
||||
let def_name = |item: &ast::AssocItem| -> Option<SmolStr> {
|
||||
match item {
|
||||
|
@ -121,7 +121,7 @@ fn add_missing_impl_members_inner(
|
|||
.map(|it| it.text().clone())
|
||||
};
|
||||
|
||||
let missing_items = get_missing_assoc_items(&ctx.sema, &impl_node)
|
||||
let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def)
|
||||
.iter()
|
||||
.map(|i| match i {
|
||||
hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value),
|
||||
|
@ -143,13 +143,13 @@ fn add_missing_impl_members_inner(
|
|||
}
|
||||
|
||||
let sema = ctx.sema;
|
||||
|
||||
ctx.add_assist(AssistId(assist_id), label, |edit| {
|
||||
let target = impl_def.syntax().text_range();
|
||||
ctx.add_assist(AssistId(assist_id), label, target, |edit| {
|
||||
let n_existing_items = impl_item_list.assoc_items().count();
|
||||
let source_scope = sema.scope_for_def(trait_);
|
||||
let target_scope = sema.scope(impl_item_list.syntax());
|
||||
let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
|
||||
.or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_node));
|
||||
.or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def));
|
||||
let items = missing_items
|
||||
.into_iter()
|
||||
.map(|it| ast_transform::apply(&*ast_transform, it))
|
||||
|
|
|
@ -41,9 +41,8 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
|
|||
// Return early if we've found an existing new fn
|
||||
let impl_def = find_struct_impl(&ctx, &strukt)?;
|
||||
|
||||
ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| {
|
||||
edit.target(strukt.syntax().text_range());
|
||||
|
||||
let target = strukt.syntax().text_range();
|
||||
ctx.add_assist(AssistId("add_new"), "Add default constructor", target, |edit| {
|
||||
let mut buf = String::with_capacity(512);
|
||||
|
||||
if impl_def.is_some() {
|
||||
|
|
|
@ -39,8 +39,7 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> {
|
|||
let rhs_range = rhs.syntax().text_range();
|
||||
let not_rhs = invert_boolean_expression(rhs);
|
||||
|
||||
ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", |edit| {
|
||||
edit.target(op_range);
|
||||
ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| {
|
||||
edit.replace(op_range, opposite_op);
|
||||
edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
|
||||
edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
|
||||
|
|
|
@ -48,8 +48,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
|
|||
let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range;
|
||||
let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message());
|
||||
for import in proposed_imports {
|
||||
group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
|
||||
edit.target(range);
|
||||
group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), range, |edit| {
|
||||
insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -66,11 +66,15 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
};
|
||||
|
||||
ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| {
|
||||
edit.target(target);
|
||||
edit.insert(offset, "pub(crate) ");
|
||||
edit.set_cursor(offset);
|
||||
})
|
||||
ctx.add_assist(
|
||||
AssistId("change_visibility"),
|
||||
"Change visibility to pub(crate)",
|
||||
target,
|
||||
|edit| {
|
||||
edit.insert(offset, "pub(crate) ");
|
||||
edit.set_cursor(offset);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn vis_offset(node: &SyntaxNode) -> TextSize {
|
||||
|
@ -86,22 +90,28 @@ fn vis_offset(node: &SyntaxNode) -> TextSize {
|
|||
|
||||
fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> {
|
||||
if vis.syntax().text() == "pub" {
|
||||
let target = vis.syntax().text_range();
|
||||
return ctx.add_assist(
|
||||
AssistId("change_visibility"),
|
||||
"Change Visibility to pub(crate)",
|
||||
target,
|
||||
|edit| {
|
||||
edit.target(vis.syntax().text_range());
|
||||
edit.replace(vis.syntax().text_range(), "pub(crate)");
|
||||
edit.set_cursor(vis.syntax().text_range().start())
|
||||
},
|
||||
);
|
||||
}
|
||||
if vis.syntax().text() == "pub(crate)" {
|
||||
return ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub", |edit| {
|
||||
edit.target(vis.syntax().text_range());
|
||||
edit.replace(vis.syntax().text_range(), "pub");
|
||||
edit.set_cursor(vis.syntax().text_range().start());
|
||||
});
|
||||
let target = vis.syntax().text_range();
|
||||
return ctx.add_assist(
|
||||
AssistId("change_visibility"),
|
||||
"Change visibility to pub",
|
||||
target,
|
||||
|edit| {
|
||||
edit.replace(vis.syntax().text_range(), "pub");
|
||||
edit.set_cursor(vis.syntax().text_range().start());
|
||||
},
|
||||
);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -95,89 +95,94 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> {
|
|||
then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
|
||||
let cursor_position = ctx.frange.range.start();
|
||||
|
||||
ctx.add_assist(AssistId("convert_to_guarded_return"), "Convert to guarded return", |edit| {
|
||||
let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
|
||||
let new_block = match if_let_pat {
|
||||
None => {
|
||||
// If.
|
||||
let new_expr = {
|
||||
let then_branch =
|
||||
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
||||
let cond = invert_boolean_expression(cond_expr);
|
||||
let e = make::expr_if(make::condition(cond, None), then_branch);
|
||||
if_indent_level.increase_indent(e)
|
||||
};
|
||||
replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
|
||||
}
|
||||
Some((path, bound_ident)) => {
|
||||
// If-let.
|
||||
let match_expr = {
|
||||
let happy_arm = {
|
||||
let pat = make::tuple_struct_pat(
|
||||
path,
|
||||
once(make::bind_pat(make::name("it")).into()),
|
||||
);
|
||||
let expr = {
|
||||
let name_ref = make::name_ref("it");
|
||||
let segment = make::path_segment(name_ref);
|
||||
let path = make::path_unqualified(segment);
|
||||
make::expr_path(path)
|
||||
let target = if_expr.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("convert_to_guarded_return"),
|
||||
"Convert to guarded return",
|
||||
target,
|
||||
|edit| {
|
||||
let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
|
||||
let new_block = match if_let_pat {
|
||||
None => {
|
||||
// If.
|
||||
let new_expr = {
|
||||
let then_branch =
|
||||
make::block_expr(once(make::expr_stmt(early_expression).into()), None);
|
||||
let cond = invert_boolean_expression(cond_expr);
|
||||
let e = make::expr_if(make::condition(cond, None), then_branch);
|
||||
if_indent_level.increase_indent(e)
|
||||
};
|
||||
replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
|
||||
}
|
||||
Some((path, bound_ident)) => {
|
||||
// If-let.
|
||||
let match_expr = {
|
||||
let happy_arm = {
|
||||
let pat = make::tuple_struct_pat(
|
||||
path,
|
||||
once(make::bind_pat(make::name("it")).into()),
|
||||
);
|
||||
let expr = {
|
||||
let name_ref = make::name_ref("it");
|
||||
let segment = make::path_segment(name_ref);
|
||||
let path = make::path_unqualified(segment);
|
||||
make::expr_path(path)
|
||||
};
|
||||
make::match_arm(once(pat.into()), expr)
|
||||
};
|
||||
make::match_arm(once(pat.into()), expr)
|
||||
|
||||
let sad_arm = make::match_arm(
|
||||
// FIXME: would be cool to use `None` or `Err(_)` if appropriate
|
||||
once(make::placeholder_pat().into()),
|
||||
early_expression,
|
||||
);
|
||||
|
||||
make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
|
||||
};
|
||||
|
||||
let sad_arm = make::match_arm(
|
||||
// FIXME: would be cool to use `None` or `Err(_)` if appropriate
|
||||
once(make::placeholder_pat().into()),
|
||||
early_expression,
|
||||
let let_stmt = make::let_stmt(
|
||||
make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
|
||||
Some(match_expr),
|
||||
);
|
||||
let let_stmt = if_indent_level.increase_indent(let_stmt);
|
||||
replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
|
||||
}
|
||||
};
|
||||
edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
|
||||
edit.set_cursor(cursor_position);
|
||||
|
||||
make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
|
||||
};
|
||||
|
||||
let let_stmt = make::let_stmt(
|
||||
make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
|
||||
Some(match_expr),
|
||||
fn replace(
|
||||
new_expr: &SyntaxNode,
|
||||
then_block: &ast::BlockExpr,
|
||||
parent_block: &ast::BlockExpr,
|
||||
if_expr: &ast::IfExpr,
|
||||
) -> SyntaxNode {
|
||||
let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
|
||||
let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
|
||||
let end_of_then =
|
||||
if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
|
||||
end_of_then.prev_sibling_or_token().unwrap()
|
||||
} else {
|
||||
end_of_then
|
||||
};
|
||||
let mut then_statements = new_expr.children_with_tokens().chain(
|
||||
then_block_items
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.skip(1)
|
||||
.take_while(|i| *i != end_of_then),
|
||||
);
|
||||
let let_stmt = if_indent_level.increase_indent(let_stmt);
|
||||
replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
|
||||
replace_children(
|
||||
&parent_block.syntax(),
|
||||
RangeInclusive::new(
|
||||
if_expr.clone().syntax().clone().into(),
|
||||
if_expr.syntax().clone().into(),
|
||||
),
|
||||
&mut then_statements,
|
||||
)
|
||||
}
|
||||
};
|
||||
edit.target(if_expr.syntax().text_range());
|
||||
edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap());
|
||||
edit.set_cursor(cursor_position);
|
||||
|
||||
fn replace(
|
||||
new_expr: &SyntaxNode,
|
||||
then_block: &ast::BlockExpr,
|
||||
parent_block: &ast::BlockExpr,
|
||||
if_expr: &ast::IfExpr,
|
||||
) -> SyntaxNode {
|
||||
let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
|
||||
let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
|
||||
let end_of_then =
|
||||
if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
|
||||
end_of_then.prev_sibling_or_token().unwrap()
|
||||
} else {
|
||||
end_of_then
|
||||
};
|
||||
let mut then_statements = new_expr.children_with_tokens().chain(
|
||||
then_block_items
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.skip(1)
|
||||
.take_while(|i| *i != end_of_then),
|
||||
);
|
||||
replace_children(
|
||||
&parent_block.syntax(),
|
||||
RangeInclusive::new(
|
||||
if_expr.clone().syntax().clone().into(),
|
||||
if_expr.syntax().clone().into(),
|
||||
),
|
||||
&mut then_statements,
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -92,10 +92,9 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
}
|
||||
|
||||
ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", |edit| {
|
||||
let target = match_expr.syntax().text_range();
|
||||
ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", target, |edit| {
|
||||
let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms);
|
||||
|
||||
edit.target(match_expr.syntax().text_range());
|
||||
edit.set_cursor(expr.syntax().text_range().start());
|
||||
edit.replace_ast(match_arm_list, new_arm_list);
|
||||
})
|
||||
|
|
|
@ -33,8 +33,7 @@ pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
}
|
||||
|
||||
ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", |edit| {
|
||||
edit.target(op_range);
|
||||
ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| {
|
||||
if let FlipAction::FlipAndReplaceOp(new_op) = action {
|
||||
edit.replace(op_range, new_op);
|
||||
}
|
||||
|
|
|
@ -28,8 +28,7 @@ pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
}
|
||||
|
||||
ctx.add_assist(AssistId("flip_comma"), "Flip comma", |edit| {
|
||||
edit.target(comma.text_range());
|
||||
ctx.add_assist(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| {
|
||||
edit.replace(prev.text_range(), next.to_string());
|
||||
edit.replace(next.text_range(), prev.to_string());
|
||||
})
|
||||
|
|
|
@ -32,8 +32,8 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> {
|
|||
non_trivia_sibling(plus.clone().into(), Direction::Next)?,
|
||||
);
|
||||
|
||||
ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", |edit| {
|
||||
edit.target(plus.text_range());
|
||||
let target = plus.text_range();
|
||||
ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| {
|
||||
edit.replace(before.text_range(), after.to_string());
|
||||
edit.replace(after.text_range(), before.to_string());
|
||||
})
|
||||
|
|
|
@ -106,9 +106,11 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
|
|||
let init_str = initializer_expr.syntax().text().to_string();
|
||||
let init_in_paren = format!("({})", &init_str);
|
||||
|
||||
let target = bind_pat.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("inline_local_variable"),
|
||||
"Inline variable",
|
||||
target,
|
||||
move |edit: &mut ActionBuilder| {
|
||||
edit.delete(delete_range);
|
||||
for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
|
||||
|
|
|
@ -42,7 +42,8 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
|
|||
if indent.kind() != WHITESPACE {
|
||||
return None;
|
||||
}
|
||||
ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", move |edit| {
|
||||
let target = expr.syntax().text_range();
|
||||
ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", target, move |edit| {
|
||||
let mut buf = String::new();
|
||||
|
||||
let cursor_offset = if wrap_in_block {
|
||||
|
@ -79,7 +80,6 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
|
|||
buf.push_str(text);
|
||||
}
|
||||
|
||||
edit.target(expr.syntax().text_range());
|
||||
edit.replace(expr.syntax().text_range(), "var_name".to_string());
|
||||
edit.insert(anchor_stmt.text_range().start(), buf);
|
||||
if wrap_in_block {
|
||||
|
|
|
@ -47,8 +47,7 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
|
|||
let else_node = else_block.syntax();
|
||||
let else_range = else_node.text_range();
|
||||
let then_range = then_node.text_range();
|
||||
return ctx.add_assist(AssistId("invert_if"), "Invert if", |edit| {
|
||||
edit.target(if_range);
|
||||
return ctx.add_assist(AssistId("invert_if"), "Invert if", if_range, |edit| {
|
||||
edit.replace(cond_range, flip_cond.syntax().text());
|
||||
edit.replace(else_range, then_node.text());
|
||||
edit.replace(then_range, else_node.text());
|
||||
|
|
|
@ -52,7 +52,8 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> {
|
|||
}
|
||||
};
|
||||
|
||||
ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| {
|
||||
let target = tree.syntax().text_range();
|
||||
ctx.add_assist(AssistId("merge_imports"), "Merge imports", target, |edit| {
|
||||
edit.rewrite(rewriter);
|
||||
// FIXME: we only need because our diff is imprecise
|
||||
edit.set_cursor(offset);
|
||||
|
|
|
@ -70,7 +70,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
}
|
||||
|
||||
ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", |edit| {
|
||||
ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| {
|
||||
let pats = if arms_to_merge.iter().any(contains_placeholder) {
|
||||
"_".into()
|
||||
} else {
|
||||
|
@ -87,7 +87,6 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
|
|||
let start = arms_to_merge.first().unwrap().syntax().text_range().start();
|
||||
let end = arms_to_merge.last().unwrap().syntax().text_range().end();
|
||||
|
||||
edit.target(current_text_range);
|
||||
edit.set_cursor(match cursor_pos {
|
||||
CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset,
|
||||
CursorPos::InPat(offset) => offset,
|
||||
|
|
|
@ -49,30 +49,37 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> {
|
|||
}
|
||||
};
|
||||
|
||||
ctx.add_assist(AssistId("move_bounds_to_where_clause"), "Move to where clause", |edit| {
|
||||
let new_params = type_param_list
|
||||
.type_params()
|
||||
.filter(|it| it.type_bound_list().is_some())
|
||||
.map(|type_param| {
|
||||
let without_bounds = type_param.remove_bounds();
|
||||
(type_param, without_bounds)
|
||||
});
|
||||
let target = type_param_list.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("move_bounds_to_where_clause"),
|
||||
"Move to where clause",
|
||||
target,
|
||||
|edit| {
|
||||
let new_params = type_param_list
|
||||
.type_params()
|
||||
.filter(|it| it.type_bound_list().is_some())
|
||||
.map(|type_param| {
|
||||
let without_bounds = type_param.remove_bounds();
|
||||
(type_param, without_bounds)
|
||||
});
|
||||
|
||||
let new_type_param_list = type_param_list.replace_descendants(new_params);
|
||||
edit.replace_ast(type_param_list.clone(), new_type_param_list);
|
||||
let new_type_param_list = type_param_list.replace_descendants(new_params);
|
||||
edit.replace_ast(type_param_list.clone(), new_type_param_list);
|
||||
|
||||
let where_clause = {
|
||||
let predicates = type_param_list.type_params().filter_map(build_predicate);
|
||||
make::where_clause(predicates)
|
||||
};
|
||||
let where_clause = {
|
||||
let predicates = type_param_list.type_params().filter_map(build_predicate);
|
||||
make::where_clause(predicates)
|
||||
};
|
||||
|
||||
let to_insert = match anchor.prev_sibling_or_token() {
|
||||
Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()),
|
||||
_ => format!(" {}", where_clause.syntax()),
|
||||
};
|
||||
edit.insert(anchor.text_range().start(), to_insert);
|
||||
edit.target(type_param_list.syntax().text_range());
|
||||
})
|
||||
let to_insert = match anchor.prev_sibling_or_token() {
|
||||
Some(ref elem) if elem.kind() == WHITESPACE => {
|
||||
format!("{} ", where_clause.syntax())
|
||||
}
|
||||
_ => format!(" {}", where_clause.syntax()),
|
||||
};
|
||||
edit.insert(anchor.text_range().start(), to_insert);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
|
||||
|
|
|
@ -40,8 +40,8 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
|
|||
let arm_expr = match_arm.expr()?;
|
||||
let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text());
|
||||
|
||||
ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", |edit| {
|
||||
edit.target(guard.syntax().text_range());
|
||||
let target = guard.syntax().text_range();
|
||||
ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| {
|
||||
let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) {
|
||||
Some(tok) => {
|
||||
if ast::Whitespace::cast(tok.clone()).is_some() {
|
||||
|
@ -108,11 +108,12 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
|
|||
|
||||
let buf = format!(" if {}", cond.syntax().text());
|
||||
|
||||
let target = if_expr.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("move_arm_cond_to_match_guard"),
|
||||
"Move condition to match guard",
|
||||
target,
|
||||
|edit| {
|
||||
edit.target(if_expr.syntax().text_range());
|
||||
let then_only_expr = then_block.statements().next().is_none();
|
||||
|
||||
match &then_block.expr() {
|
||||
|
|
|
@ -25,8 +25,8 @@ use crate::{Assist, AssistCtx, AssistId};
|
|||
pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> {
|
||||
let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?;
|
||||
let value = token.value()?;
|
||||
ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", |edit| {
|
||||
edit.target(token.syntax().text_range());
|
||||
let target = token.syntax().text_range();
|
||||
ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| {
|
||||
let max_hash_streak = count_hashes(&value);
|
||||
let mut hashes = String::with_capacity(max_hash_streak + 1);
|
||||
for _ in 0..hashes.capacity() {
|
||||
|
@ -54,8 +54,8 @@ pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> {
|
|||
pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> {
|
||||
let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?;
|
||||
let value = token.value()?;
|
||||
ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", |edit| {
|
||||
edit.target(token.syntax().text_range());
|
||||
let target = token.syntax().text_range();
|
||||
ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| {
|
||||
// parse inside string to escape `"`
|
||||
let escaped = value.escape_default().to_string();
|
||||
edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped));
|
||||
|
@ -79,8 +79,8 @@ pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> {
|
|||
// ```
|
||||
pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> {
|
||||
let token = ctx.find_token_at_offset(RAW_STRING)?;
|
||||
ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| {
|
||||
edit.target(token.text_range());
|
||||
let target = token.text_range();
|
||||
ctx.add_assist(AssistId("add_hash"), "Add # to raw string", target, |edit| {
|
||||
edit.insert(token.text_range().start() + TextSize::of('r'), "#");
|
||||
edit.insert(token.text_range().end(), "#");
|
||||
})
|
||||
|
@ -108,8 +108,8 @@ pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> {
|
|||
// no hash to remove
|
||||
return None;
|
||||
}
|
||||
ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", |edit| {
|
||||
edit.target(token.text_range());
|
||||
let target = token.text_range();
|
||||
ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| {
|
||||
let result = &text[2..text.len() - 1];
|
||||
let result = if result.starts_with('\"') {
|
||||
// FIXME: this logic is wrong, not only the last has has to handled specially
|
||||
|
|
|
@ -57,8 +57,8 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> {
|
|||
text.slice(without_parens).to_string()
|
||||
};
|
||||
|
||||
ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", |edit| {
|
||||
edit.target(macro_call.syntax().text_range());
|
||||
let target = macro_call.syntax().text_range();
|
||||
ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| {
|
||||
edit.replace(macro_range, macro_content);
|
||||
edit.set_cursor(cursor_pos);
|
||||
})
|
||||
|
|
|
@ -25,7 +25,8 @@ pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> {
|
|||
_ => mut_token.text_range().end(),
|
||||
};
|
||||
|
||||
ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", |edit| {
|
||||
let target = mut_token.text_range();
|
||||
ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| {
|
||||
edit.set_cursor(delete_from);
|
||||
edit.delete(TextRange::new(delete_from, delete_to));
|
||||
})
|
||||
|
|
|
@ -50,11 +50,11 @@ fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
|
|||
return None;
|
||||
}
|
||||
|
||||
ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
|
||||
let target = record.syntax().text_range();
|
||||
ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", target, |edit| {
|
||||
for (old, new) in fields.iter().zip(&sorted_fields) {
|
||||
algo::diff(old, new).into_text_edit(edit.text_edit_builder());
|
||||
}
|
||||
edit.target(record.syntax().text_range())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -44,30 +44,35 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
|
|||
};
|
||||
|
||||
let sema = ctx.sema;
|
||||
ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| {
|
||||
let match_expr = {
|
||||
let then_arm = {
|
||||
let then_expr = unwrap_trivial_block(then_block);
|
||||
make::match_arm(vec![pat.clone()], then_expr)
|
||||
let target = if_expr.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("replace_if_let_with_match"),
|
||||
"Replace with match",
|
||||
target,
|
||||
move |edit| {
|
||||
let match_expr = {
|
||||
let then_arm = {
|
||||
let then_expr = unwrap_trivial_block(then_block);
|
||||
make::match_arm(vec![pat.clone()], then_expr)
|
||||
};
|
||||
let else_arm = {
|
||||
let pattern = sema
|
||||
.type_of_pat(&pat)
|
||||
.and_then(|ty| TryEnum::from_ty(sema, &ty))
|
||||
.map(|it| it.sad_pattern())
|
||||
.unwrap_or_else(|| make::placeholder_pat().into());
|
||||
let else_expr = unwrap_trivial_block(else_block);
|
||||
make::match_arm(vec![pattern], else_expr)
|
||||
};
|
||||
make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
|
||||
};
|
||||
let else_arm = {
|
||||
let pattern = sema
|
||||
.type_of_pat(&pat)
|
||||
.and_then(|ty| TryEnum::from_ty(sema, &ty))
|
||||
.map(|it| it.sad_pattern())
|
||||
.unwrap_or_else(|| make::placeholder_pat().into());
|
||||
let else_expr = unwrap_trivial_block(else_block);
|
||||
make::match_arm(vec![pattern], else_expr)
|
||||
};
|
||||
make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
|
||||
};
|
||||
|
||||
let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr);
|
||||
let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr);
|
||||
|
||||
edit.target(if_expr.syntax().text_range());
|
||||
edit.set_cursor(if_expr.syntax().text_range().start());
|
||||
edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
|
||||
})
|
||||
edit.set_cursor(if_expr.syntax().text_range().start());
|
||||
edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -47,7 +47,8 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> {
|
|||
let ty = ctx.sema.type_of_expr(&init)?;
|
||||
let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case());
|
||||
|
||||
ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| {
|
||||
let target = let_kw.text_range();
|
||||
ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| {
|
||||
let with_placeholder: ast::Pat = match happy_variant {
|
||||
None => make::placeholder_pat().into(),
|
||||
Some(var_name) => make::tuple_struct_pat(
|
||||
|
@ -67,7 +68,6 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> {
|
|||
let stmt = stmt.replace_descendant(placeholder.into(), original_pat);
|
||||
|
||||
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
||||
edit.target(let_kw.text_range());
|
||||
edit.set_cursor(target_offset);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -33,9 +33,11 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist>
|
|||
return None;
|
||||
}
|
||||
|
||||
let target = path.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("replace_qualified_name_with_use"),
|
||||
"Replace qualified path with use",
|
||||
target,
|
||||
|edit| {
|
||||
let path_to_import = hir_path.mod_path().clone();
|
||||
insert_use_statement(path.syntax(), &path_to_import, edit);
|
||||
|
|
|
@ -38,26 +38,32 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> {
|
|||
let caller = method_call.expr()?;
|
||||
let ty = ctx.sema.type_of_expr(&caller)?;
|
||||
let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case();
|
||||
let target = method_call.syntax().text_range();
|
||||
ctx.add_assist(
|
||||
AssistId("replace_unwrap_with_match"),
|
||||
"Replace unwrap with match",
|
||||
target,
|
||||
|edit| {
|
||||
let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
|
||||
let it = make::bind_pat(make::name("a")).into();
|
||||
let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
|
||||
|
||||
ctx.add_assist(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", |edit| {
|
||||
let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
|
||||
let it = make::bind_pat(make::name("a")).into();
|
||||
let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
|
||||
let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
|
||||
let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
|
||||
|
||||
let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
|
||||
let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
|
||||
let unreachable_call = make::unreachable_macro_call().into();
|
||||
let err_arm =
|
||||
make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
|
||||
|
||||
let unreachable_call = make::unreachable_macro_call().into();
|
||||
let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
|
||||
let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
|
||||
let match_expr = make::expr_match(caller.clone(), match_arm_list);
|
||||
let match_expr =
|
||||
IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
|
||||
|
||||
let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
|
||||
let match_expr = make::expr_match(caller.clone(), match_arm_list);
|
||||
let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
|
||||
|
||||
edit.target(method_call.syntax().text_range());
|
||||
edit.set_cursor(caller.syntax().text_range().start());
|
||||
edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
|
||||
})
|
||||
edit.set_cursor(caller.syntax().text_range().start());
|
||||
edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -28,8 +28,8 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> {
|
|||
}
|
||||
let cursor = ctx.frange.range.start();
|
||||
|
||||
ctx.add_assist(AssistId("split_import"), "Split import", |edit| {
|
||||
edit.target(colon_colon.text_range());
|
||||
let target = colon_colon.text_range();
|
||||
ctx.add_assist(AssistId("split_import"), "Split import", target, |edit| {
|
||||
edit.replace_ast(use_tree, new_tree);
|
||||
edit.set_cursor(cursor);
|
||||
})
|
||||
|
|
|
@ -57,9 +57,9 @@ pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> {
|
|||
}
|
||||
};
|
||||
|
||||
ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| {
|
||||
let target = expr_to_unwrap.syntax().text_range();
|
||||
ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", target, |edit| {
|
||||
edit.set_cursor(expr.syntax().text_range().start());
|
||||
edit.target(expr_to_unwrap.syntax().text_range());
|
||||
|
||||
let pat_start: &[_] = &[' ', '{', '\n'];
|
||||
let expr_to_unwrap = expr_to_unwrap.to_string();
|
||||
|
|
|
@ -36,16 +36,24 @@ pub struct AssistLabel {
|
|||
/// Short description of the assist, as shown in the UI.
|
||||
pub label: String,
|
||||
pub group: Option<GroupLabel>,
|
||||
/// Target ranges are used to sort assists: the smaller the target range,
|
||||
/// the more specific assist is, and so it should be sorted first.
|
||||
pub target: TextRange,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GroupLabel(pub String);
|
||||
|
||||
impl AssistLabel {
|
||||
pub(crate) fn new(id: AssistId, label: String, group: Option<GroupLabel>) -> AssistLabel {
|
||||
pub(crate) fn new(
|
||||
id: AssistId,
|
||||
label: String,
|
||||
group: Option<GroupLabel>,
|
||||
target: TextRange,
|
||||
) -> AssistLabel {
|
||||
// FIXME: make fields private, so that this invariant can't be broken
|
||||
assert!(label.starts_with(|c: char| c.is_uppercase()));
|
||||
AssistLabel { id, label, group }
|
||||
AssistLabel { id, label, group, target }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,8 +61,6 @@ impl AssistLabel {
|
|||
pub struct AssistAction {
|
||||
pub edit: TextEdit,
|
||||
pub cursor_position: Option<TextSize>,
|
||||
// FIXME: This belongs to `AssistLabel`
|
||||
pub target: Option<TextRange>,
|
||||
pub file: AssistFile,
|
||||
}
|
||||
|
||||
|
@ -104,7 +110,7 @@ pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssi
|
|||
.flat_map(|it| it.0)
|
||||
.map(|it| it.into_resolved().unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
a.sort_by_key(|it| it.action.target.map_or(TextSize::from(!0u32), |it| it.len()));
|
||||
a.sort_by_key(|it| it.label.target.len());
|
||||
a
|
||||
}
|
||||
|
||||
|
|
|
@ -118,8 +118,7 @@ fn check(assist: Handler, before: &str, expected: ExpectedResult) {
|
|||
assert_eq_text!(after, &actual);
|
||||
}
|
||||
(Some(assist), ExpectedResult::Target(target)) => {
|
||||
let action = assist.0[0].action.clone().unwrap();
|
||||
let range = action.target.expect("expected target on action");
|
||||
let range = assist.0[0].label.target;
|
||||
assert_eq_text!(&text_without_caret[range], target);
|
||||
}
|
||||
(Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
|
||||
|
|
Loading…
Reference in a new issue