aboutsummaryrefslogtreecommitdiff
path: root/crates/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion')
-rw-r--r--crates/completion/src/config.rs10
-rw-r--r--crates/completion/src/item.rs63
-rw-r--r--crates/completion/src/lib.rs2
-rw-r--r--crates/completion/src/render.rs13
-rw-r--r--crates/completion/src/render/enum_variant.rs8
-rw-r--r--crates/completion/src/render/function.rs8
-rw-r--r--crates/completion/src/render/macro_.rs11
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)]
272pub struct ImportToAdd { 272pub 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
278impl 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)]
281pub(crate) struct Builder { 300pub(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
19pub use crate::{ 19pub 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;
16use test_utils::mark; 16use test_utils::mark;
17 17
18use crate::{ 18use 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;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::{ 7use 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
12pub(crate) fn render_enum_variant<'a>( 12pub(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};
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::{ 7use 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
12pub(crate) fn render_fn<'a>( 12pub(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;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::{ 7use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd}, 8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
9 render::RenderContext, 9 render::RenderContext,
10}; 10};
11 11
12pub(crate) fn render_macro<'a>( 12pub(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();