From 73dc8b6f06b49f4728a50e83781c361e9a8b3100 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 2 Jan 2020 01:39:01 +0200 Subject: Another attempt to add multiple edits --- crates/ra_assists/src/assist_ctx.rs | 45 +++++++++++++++++++--- .../src/assists/inline_local_variable.rs | 4 +- crates/ra_assists/src/doc_tests.rs | 6 +-- crates/ra_assists/src/lib.rs | 7 +++- 4 files changed, 49 insertions(+), 13 deletions(-) (limited to 'crates/ra_assists/src') diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 1a65b5dc0..879216a36 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -14,7 +14,7 @@ use crate::{AssistAction, AssistId, AssistLabel}; #[derive(Clone, Debug)] pub(crate) enum Assist { Unresolved { label: AssistLabel }, - Resolved { label: AssistLabel, action: AssistAction }, + Resolved { label: AssistLabel, action: AssistAction, alternative_actions: Vec }, } /// `AssistCtx` allows to apply an assist or check if it could be applied. @@ -81,18 +81,43 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { self, id: AssistId, label: impl Into, - f: impl FnOnce(&mut AssistBuilder), + f: impl FnOnce(&mut ActionBuilder), ) -> Option { let label = AssistLabel { label: label.into(), id }; assert!(label.label.chars().nth(0).unwrap().is_uppercase()); let assist = if self.should_compute_edit { let action = { - let mut edit = AssistBuilder::default(); + let mut edit = ActionBuilder::default(); f(&mut edit); edit.build() }; - Assist::Resolved { label, action } + Assist::Resolved { label, action, alternative_actions: Vec::default() } + } else { + Assist::Unresolved { label } + }; + + Some(assist) + } + + #[allow(dead_code)] // will be used for auto import assist with multiple actions + pub(crate) fn add_assist_group( + self, + id: AssistId, + label: impl Into, + f: impl FnOnce() -> (ActionBuilder, Vec), + ) -> Option { + let label = AssistLabel { label: label.into(), id }; + let assist = if self.should_compute_edit { + let (action, alternative_actions) = f(); + Assist::Resolved { + label, + action: action.build(), + alternative_actions: alternative_actions + .into_iter() + .map(ActionBuilder::build) + .collect(), + } } else { Assist::Unresolved { label } }; @@ -128,13 +153,20 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { } #[derive(Default)] -pub(crate) struct AssistBuilder { +pub(crate) struct ActionBuilder { edit: TextEditBuilder, cursor_position: Option, target: Option, + label: Option, } -impl AssistBuilder { +impl ActionBuilder { + #[allow(dead_code)] + /// Adds a custom label to the action, if it needs to be different from the assist label + pub fn label(&mut self, label: impl Into) { + self.label = Some(label.into()) + } + /// Replaces specified `range` of text with a given string. pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into) { self.edit.replace(range, replace_with.into()) @@ -193,6 +225,7 @@ impl AssistBuilder { edit: self.edit.finish(), cursor_position: self.cursor_position, target: self.target, + label: self.label, } } } diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index 164aee90c..45e0f983f 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs @@ -4,7 +4,7 @@ use ra_syntax::{ TextRange, }; -use crate::assist_ctx::AssistBuilder; +use crate::assist_ctx::ActionBuilder; use crate::{Assist, AssistCtx, AssistId}; // Assist: inline_local_variable @@ -94,7 +94,7 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx) -> Option< ctx.add_assist( AssistId("inline_local_variable"), "Inline variable", - move |edit: &mut AssistBuilder| { + move |edit: &mut ActionBuilder| { edit.delete(delete_range); for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { if should_wrap { diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index a8f8446cb..21bee228d 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs @@ -15,16 +15,16 @@ fn check(assist_id: &str, before: &str, after: &str) { let (db, file_id) = TestDB::with_single_file(&before); let frange = FileRange { file_id, range: selection.into() }; - let (_assist_id, action) = crate::assists(&db, frange) + let (_assist_id, action, _) = crate::assists(&db, frange) .into_iter() - .find(|(id, _)| id.id.0 == assist_id) + .find(|(id, _, _)| id.id.0 == assist_id) .unwrap_or_else(|| { panic!( "\n\nAssist is not applicable: {}\nAvailable assists: {}", assist_id, crate::assists(&db, frange) .into_iter() - .map(|(id, _)| id.id.0) + .map(|(id, _, _)| id.id.0) .collect::>() .join(", ") ) diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 150b34ac7..95a530821 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -35,6 +35,7 @@ pub struct AssistLabel { #[derive(Debug, Clone)] pub struct AssistAction { + pub label: Option, pub edit: TextEdit, pub cursor_position: Option, pub target: Option, @@ -64,7 +65,7 @@ where /// /// Assists are returned in the "resolved" state, that is with edit fully /// computed. -pub fn assists(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction)> +pub fn assists(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction, Vec)> where H: HirDatabase + 'static, { @@ -75,7 +76,9 @@ where .iter() .filter_map(|f| f(ctx.clone())) .map(|a| match a { - Assist::Resolved { label, action } => (label, action), + Assist::Resolved { label, action, alternative_actions } => { + (label, action, alternative_actions) + } Assist::Unresolved { .. } => unreachable!(), }) .collect::>(); -- cgit v1.2.3