support rename after adding label
diff --git a/crates/ide-assists/src/handlers/add_label_to_loop.rs b/crates/ide-assists/src/handlers/add_label_to_loop.rs
index d2b9034..b84ad24 100644
--- a/crates/ide-assists/src/handlers/add_label_to_loop.rs
+++ b/crates/ide-assists/src/handlers/add_label_to_loop.rs
@@ -1,7 +1,14 @@
-use ide_db::syntax_helpers::node_ext::for_each_break_and_continue_expr;
+use ide_db::{
+ source_change::SourceChangeBuilder, syntax_helpers::node_ext::for_each_break_and_continue_expr,
+};
use syntax::{
- T,
- ast::{self, AstNode, HasLoopBody},
+ SyntaxToken, T,
+ ast::{
+ self, AstNode, HasLoopBody,
+ make::{self, tokens},
+ syntax_factory::SyntaxFactory,
+ },
+ syntax_editor::{Position, SyntaxEditor},
};
use crate::{AssistContext, AssistId, Assists};
@@ -21,9 +28,9 @@
// ->
// ```
// fn main() {
-// 'l: loop {
-// break 'l;
-// continue 'l;
+// ${1:'l}: loop {
+// break ${2:'l};
+// continue ${0:'l};
// }
// }
// ```
@@ -39,30 +46,56 @@
"Add Label",
loop_expr.syntax().text_range(),
|builder| {
- builder.insert(loop_kw.text_range().start(), "'l: ");
+ let make = SyntaxFactory::with_mappings();
+ let mut editor = builder.make_editor(loop_expr.syntax());
+
+ let label = make.lifetime("'l");
+ let elements = vec![
+ label.syntax().clone().into(),
+ make::token(T![:]).into(),
+ tokens::single_space().into(),
+ ];
+ editor.insert_all(Position::before(&loop_kw), elements);
+
+ if let Some(cap) = ctx.config.snippet_cap {
+ editor.add_annotation(label.syntax(), builder.make_placeholder_snippet(cap));
+ }
let loop_body = loop_expr.loop_body().and_then(|it| it.stmt_list());
- for_each_break_and_continue_expr(
- loop_expr.label(),
- loop_body,
- &mut |expr| match expr {
- ast::Expr::BreakExpr(break_expr) => {
- if let Some(break_token) = break_expr.break_token() {
- builder.insert(break_token.text_range().end(), " 'l")
- }
- }
- ast::Expr::ContinueExpr(continue_expr) => {
- if let Some(continue_token) = continue_expr.continue_token() {
- builder.insert(continue_token.text_range().end(), " 'l")
- }
- }
- _ => {}
- },
- );
+ for_each_break_and_continue_expr(loop_expr.label(), loop_body, &mut |expr| {
+ let token = match expr {
+ ast::Expr::BreakExpr(break_expr) => break_expr.break_token(),
+ ast::Expr::ContinueExpr(continue_expr) => continue_expr.continue_token(),
+ _ => return,
+ };
+ if let Some(token) = token {
+ insert_label_after_token(&mut editor, &make, &token, ctx, builder);
+ }
+ });
+
+ editor.add_mappings(make.finish_with_mappings());
+ builder.add_file_edits(ctx.vfs_file_id(), editor);
+ builder.rename();
},
)
}
+fn insert_label_after_token(
+ editor: &mut SyntaxEditor,
+ make: &SyntaxFactory,
+ token: &SyntaxToken,
+ ctx: &AssistContext<'_>,
+ builder: &mut SourceChangeBuilder,
+) {
+ let label = make.lifetime("'l");
+ let elements = vec![tokens::single_space().into(), label.syntax().clone().into()];
+ editor.insert_all(Position::after(token), elements);
+
+ if let Some(cap) = ctx.config.snippet_cap {
+ editor.add_annotation(label.syntax(), builder.make_placeholder_snippet(cap));
+ }
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
@@ -82,9 +115,9 @@
}"#,
r#"
fn main() {
- 'l: loop {
- break 'l;
- continue 'l;
+ ${1:'l}: loop {
+ break ${2:'l};
+ continue ${0:'l};
}
}"#,
);
@@ -107,9 +140,9 @@
}"#,
r#"
fn main() {
- 'l: loop {
- break 'l;
- continue 'l;
+ ${1:'l}: loop {
+ break ${2:'l};
+ continue ${0:'l};
loop {
break;
continue;
@@ -139,9 +172,9 @@
loop {
break;
continue;
- 'l: loop {
- break 'l;
- continue 'l;
+ ${1:'l}: loop {
+ break ${2:'l};
+ continue ${0:'l};
}
}
}"#,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 7f0836a..160b31a 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -183,9 +183,9 @@
"#####,
r#####"
fn main() {
- 'l: loop {
- break 'l;
- continue 'l;
+ ${1:'l}: loop {
+ break ${2:'l};
+ continue ${0:'l};
}
}
"#####,