]> git.lizzy.rs Git - rust.git/commitdiff
ra_assists: assist "providers" can produce multiple assists
authorAndrea Pretto <eulerdisk@gmail.com>
Mon, 11 Feb 2019 17:07:21 +0000 (18:07 +0100)
committerAndrea Pretto <eulerdisk@gmail.com>
Mon, 11 Feb 2019 17:07:21 +0000 (18:07 +0100)
14 files changed:
Cargo.lock
crates/ra_assists/Cargo.toml
crates/ra_assists/src/add_derive.rs
crates/ra_assists/src/add_impl.rs
crates/ra_assists/src/assist_ctx.rs
crates/ra_assists/src/auto_import.rs
crates/ra_assists/src/change_visibility.rs
crates/ra_assists/src/fill_match_arms.rs
crates/ra_assists/src/flip_comma.rs
crates/ra_assists/src/introduce_variable.rs
crates/ra_assists/src/lib.rs
crates/ra_assists/src/remove_dbg.rs
crates/ra_assists/src/replace_if_let_with_match.rs
crates/ra_assists/src/split_import.rs

index 210ad53c1f6d54023bde13f206f5a9cc07df8449..ff24b9dc84d67b030aeacbf48816779dc73b7518 100644 (file)
@@ -921,6 +921,7 @@ version = "0.1.0"
 name = "ra_assists"
 version = "0.1.0"
 dependencies = [
+ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_db 0.1.0",
  "ra_fmt 0.1.0",
index f8fbe75b5b238ca8d31e29a7d28e08006cfdc402..880bc4b189752cb34f10d7ed1f6cd2da27b70a66 100644 (file)
@@ -6,6 +6,7 @@ authors = ["rust-analyzer developers"]
 
 [dependencies]
 join_to_string = "0.1.3"
+itertools = "0.8.0"
 
 ra_syntax = { path = "../ra_syntax" }
 ra_text_edit = { path = "../ra_text_edit" }
index ea9707631db0b2815ab391ae847512d5a1eecd49..0556dd69cfb3b8dcbae365bb3deeb353919f0290 100644 (file)
@@ -7,10 +7,10 @@
 
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
     let node_start = derive_insertion_offset(nominal)?;
-    ctx.build("add `#[derive]`", |edit| {
+    ctx.add_action("add `#[derive]`", |edit| {
         let derive_attr = nominal
             .attrs()
             .filter_map(|x| x.as_call())
@@ -26,7 +26,9 @@ pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
         };
         edit.target(nominal.syntax().range());
         edit.set_cursor(offset)
-    })
+    });
+
+    ctx.build()
 }
 
 // Insert `derive` after doc comments.
index 32fc074a6207750e41ad42129eb46f0f47689aa8..b40b9cc0c2f9a9ac0c910ca7cb3a581cb65df245 100644 (file)
@@ -7,10 +7,10 @@
 
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
     let name = nominal.name()?;
-    ctx.build("add impl", |edit| {
+    ctx.add_action("add impl", |edit| {
         edit.target(nominal.syntax().range());
         let type_params = nominal.type_param_list();
         let start_offset = nominal.syntax().range().end();
@@ -32,7 +32,9 @@ pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
         edit.set_cursor(start_offset + TextUnit::of_str(&buf));
         buf.push_str("\n}");
         edit.insert(start_offset, buf);
-    })
+    });
+
+    ctx.build()
 }
 
 #[cfg(test)]
index e240c35d6f3a68298381874c15b748f8117da842..e9c4f0a23889495ae82c13abc46ec6ba67c3c7ea 100644 (file)
@@ -9,9 +9,10 @@
 
 use crate::{AssistLabel, AssistAction};
 
+#[derive(Clone, Debug)]
 pub(crate) enum Assist {
-    Unresolved(AssistLabel),
-    Resolved(AssistLabel, AssistAction),
+    Unresolved(Vec<AssistLabel>),
+    Resolved(Vec<(AssistLabel, AssistAction)>),
 }
 
 /// `AssistCtx` allows to apply an assist or check if it could be applied.
