aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assist_ctx.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assist_ctx.rs')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs56
1 files changed, 44 insertions, 12 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 1b626faaa..9d533fa0c 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,4 +1,5 @@
1//! This module defines `AssistCtx` -- the API surface that is exposed to assists. 1//! This module defines `AssistCtx` -- the API surface that is exposed to assists.
2use either::Either;
2use hir::{db::HirDatabase, InFile, SourceAnalyzer}; 3use hir::{db::HirDatabase, InFile, SourceAnalyzer};
3use ra_db::FileRange; 4use ra_db::FileRange;
4use ra_fmt::{leading_indent, reindent}; 5use ra_fmt::{leading_indent, reindent};
@@ -9,12 +10,12 @@ use ra_syntax::{
9}; 10};
10use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
11 12
12use crate::{AssistAction, AssistId, AssistLabel}; 13use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist};
13 14
14#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
15pub(crate) enum Assist { 16pub(crate) enum Assist {
16 Unresolved { label: AssistLabel }, 17 Unresolved { label: AssistLabel },
17 Resolved { label: AssistLabel, action: AssistAction }, 18 Resolved { assist: ResolvedAssist },
18} 19}
19 20
20/// `AssistCtx` allows to apply an assist or check if it could be applied. 21/// `AssistCtx` allows to apply an assist or check if it could be applied.
@@ -81,22 +82,45 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
81 self, 82 self,
82 id: AssistId, 83 id: AssistId,
83 label: impl Into<String>, 84 label: impl Into<String>,
84 f: impl FnOnce(&mut AssistBuilder), 85 f: impl FnOnce(&mut ActionBuilder),
85 ) -> Option<Assist> { 86 ) -> Option<Assist> {
86 let label = AssistLabel { label: label.into(), id }; 87 let label = AssistLabel { label: label.into(), id };
87 assert_eq!( 88 assert!(label.label.chars().nth(0).unwrap().is_uppercase());
88 label.label.chars().nth(0).and_then(|c| Some(c.is_uppercase())).unwrap(),
89 true,
90 "First character should be uppercase"
91 );
92 89
93 let assist = if self.should_compute_edit { 90 let assist = if self.should_compute_edit {
94 let action = { 91 let action = {
95 let mut edit = AssistBuilder::default(); 92 let mut edit = ActionBuilder::default();
96 f(&mut edit); 93 f(&mut edit);
97 edit.build() 94 edit.build()
98 }; 95 };
99 Assist::Resolved { label, action } 96 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } }
97 } else {
98 Assist::Unresolved { label }
99 };
100
101 Some(assist)
102 }
103
104 #[allow(dead_code)] // will be used for auto import assist with multiple actions
105 pub(crate) fn add_assist_group(
106 self,
107 id: AssistId,
108 label: impl Into<String>,
109 f: impl FnOnce() -> Vec<ActionBuilder>,
110 ) -> Option<Assist> {
111 let label = AssistLabel { label: label.into(), id };
112 let assist = if self.should_compute_edit {
113 let actions = f();
114 assert!(!actions.is_empty(), "Assist cannot have no");
115
116 Assist::Resolved {
117 assist: ResolvedAssist {
118 label,
119 action_data: Either::Right(
120 actions.into_iter().map(ActionBuilder::build).collect(),
121 ),
122 },
123 }
100 } else { 124 } else {
101 Assist::Unresolved { label } 125 Assist::Unresolved { label }
102 }; 126 };
@@ -132,13 +156,20 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
132} 156}
133 157
134#[derive(Default)] 158#[derive(Default)]
135pub(crate) struct AssistBuilder { 159pub(crate) struct ActionBuilder {
136 edit: TextEditBuilder, 160 edit: TextEditBuilder,
137 cursor_position: Option<TextUnit>, 161 cursor_position: Option<TextUnit>,
138 target: Option<TextRange>, 162 target: Option<TextRange>,
163 label: Option<String>,
139} 164}
140 165
141impl AssistBuilder { 166impl ActionBuilder {
167 #[allow(dead_code)]
168 /// Adds a custom label to the action, if it needs to be different from the assist label
169 pub(crate) fn label(&mut self, label: impl Into<String>) {
170 self.label = Some(label.into())
171 }
172
142 /// Replaces specified `range` of text with a given string. 173 /// Replaces specified `range` of text with a given string.
143 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 174 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
144 self.edit.replace(range, replace_with.into()) 175 self.edit.replace(range, replace_with.into())
@@ -197,6 +228,7 @@ impl AssistBuilder {
197 edit: self.edit.finish(), 228 edit: self.edit.finish(),
198 cursor_position: self.cursor_position, 229 cursor_position: self.cursor_position,
199 target: self.target, 230 target: self.target,
231 label: self.label,
200 } 232 }
201 } 233 }
202} 234}