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.rs58
1 files changed, 41 insertions, 17 deletions
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index a680f752b..5b1a4680b 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -5,7 +5,7 @@ use hir::Semantics;
5use ra_db::{FileId, FileRange}; 5use ra_db::{FileId, FileRange};
6use ra_fmt::{leading_indent, reindent}; 6use ra_fmt::{leading_indent, reindent};
7use ra_ide_db::{ 7use ra_ide_db::{
8 source_change::{SingleFileChange, SourceChange}, 8 source_change::{SourceChange, SourceFileEdit},
9 RootDatabase, 9 RootDatabase,
10}; 10};
11use ra_syntax::{ 11use ra_syntax::{
@@ -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.
@@ -142,11 +150,10 @@ impl Assists {
142 self.add_impl(label, f) 150 self.add_impl(label, f)
143 } 151 }
144 fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { 152 fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> {
145 let change_label = label.label.clone();
146 let source_change = if self.resolve { 153 let source_change = if self.resolve {
147 let mut builder = AssistBuilder::new(self.file); 154 let mut builder = AssistBuilder::new(self.file);
148 f(&mut builder); 155 f(&mut builder);
149 Some(builder.finish(change_label)) 156 Some(builder.finish())
150 } else { 157 } else {
151 None 158 None
152 }; 159 };
@@ -163,13 +170,13 @@ impl Assists {
163 170
164pub(crate) struct AssistBuilder { 171pub(crate) struct AssistBuilder {
165 edit: TextEditBuilder, 172 edit: TextEditBuilder,
166 cursor_position: Option<TextSize>,
167 file: FileId, 173 file: FileId,
174 is_snippet: bool,
168} 175}
169 176
170impl AssistBuilder { 177impl AssistBuilder {
171 pub(crate) fn new(file: FileId) -> AssistBuilder { 178 pub(crate) fn new(file: FileId) -> AssistBuilder {
172 AssistBuilder { edit: TextEditBuilder::default(), cursor_position: None, file } 179 AssistBuilder { edit: TextEditBuilder::default(), file, is_snippet: false }
173 } 180 }
174 181
175 /// Remove specified `range` of text. 182 /// Remove specified `range` of text.
@@ -180,10 +187,30 @@ impl AssistBuilder {
180 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { 187 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
181 self.edit.insert(offset, text.into()) 188 self.edit.insert(offset, text.into())
182 } 189 }
190 /// Append specified `snippet` at the given `offset`
191 pub(crate) fn insert_snippet(
192 &mut self,
193 _cap: SnippetCap,
194 offset: TextSize,
195 snippet: impl Into<String>,
196 ) {
197 self.is_snippet = true;
198 self.insert(offset, snippet);
199 }
183 /// Replaces specified `range` of text with a given string. 200 /// Replaces specified `range` of text with a given string.
184 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 201 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
185 self.edit.replace(range, replace_with.into()) 202 self.edit.replace(range, replace_with.into())
186 } 203 }
204 /// Replaces specified `range` of text with a given `snippet`.
205 pub(crate) fn replace_snippet(
206 &mut self,
207 _cap: SnippetCap,
208 range: TextRange,
209 snippet: impl Into<String>,
210 ) {
211 self.is_snippet = true;
212 self.replace(range, snippet);
213 }
187 pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { 214 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) 215 algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
189 } 216 }
@@ -207,10 +234,6 @@ impl AssistBuilder {
207 algo::diff(&node, &new).into_text_edit(&mut self.edit) 234 algo::diff(&node, &new).into_text_edit(&mut self.edit)
208 } 235 }
209 236
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 237 // FIXME: better API
215 pub(crate) fn set_file(&mut self, assist_file: FileId) { 238 pub(crate) fn set_file(&mut self, assist_file: FileId) {
216 self.file = assist_file; 239 self.file = assist_file;
@@ -222,12 +245,13 @@ impl AssistBuilder {
222 &mut self.edit 245 &mut self.edit
223 } 246 }
224 247
225 fn finish(self, change_label: String) -> SourceChange { 248 fn finish(self) -> SourceChange {
226 let edit = self.edit.finish(); 249 let edit = self.edit.finish();
227 if edit.is_empty() && self.cursor_position.is_none() { 250 let source_file_edit = SourceFileEdit { file_id: self.file, edit };
228 panic!("Only call `add_assist` if the assist can be applied") 251 let mut res: SourceChange = source_file_edit.into();
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}