diff options
author | Kirill Bulatov <[email protected]> | 2020-12-03 09:13:28 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-12-07 21:41:08 +0000 |
commit | f6d2540df09bc0dcd8a748ec0ed7cb33ac76d9f2 (patch) | |
tree | a206df6f66f41a9f4840d3e19204d67a46831513 /crates/completion/src/item.rs | |
parent | 68a747efe048e8e92eedafaa27b0c0d2f317f04d (diff) |
Simplify import edit calculation
Diffstat (limited to 'crates/completion/src/item.rs')
-rw-r--r-- | crates/completion/src/item.rs | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index 775245b3b..4e56f28f3 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -68,7 +68,7 @@ pub struct CompletionItem { | |||
68 | ref_match: Option<(Mutability, CompletionScore)>, | 68 | ref_match: Option<(Mutability, CompletionScore)>, |
69 | 69 | ||
70 | /// The import data to add to completion's edits. | 70 | /// The import data to add to completion's edits. |
71 | import_to_add: Option<ImportToAdd>, | 71 | import_to_add: Option<ImportEdit>, |
72 | } | 72 | } |
73 | 73 | ||
74 | // We use custom debug for CompletionItem to make snapshot tests more readable. | 74 | // We use custom debug for CompletionItem to make snapshot tests more readable. |
@@ -209,7 +209,7 @@ impl CompletionItem { | |||
209 | score: None, | 209 | score: None, |
210 | ref_match: None, | 210 | ref_match: None, |
211 | import_to_add: None, | 211 | import_to_add: None, |
212 | resolve_import_immediately: true, | 212 | resolve_import_lazily: false, |
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
@@ -262,27 +262,46 @@ impl CompletionItem { | |||
262 | self.ref_match | 262 | self.ref_match |
263 | } | 263 | } |
264 | 264 | ||
265 | pub fn import_to_add(&self) -> Option<&ImportToAdd> { | 265 | pub fn import_to_add(&self) -> Option<&ImportEdit> { |
266 | self.import_to_add.as_ref() | 266 | self.import_to_add.as_ref() |
267 | } | 267 | } |
268 | } | 268 | } |
269 | 269 | ||
270 | /// An extra import to add after the completion is applied. | 270 | /// An extra import to add after the completion is applied. |
271 | #[derive(Debug, Clone)] | 271 | #[derive(Debug, Clone)] |
272 | pub struct ImportToAdd { | 272 | pub struct ImportEdit { |
273 | pub import_path: ModPath, | 273 | pub import_path: ModPath, |
274 | pub import_scope: ImportScope, | 274 | pub import_scope: ImportScope, |
275 | pub merge_behaviour: Option<MergeBehaviour>, | 275 | pub merge_behaviour: Option<MergeBehaviour>, |
276 | } | 276 | } |
277 | 277 | ||
278 | impl ImportEdit { | ||
279 | /// Attempts to insert the import to the given scope, producing a text edit. | ||
280 | /// May return no edit in edge cases, such as scope already containing the import. | ||
281 | pub fn to_text_edit(&self) -> Option<TextEdit> { | ||
282 | let _p = profile::span("ImportEdit::to_edit"); | ||
283 | |||
284 | let rewriter = insert_use::insert_use( | ||
285 | &self.import_scope, | ||
286 | mod_path_to_ast(&self.import_path), | ||
287 | self.merge_behaviour, | ||
288 | ); | ||
289 | let old_ast = rewriter.rewrite_root()?; | ||
290 | let mut import_insert = TextEdit::builder(); | ||
291 | algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); | ||
292 | |||
293 | Some(import_insert.finish()) | ||
294 | } | ||
295 | } | ||
296 | |||
278 | /// A helper to make `CompletionItem`s. | 297 | /// A helper to make `CompletionItem`s. |
279 | #[must_use] | 298 | #[must_use] |
280 | #[derive(Clone)] | 299 | #[derive(Clone)] |
281 | pub(crate) struct Builder { | 300 | pub(crate) struct Builder { |
282 | source_range: TextRange, | 301 | source_range: TextRange, |
283 | completion_kind: CompletionKind, | 302 | completion_kind: CompletionKind, |
284 | import_to_add: Option<ImportToAdd>, | 303 | import_to_add: Option<ImportEdit>, |
285 | resolve_import_immediately: bool, | 304 | resolve_import_lazily: bool, |
286 | label: String, | 305 | label: String, |
287 | insert_text: Option<String>, | 306 | insert_text: Option<String>, |
288 | insert_text_format: InsertTextFormat, | 307 | insert_text_format: InsertTextFormat, |
@@ -304,7 +323,6 @@ impl Builder { | |||
304 | let mut label = self.label; | 323 | let mut label = self.label; |
305 | let mut lookup = self.lookup; | 324 | let mut lookup = self.lookup; |
306 | let mut insert_text = self.insert_text; | 325 | let mut insert_text = self.insert_text; |
307 | let mut text_edits = TextEdit::builder(); | ||
308 | 326 | ||
309 | if let Some(import_to_add) = self.import_to_add.as_ref() { | 327 | if let Some(import_to_add) = self.import_to_add.as_ref() { |
310 | let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); | 328 | let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); |
@@ -319,35 +337,28 @@ impl Builder { | |||
319 | } | 337 | } |
320 | label = format!("{}::{}", import_path_without_last_segment, label); | 338 | label = format!("{}::{}", import_path_without_last_segment, label); |
321 | } | 339 | } |
322 | |||
323 | if self.resolve_import_immediately { | ||
324 | let rewriter = insert_use::insert_use( | ||
325 | &import_to_add.import_scope, | ||
326 | mod_path_to_ast(&import_to_add.import_path), | ||
327 | import_to_add.merge_behaviour, | ||
328 | ); | ||
329 | if let Some(old_ast) = rewriter.rewrite_root() { | ||
330 | algo::diff(&old_ast, &rewriter.rewrite(&old_ast)) | ||
331 | .into_text_edit(&mut text_edits); | ||
332 | } | ||
333 | } | ||
334 | } | 340 | } |
335 | 341 | ||
336 | let original_edit = match self.text_edit { | 342 | let mut text_edit = match self.text_edit { |
337 | Some(it) => it, | 343 | Some(it) => it, |
338 | None => { | 344 | None => { |
339 | TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone())) | 345 | TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone())) |
340 | } | 346 | } |
341 | }; | 347 | }; |
342 | 348 | ||
343 | let mut resulting_edit = text_edits.finish(); | 349 | if !self.resolve_import_lazily { |
344 | resulting_edit.union(original_edit).expect("Failed to unite text edits"); | 350 | if let Some(import_edit) = |
351 | self.import_to_add.as_ref().and_then(|import_edit| import_edit.to_text_edit()) | ||
352 | { | ||
353 | text_edit.union(import_edit).expect("Failed to unite import and completion edits"); | ||
354 | } | ||
355 | } | ||
345 | 356 | ||
346 | CompletionItem { | 357 | CompletionItem { |
347 | source_range: self.source_range, | 358 | source_range: self.source_range, |
348 | label, | 359 | label, |
349 | insert_text_format: self.insert_text_format, | 360 | insert_text_format: self.insert_text_format, |
350 | text_edit: resulting_edit, | 361 | text_edit, |
351 | detail: self.detail, | 362 | detail: self.detail, |
352 | documentation: self.documentation, | 363 | documentation: self.documentation, |
353 | lookup, | 364 | lookup, |
@@ -422,11 +433,11 @@ impl Builder { | |||
422 | } | 433 | } |
423 | pub(crate) fn add_import( | 434 | pub(crate) fn add_import( |
424 | mut self, | 435 | mut self, |
425 | import_to_add: Option<ImportToAdd>, | 436 | import_to_add: Option<ImportEdit>, |
426 | resolve_import_immediately: bool, | 437 | resolve_import_lazily: bool, |
427 | ) -> Builder { | 438 | ) -> Builder { |
428 | self.import_to_add = import_to_add; | 439 | self.import_to_add = import_to_add; |
429 | self.resolve_import_immediately = resolve_import_immediately; | 440 | self.resolve_import_lazily = resolve_import_lazily; |
430 | self | 441 | self |
431 | } | 442 | } |
432 | pub(crate) fn set_ref_match( | 443 | pub(crate) fn set_ref_match( |