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