@@ -50,6 +51,7 @@ pub(crate) struct AssistCtx<'a, DB> {
     pub(crate) frange: FileRange,
     source_file: &'a SourceFile,
     should_compute_edit: bool,
+    assist: Assist,
 }
 
 impl<'a, DB> Clone for AssistCtx<'a, DB> {
@@ -59,6 +61,7 @@ fn clone(&self) -> Self {
             frange: self.frange,
             source_file: self.source_file,
             should_compute_edit: self.should_compute_edit,
+            assist: self.assist.clone(),
         }
     }
 }
@@ -69,25 +72,35 @@ pub(crate) fn with_ctx<F, T>(db: &DB, frange: FileRange, should_compute_edit: bo
         F: FnOnce(AssistCtx<DB>) -> T,
     {
         let source_file = &db.parse(frange.file_id);
-        let ctx = AssistCtx { db, frange, source_file, should_compute_edit };
+        let assist =
+            if should_compute_edit { Assist::Resolved(vec![]) } else { Assist::Unresolved(vec![]) };
+
+        let ctx = AssistCtx { db, frange, source_file, should_compute_edit, assist };
         f(ctx)
     }
 
-    pub(crate) fn build(
-        self,
+    pub(crate) fn add_action(
+        &mut self,
         label: impl Into<String>,
         f: impl FnOnce(&mut AssistBuilder),
-    ) -> Option<Assist> {
+    ) -> &mut Self {
         let label = AssistLabel { label: label.into() };
-        if !self.should_compute_edit {
-            return Some(Assist::Unresolved(label));
+        match &mut self.assist {
+            Assist::Unresolved(labels) => labels.push(label),
+            Assist::Resolved(labels_actions) => {
+                let action = {
+                    let mut edit = AssistBuilder::default();
+                    f(&mut edit);
+                    edit.build()
+                };
+                labels_actions.push((label, action));
+            }
         }
-        let action = {
-            let mut edit = AssistBuilder::default();
-            f(&mut edit);
-            edit.build()
-        };
-        Some(Assist::Resolved(label, action))
+        self
+    }
+
+    pub(crate) fn build(self) -> Option<Assist> {
+        Some(self.assist)
     }
 
     pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<&'a SyntaxNode> {
index 6a0c351f199444af8e0677b69b1498348f40ad1d..b251c936948ea5ed15767a8fc42cf6b3be83a741 100644 (file)
@@ -480,7 +480,7 @@ fn make_assist_add_nested_import(
     }
 }
 
-pub(crate) fn auto_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let node = ctx.covering_node();
     let current_file = node.ancestors().find_map(ast::SourceFile::cast)?;
 
@@ -495,7 +495,7 @@ pub(crate) fn auto_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
         return None;
     }
 
-    ctx.build(format!("import {} in the current file", fmt_segments(&segments)), |edit| {
+    ctx.add_action(format!("import {} in the current file", fmt_segments(&segments)), |edit| {
         let action = best_action_for_target(current_file.syntax(), path, &segments);
         make_assist(&action, segments.as_slice(), edit);
         if let Some(last_segment) = path.segment() {
@@ -506,7 +506,9 @@ pub(crate) fn auto_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
                 last_segment.syntax().range().start(),
             ));
         }
-    })
+    });
+
+    ctx.build()
 }
 
 #[cfg(test)]
index 6d9a4eec2fbf46dbd2dd08f96b2146a45b45a2c7..c2ba897a4bd563f1281151359d03879aa1f68329 100644 (file)
@@ -14,7 +14,7 @@ pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
     add_vis(ctx)
 }
 
-fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() {
         FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
         _ => false,
@@ -41,11 +41,13 @@ fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
         (vis_offset(field.syntax()), ident.range())
     };
 
-    ctx.build("make pub(crate)", |edit| {
+    ctx.add_action("make pub(crate)", |edit| {
         edit.target(target);
         edit.insert(offset, "pub(crate) ");
         edit.set_cursor(offset);
-    })
+    });
+
+    ctx.build()
 }
 
 fn vis_offset(node: &SyntaxNode) -> TextUnit {
@@ -59,20 +61,24 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
         .unwrap_or(node.range().start())
 }
 
-fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> {
+fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: &ast::Visibility) -> Option<Assist> {
     if vis.syntax().text() == "pub" {
-        return ctx.build("change to pub(crate)", |edit| {
+        ctx.add_action("change to pub(crate)", |edit| {
             edit.target(vis.syntax().range());
             edit.replace(vis.syntax().range(), "pub(crate)");
-            edit.set_cursor(vis.syntax().range().start());
+            edit.set_cursor(vis.syntax().range().start())
         });
+
+        return ctx.build();
     }
     if vis.syntax().text() == "pub(crate)" {
-        return ctx.build("change to pub", |edit| {
+        ctx.add_action("change to pub", |edit| {
             edit.target(vis.syntax().range());
             edit.replace(vis.syntax().range(), "pub");
             edit.set_cursor(vis.syntax().range().start());
         });
+
+        return ctx.build();
     }
     None
 }
index 69b535a274a534c63727344a4213f33836ab9161..d8e40b4b7b23f7eb07b9d09b622d3a411fffc259 100644 (file)
@@ -8,7 +8,7 @@
 
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?;
 
     // We already have some match arms, so we don't provide any assists.
@@ -33,7 +33,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
     let enum_name = enum_def.name(ctx.db)?;
     let db = ctx.db;
 
-    ctx.build("fill match arms", |edit| {
+    ctx.add_action("fill match arms", |edit| {
         let mut buf = format!("match {} {{\n", expr.syntax().text().to_string());
         let variants = enum_def.variants(db);
         for variant in variants {
@@ -68,7 +68,9 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
         edit.target(match_expr.syntax().range());
         edit.set_cursor(expr.syntax().range().start());
         edit.replace_node_and_indent(match_expr.syntax(), buf);
-    })
+    });
+
+    ctx.build()
 }
 
 #[cfg(test)]
index 33da58f1761a0586b2166d7aac76c3a242525b3b..08644d720c9595c0b741679502d38cc30bae950c 100644 (file)
@@ -6,15 +6,17 @@
 
 use crate::{AssistCtx, Assist, non_trivia_sibling};
 
-pub(crate) fn flip_comma(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?;
     let prev = non_trivia_sibling(comma, Direction::Prev)?;
     let next = non_trivia_sibling(comma, Direction::Next)?;
-    ctx.build("flip comma", |edit| {
+    ctx.add_action("flip comma", |edit| {
         edit.target(comma.range());
         edit.replace(prev.range(), next.text());
         edit.replace(next.range(), prev.text());
-    })
+    });
+
+    ctx.build()
 }
 
 #[cfg(test)]
index 954b97b055db3e465bfa3a3db43ff95ab34e82a0..f0e012105f5ecb5008756fac6397eb208f631dfc 100644 (file)
@@ -8,7 +8,7 @@
 
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let node = ctx.covering_node();
     if !valid_covering_node(node) {
         return None;
@@ -19,7 +19,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Ass
     if indent.kind() != WHITESPACE {
         return None;
     }
-    ctx.build("introduce variable", move |edit| {
+    ctx.add_action("introduce variable", move |edit| {
         let mut buf = String::new();
 
         let cursor_offset = if wrap_in_block {
@@ -68,7 +68,9 @@ pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Ass
             }
         }
         edit.set_cursor(anchor_stmt.range().start() + cursor_offset);
-    })
+    });
+
+    ctx.build()
 }
 
 fn valid_covering_node(node: &SyntaxNode) -> bool {
index af578893efc46b45327450d1b941dc11a5808b32..c607a5142be136bbae38864f232217c428f1c6ee 100644 (file)
@@ -7,6 +7,8 @@
 
 mod assist_ctx;
 
+use itertools::Itertools;
+
 use ra_text_edit::TextEdit;
 use ra_syntax::{TextRange, TextUnit, SyntaxNode, Direction};
 use ra_db::FileRange;
 
 pub(crate) use crate::assist_ctx::{AssistCtx, Assist};
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct AssistLabel {
     /// Short description of the assist, as shown in the UI.
     pub label: String,
 }
 
+#[derive(Debug, Clone)]
 pub struct AssistAction {
     pub edit: TextEdit,
     pub cursor_position: Option<TextUnit>,
@@ -39,10 +42,10 @@ pub fn applicable_assists<H>(db: &H, range: FileRange) -> Vec<AssistLabel>
             .iter()
             .filter_map(|f| f(ctx.clone()))
             .map(|a| match a {
-                Assist::Unresolved(label) => label,
+                Assist::Unresolved(labels) => labels,
                 Assist::Resolved(..) => unreachable!(),
             })
-            .collect()
+            .concat()
     })
 }
 
@@ -61,10 +64,10 @@ pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)>
             .iter()
             .filter_map(|f| f(ctx.clone()))
             .map(|a| match a {
-                Assist::Resolved(label, action) => (label, action),
+                Assist::Resolved(labels_actions) => labels_actions,
                 Assist::Unresolved(..) => unreachable!(),
             })
-            .collect::<Vec<(AssistLabel, AssistAction)>>();
+            .concat();
         a.sort_by(|a, b| match (a.1.target, b.1.target) {
             (Some(a), Some(b)) => a.len().cmp(&b.len()),
             (Some(_), None) => Ordering::Less,
@@ -118,6 +121,39 @@ pub(crate) fn check_assist(
         assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
         before: &str,
         after: &str,
+    ) {
+        check_assist_nth_action(assist, before, after, 0)
+    }
+
+    pub(crate) fn check_assist_range(
+        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
+        before: &str,
+        after: &str,
+    ) {
+        check_assist_range_nth_action(assist, before, after, 0)
+    }
+
+    pub(crate) fn check_assist_target(
+        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
+        before: &str,
+        target: &str,
+    ) {
+        check_assist_target_nth_action(assist, before, target, 0)
+    }
+
+    pub(crate) fn check_assist_range_target(
+        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
+        before: &str,
+        target: &str,
+    ) {
+        check_assist_range_target_nth_action(assist, before, target, 0)
+    }
+
+    pub(crate) fn check_assist_nth_action(
+        assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
+        before: &str,
+        after: &str,
+        index: usize,
     ) {
         let (before_cursor_pos, before) = extract_offset(before);
         let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
@@ -125,11 +161,12 @@ pub(crate) fn check_assist(
             FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
         let assist =
             AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
-        let action = match assist {
+        let labels_actions = match assist {
             Assist::Unresolved(_) => unreachable!(),
-            Assist::Resolved(_, it) => it,
+            Assist::Resolved(labels_actions) => labels_actions,
         };
 
+        let (_, action) = labels_actions.get(index).expect("expect assist action at index");
         let actual = action.edit.apply(&before);
         let actual_cursor_pos = match action.cursor_position {
             None => action
@@ -142,21 +179,23 @@ pub(crate) fn check_assist(
         assert_eq_text!(after, &actual);
     }
 
-    pub(crate) fn check_assist_range(
+    pub(crate) fn check_assist_range_nth_action(
         assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
         before: &str,
         after: &str,
+        index: usize,
     ) {
         let (range, before) = extract_range(before);
         let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
         let frange = FileRange { file_id, range };
         let assist =
             AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
-        let action = match assist {
+        let labels_actions = match assist {
             Assist::Unresolved(_) => unreachable!(),
-            Assist::Resolved(_, it) => it,
+            Assist::Resolved(labels_actions) => labels_actions,
         };
 
+        let (_, action) = labels_actions.get(index).expect("expect assist action at index");
         let mut actual = action.edit.apply(&before);
         if let Some(pos) = action.cursor_position {
             actual = add_cursor(&actual, pos);
@@ -164,10 +203,11 @@ pub(crate) fn check_assist_range(
         assert_eq_text!(after, &actual);
     }
 
-    pub(crate) fn check_assist_target(
+    pub(crate) fn check_assist_target_nth_action(
         assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
         before: &str,
         target: &str,
+        index: usize,
     ) {
         let (before_cursor_pos, before) = extract_offset(before);
         let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
@@ -175,30 +215,33 @@ pub(crate) fn check_assist_target(
             FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
         let assist =
             AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
-        let action = match assist {
+        let labels_actions = match assist {
             Assist::Unresolved(_) => unreachable!(),
-            Assist::Resolved(_, it) => it,
+            Assist::Resolved(labels_actions) => labels_actions,
         };
 
+        let (_, action) = labels_actions.get(index).expect("expect assist action at index");
         let range = action.target.expect("expected target on action");
         assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
     }
 
-    pub(crate) fn check_assist_range_target(
+    pub(crate) fn check_assist_range_target_nth_action(
         assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
         before: &str,
         target: &str,
+        index: usize,
     ) {
         let (range, before) = extract_range(before);
         let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
         let frange = FileRange { file_id, range };
         let assist =
             AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
-        let action = match assist {
+        let labels_actions = match assist {
             Assist::Unresolved(_) => unreachable!(),
-            Assist::Resolved(_, it) => it,
+            Assist::Resolved(labels_actions) => labels_actions,
         };
 
+        let (_, action) = labels_actions.get(index).expect("expect assist action at index");
         let range = action.target.expect("expected target on action");
         assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
     }
index e9d0a635b3ed9563908e40494e55309745b9d47e..db260c6caf5aa646af15908f7e47ca7cb4a966cd 100644 (file)
@@ -8,7 +8,7 @@
 };
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn remove_dbg(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let macro_call = ctx.node_at_offset::<ast::MacroCall>()?;
 
     if !is_valid_macrocall(macro_call, "dbg")? {
@@ -46,11 +46,13 @@ pub(crate) fn remove_dbg(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
         macro_args.text().slice(start..end).to_string()
     };
 
-    ctx.build("remove dbg!()", |edit| {
+    ctx.add_action("remove dbg!()", |edit| {
         edit.target(macro_call.syntax().range());
         edit.replace(macro_range, macro_content);
         edit.set_cursor(cursor_pos);
-    })
+    });
+
+    ctx.build()
 }
 
 /// Verifies that the given macro_call actually matches the given name
index f74ab3c6730f0983a1327fb73f9342e264b549fc..87a2c11859bafd21f35c1f79f6a0a6b59a7de95e 100644 (file)
@@ -4,7 +4,7 @@
 
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let if_expr: &ast::IfExpr = ctx.node_at_offset()?;
     let cond = if_expr.condition()?;
     let pat = cond.pat()?;
@@ -15,12 +15,14 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Opt
         ast::ElseBranchFlavor::IfExpr(_) => return None,
     };
 
-    ctx.build("replace with match", |edit| {
+    ctx.add_action("replace with match", |edit| {
         let match_expr = build_match_expr(expr, pat, then_block, else_block);
         edit.target(if_expr.syntax().range());
         edit.replace_node_and_indent(if_expr.syntax(), match_expr);
         edit.set_cursor(if_expr.syntax().range().start())
-    })
+    });
+
+    ctx.build()
 }
 
 fn build_match_expr(
index 051bc6fecf2ab9b8b5b58c915fd2318959eec003..f043be6369ffac5b95cd8632087232b7880a3ed2 100644 (file)
@@ -7,7 +7,7 @@
 
 use crate::{AssistCtx, Assist};
 
-pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
     let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?;
     let path = colon_colon.parent().and_then(ast::Path::cast)?;
     let top_path = generate(Some(path), |it| it.parent_path()).last()?;
@@ -23,12 +23,14 @@ pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
         None => top_path.syntax().range().end(),
     };
 
-    ctx.build("split import", |edit| {
+    ctx.add_action("split import", |edit| {
         edit.target(colon_colon.range());
         edit.insert(l_curly, "{");
         edit.insert(r_curly, "}");
         edit.set_cursor(l_curly + TextUnit::of_str("{"));
-    })
+    });
+
+    ctx.build()
 }
 
 #[cfg(test)]