diff options
Diffstat (limited to 'crates/completion')
-rw-r--r-- | crates/completion/src/config.rs | 10 | ||||
-rw-r--r-- | crates/completion/src/item.rs | 63 | ||||
-rw-r--r-- | crates/completion/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/completion/src/render.rs | 13 | ||||
-rw-r--r-- | crates/completion/src/render/enum_variant.rs | 8 | ||||
-rw-r--r-- | crates/completion/src/render/function.rs | 8 | ||||
-rw-r--r-- | crates/completion/src/render/macro_.rs | 11 |
7 files changed, 65 insertions, 50 deletions
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index eacdd3449..487c1d0f1 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -36,12 +36,10 @@ impl CompletionConfig { | |||
36 | self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None } | 36 | self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None } |
37 | } | 37 | } |
38 | 38 | ||
39 | /// Whether the completions' additional edits are calculated later, during a resolve request or not. | 39 | /// Whether the completions' additional edits are calculated when sending an initional completions list |
40 | /// See `CompletionResolveCapability` for the details. | 40 | /// or later, in a separate resolve request. |
41 | pub fn resolve_edits_immediately(&self) -> bool { | 41 | pub fn resolve_additional_edits_lazily(&self) -> bool { |
42 | !self | 42 | self.active_resolve_capabilities.contains(&CompletionResolveCapability::AdditionalTextEdits) |
43 | .active_resolve_capabilities | ||
44 | .contains(&CompletionResolveCapability::AdditionalTextEdits) | ||
45 | } | 43 | } |
46 | } | 44 | } |
47 | 45 | ||
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( |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index c689b0dde..c57203c80 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -18,7 +18,7 @@ use crate::{completions::Completions, context::CompletionContext, item::Completi | |||
18 | 18 | ||
19 | pub use crate::{ | 19 | pub use crate::{ |
20 | config::{CompletionConfig, CompletionResolveCapability}, | 20 | config::{CompletionConfig, CompletionResolveCapability}, |
21 | item::{CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd, InsertTextFormat}, | 21 | item::{CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, InsertTextFormat}, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | //FIXME: split the following feature into fine-grained features. | 24 | //FIXME: split the following feature into fine-grained features. |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 2b4f1ea14..a6faedb18 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -16,7 +16,7 @@ use syntax::TextRange; | |||
16 | use test_utils::mark; | 16 | use test_utils::mark; |
17 | 17 | ||
18 | use crate::{ | 18 | use crate::{ |
19 | config::SnippetCap, item::ImportToAdd, CompletionContext, CompletionItem, CompletionItemKind, | 19 | config::SnippetCap, item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, |
20 | CompletionKind, CompletionScore, | 20 | CompletionKind, CompletionScore, |
21 | }; | 21 | }; |
22 | 22 | ||
@@ -56,7 +56,7 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
56 | let local_name = import_path.segments.last()?.to_string(); | 56 | let local_name = import_path.segments.last()?.to_string(); |
57 | Render::new(ctx).render_resolution( | 57 | Render::new(ctx).render_resolution( |
58 | local_name, | 58 | local_name, |
59 | Some(ImportToAdd { import_path, import_scope, merge_behaviour }), | 59 | Some(ImportEdit { import_path, import_scope, merge_behaviour }), |
60 | resolution, | 60 | resolution, |
61 | ) | 61 | ) |
62 | } | 62 | } |
@@ -147,7 +147,7 @@ impl<'a> Render<'a> { | |||
147 | fn render_resolution( | 147 | fn render_resolution( |
148 | self, | 148 | self, |
149 | local_name: String, | 149 | local_name: String, |
150 | import_to_add: Option<ImportToAdd>, | 150 | import_to_add: Option<ImportEdit>, |
151 | resolution: &ScopeDef, | 151 | resolution: &ScopeDef, |
152 | ) -> Option<CompletionItem> { | 152 | ) -> Option<CompletionItem> { |
153 | let _p = profile::span("render_resolution"); | 153 | let _p = profile::span("render_resolution"); |
@@ -194,7 +194,10 @@ impl<'a> Render<'a> { | |||
194 | local_name, | 194 | local_name, |
195 | ) | 195 | ) |
196 | .kind(CompletionItemKind::UnresolvedReference) | 196 | .kind(CompletionItemKind::UnresolvedReference) |
197 | .add_import(import_to_add, self.ctx.completion.config.resolve_edits_immediately()) | 197 | .add_import( |
198 | import_to_add, | ||
199 | self.ctx.completion.config.resolve_additional_edits_lazily(), | ||
200 | ) | ||
198 | .build(); | 201 | .build(); |
199 | return Some(item); | 202 | return Some(item); |
200 | } | 203 | } |
@@ -249,7 +252,7 @@ impl<'a> Render<'a> { | |||
249 | 252 | ||
250 | let item = item | 253 | let item = item |
251 | .kind(kind) | 254 | .kind(kind) |
252 | .add_import(import_to_add, self.ctx.completion.config.resolve_edits_immediately()) | 255 | .add_import(import_to_add, self.ctx.completion.config.resolve_additional_edits_lazily()) |
253 | .set_documentation(docs) | 256 | .set_documentation(docs) |
254 | .set_ref_match(ref_match) | 257 | .set_ref_match(ref_match) |
255 | .build(); | 258 | .build(); |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index 4a91fe3c7..e979a090b 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -5,13 +5,13 @@ use itertools::Itertools; | |||
5 | use test_utils::mark; | 5 | use test_utils::mark; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd}, | 8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, |
9 | render::{builder_ext::Params, RenderContext}, | 9 | render::{builder_ext::Params, RenderContext}, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub(crate) fn render_enum_variant<'a>( | 12 | pub(crate) fn render_enum_variant<'a>( |
13 | ctx: RenderContext<'a>, | 13 | ctx: RenderContext<'a>, |
14 | import_to_add: Option<ImportToAdd>, | 14 | import_to_add: Option<ImportEdit>, |
15 | local_name: Option<String>, | 15 | local_name: Option<String>, |
16 | variant: hir::EnumVariant, | 16 | variant: hir::EnumVariant, |
17 | path: Option<ModPath>, | 17 | path: Option<ModPath>, |
@@ -62,7 +62,7 @@ impl<'a> EnumVariantRender<'a> { | |||
62 | } | 62 | } |
63 | } | 63 | } |
64 | 64 | ||
65 | fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem { | 65 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
66 | let mut builder = CompletionItem::new( | 66 | let mut builder = CompletionItem::new( |
67 | CompletionKind::Reference, | 67 | CompletionKind::Reference, |
68 | self.ctx.source_range(), | 68 | self.ctx.source_range(), |
@@ -71,7 +71,7 @@ impl<'a> EnumVariantRender<'a> { | |||
71 | .kind(CompletionItemKind::EnumVariant) | 71 | .kind(CompletionItemKind::EnumVariant) |
72 | .set_documentation(self.variant.docs(self.ctx.db())) | 72 | .set_documentation(self.variant.docs(self.ctx.db())) |
73 | .set_deprecated(self.ctx.is_deprecated(self.variant)) | 73 | .set_deprecated(self.ctx.is_deprecated(self.variant)) |
74 | .add_import(import_to_add, self.ctx.completion.config.resolve_edits_immediately()) | 74 | .add_import(import_to_add, self.ctx.completion.config.resolve_additional_edits_lazily()) |
75 | .detail(self.detail()); | 75 | .detail(self.detail()); |
76 | 76 | ||
77 | if self.variant_kind == StructKind::Tuple { | 77 | if self.variant_kind == StructKind::Tuple { |
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 20f2b9b7e..dd2c999ef 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -5,13 +5,13 @@ use syntax::{ast::Fn, display::function_declaration}; | |||
5 | use test_utils::mark; | 5 | use test_utils::mark; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd}, | 8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, |
9 | render::{builder_ext::Params, RenderContext}, | 9 | render::{builder_ext::Params, RenderContext}, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub(crate) fn render_fn<'a>( | 12 | pub(crate) fn render_fn<'a>( |
13 | ctx: RenderContext<'a>, | 13 | ctx: RenderContext<'a>, |
14 | import_to_add: Option<ImportToAdd>, | 14 | import_to_add: Option<ImportEdit>, |
15 | local_name: Option<String>, | 15 | local_name: Option<String>, |
16 | fn_: hir::Function, | 16 | fn_: hir::Function, |
17 | ) -> CompletionItem { | 17 | ) -> CompletionItem { |
@@ -39,7 +39,7 @@ impl<'a> FunctionRender<'a> { | |||
39 | FunctionRender { ctx, name, func: fn_, ast_node } | 39 | FunctionRender { ctx, name, func: fn_, ast_node } |
40 | } | 40 | } |
41 | 41 | ||
42 | fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem { | 42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
43 | let params = self.params(); | 43 | let params = self.params(); |
44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | 44 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) |
45 | .kind(self.kind()) | 45 | .kind(self.kind()) |
@@ -47,7 +47,7 @@ impl<'a> FunctionRender<'a> { | |||
47 | .set_deprecated(self.ctx.is_deprecated(self.func)) | 47 | .set_deprecated(self.ctx.is_deprecated(self.func)) |
48 | .detail(self.detail()) | 48 | .detail(self.detail()) |
49 | .add_call_parens(self.ctx.completion, self.name, params) | 49 | .add_call_parens(self.ctx.completion, self.name, params) |
50 | .add_import(import_to_add, self.ctx.completion.config.resolve_edits_immediately()) | 50 | .add_import(import_to_add, self.ctx.completion.config.resolve_additional_edits_lazily()) |
51 | .build() | 51 | .build() |
52 | } | 52 | } |
53 | 53 | ||
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs index be7c53659..bdbc642ca 100644 --- a/crates/completion/src/render/macro_.rs +++ b/crates/completion/src/render/macro_.rs | |||
@@ -5,13 +5,13 @@ use syntax::display::macro_label; | |||
5 | use test_utils::mark; | 5 | use test_utils::mark; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd}, | 8 | item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, |
9 | render::RenderContext, | 9 | render::RenderContext, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub(crate) fn render_macro<'a>( | 12 | pub(crate) fn render_macro<'a>( |
13 | ctx: RenderContext<'a>, | 13 | ctx: RenderContext<'a>, |
14 | import_to_add: Option<ImportToAdd>, | 14 | import_to_add: Option<ImportEdit>, |
15 | name: String, | 15 | name: String, |
16 | macro_: hir::MacroDef, | 16 | macro_: hir::MacroDef, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
@@ -38,7 +38,7 @@ impl<'a> MacroRender<'a> { | |||
38 | MacroRender { ctx, name, macro_, docs, bra, ket } | 38 | MacroRender { ctx, name, macro_, docs, bra, ket } |
39 | } | 39 | } |
40 | 40 | ||
41 | fn render(&self, import_to_add: Option<ImportToAdd>) -> Option<CompletionItem> { | 41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { |
42 | // FIXME: Currently proc-macro do not have ast-node, | 42 | // FIXME: Currently proc-macro do not have ast-node, |
43 | // such that it does not have source | 43 | // such that it does not have source |
44 | if self.macro_.is_proc_macro() { | 44 | if self.macro_.is_proc_macro() { |
@@ -50,7 +50,10 @@ impl<'a> MacroRender<'a> { | |||
50 | .kind(CompletionItemKind::Macro) | 50 | .kind(CompletionItemKind::Macro) |
51 | .set_documentation(self.docs.clone()) | 51 | .set_documentation(self.docs.clone()) |
52 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) | 52 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) |
53 | .add_import(import_to_add, self.ctx.completion.config.resolve_edits_immediately()) | 53 | .add_import( |
54 | import_to_add, | ||
55 | self.ctx.completion.config.resolve_additional_edits_lazily(), | ||
56 | ) | ||
54 | .detail(self.detail()); | 57 | .detail(self.detail()); |
55 | 58 | ||
56 | let needs_bang = self.needs_bang(); | 59 | let needs_bang = self.needs_bang(); |