aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assist_context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assist_context.rs')
-rw-r--r--crates/ra_assists/src/assist_context.rs50
1 files changed, 37 insertions, 13 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index a680f752b..f3af70a3e 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -15,7 +15,10 @@ use ra_syntax::{
15}; 15};
16use ra_text_edit::TextEditBuilder; 16use ra_text_edit::TextEditBuilder;
17 17
18use crate::{Assist, AssistId, GroupLabel, ResolvedAssist}; 18use crate::{
19 assist_config::{AssistConfig, SnippetCap},
20 Assist, AssistId, GroupLabel, ResolvedAssist,
21};
19 22
20/// `AssistContext` allows to apply an assist or check if it could be applied. 23/// `AssistContext` allows to apply an assist or check if it could be applied.
21/// 24///
@@ -48,6 +51,7 @@ use crate::{Assist, AssistId, GroupLabel, ResolvedAssist};
48/// moment, because the LSP API is pretty awkward in this place, and it's much 51/// moment, because the LSP API is pretty awkward in this place, and it's much
49/// easier to just compute the edit eagerly :-) 52/// easier to just compute the edit eagerly :-)
50pub(crate) struct AssistContext<'a> { 53pub(crate) struct AssistContext<'a> {
54 pub(crate) config: &'a AssistConfig,
51 pub(crate) sema: Semantics<'a, RootDatabase>, 55 pub(crate) sema: Semantics<'a, RootDatabase>,
52 pub(crate) db: &'a RootDatabase, 56 pub(crate) db: &'a RootDatabase,
53 pub(crate) frange: FileRange, 57 pub(crate) frange: FileRange,
@@ -55,10 +59,14 @@ pub(crate) struct AssistContext<'a> {
55} 59}
56 60
57impl<'a> AssistContext<'a> { 61impl<'a> AssistContext<'a> {
58 pub fn new(sema: Semantics<'a, RootDatabase>, frange: FileRange) -> AssistContext<'a> { 62 pub(crate) fn new(
63 sema: Semantics<'a, RootDatabase>,
64 config: &'a AssistConfig,
65 frange: FileRange,
66 ) -> AssistContext<'a> {
59 let source_file = sema.parse(frange.file_id); 67 let source_file = sema.parse(frange.file_id);
60 let db = sema.db; 68 let db = sema.db;
61 AssistContext { sema, db, frange, source_file } 69 AssistContext { config, sema, db, frange, source_file }
62 } 70 }
63 71
64 // NB, this ignores active selection. 72 // NB, this ignores active selection.
@@ -163,13 +171,13 @@ impl Assists {
163 171
164pub(crate) struct AssistBuilder { 172pub(crate) struct AssistBuilder {
165 edit: TextEditBuilder, 173 edit: TextEditBuilder,
166 cursor_position: Option<TextSize>,
167 file: FileId, 174 file: FileId,
175 is_snippet: bool,
168} 176}
169 177
170impl AssistBuilder { 178impl AssistBuilder {
171 pub(crate) fn new(file: FileId) -> AssistBuilder { 179 pub(crate) fn new(file: FileId) -> AssistBuilder {
172 AssistBuilder { edit: TextEditBuilder::default(), cursor_position: None, file } 180 AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false }
173 } 181 }
174 182
175 /// Remove specified `range` of text. 183 /// Remove specified `range` of text.
@@ -180,10 +188,30 @@ impl AssistBuilder {
180 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { 188 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
181 self.edit.insert(offset, text.into()) 189 self.edit.insert(offset, text.into())
182 } 190 }
191 /// Append specified `snippet` at the given `offset`
192 pub(crate) fn insert_snippet(
193 &mut self,
194 _cap: SnippetCap,
195 offset: TextSize,
196 snippet: impl Into<String>,
197 ) {
198 self.is_snippet = true;
199 self.insert(offset, snippet);
200 }
183 /// Replaces specified `range` of text with a given string. 201 /// Replaces specified `range` of text with a given string.
184 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 202 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
185 self.edit.replace(range, replace_with.into()) 203 self.edit.replace(range, replace_with.into())
186 } 204 }
205 /// Replaces specified `range` of text with a given `snippet`.
206 pub(crate) fn replace_snippet(
207 &mut self,
208 _cap: SnippetCap,
209 range: TextRange,
210 snippet: impl Into<String>,
211 ) {
212 self.is_snippet = true;
213 self.replace(range, snippet);
214 }
187 pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { 215 pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
188 algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) 216 algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
189 } 217 }
@@ -207,10 +235,6 @@ impl AssistBuilder {
207 algo::diff(&node, &new).into_text_edit(&mut self.edit) 235 algo::diff(&node, &new).into_text_edit(&mut self.edit)
208 } 236 }
209 237
210 /// Specify desired position of the cursor after the assist is applied.
211 pub(crate) fn set_cursor(&mut self, offset: TextSize) {
212 self.cursor_position = Some(offset)
213 }
214 // FIXME: better API 238 // FIXME: better API
215 pub(crate) fn set_file(&mut self, assist_file: FileId) { 239 pub(crate) fn set_file(&mut self, assist_file: FileId) {
216 self.file = assist_file; 240 self.file = assist_file;
@@ -224,10 +248,10 @@ impl AssistBuilder {
224 248
225 fn finish(self, change_label: String) -> SourceChange { 249 fn finish(self, change_label: String) -> SourceChange {
226 let edit = self.edit.finish(); 250 let edit = self.edit.finish();
227 if edit.is_empty() && self.cursor_position.is_none() { 251 let mut res = SingleFileChange { label: change_label, edit }.into_source_change(self.file);
228 panic!("Only call `add_assist` if the assist can be applied") 252 if self.is_snippet {
253 res.is_snippet = true;
229 } 254 }
230 SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position } 255 res
231 .into_source_change(self.file)
232 } 256 }
233} 257}