Skip to content

Commit f6d2540

Browse files
Simplify import edit calculation
1 parent 68a747e commit f6d2540

File tree

12 files changed

+114
-111
lines changed

12 files changed

+114
-111
lines changed

crates/completion/src/config.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,10 @@ impl CompletionConfig {
3636
self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None }
3737
}
3838

39-
/// Whether the completions' additional edits are calculated later, during a resolve request or not.
40-
/// See `CompletionResolveCapability` for the details.
41-
pub fn resolve_edits_immediately(&self) -> bool {
42-
!self
43-
.active_resolve_capabilities
44-
.contains(&CompletionResolveCapability::AdditionalTextEdits)
39+
/// Whether the completions' additional edits are calculated when sending an initional completions list
40+
/// or later, in a separate resolve request.
41+
pub fn resolve_additional_edits_lazily(&self) -> bool {
42+
self.active_resolve_capabilities.contains(&CompletionResolveCapability::AdditionalTextEdits)
4543
}
4644
}
4745

crates/completion/src/item.rs

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub struct CompletionItem {
6868
ref_match: Option<(Mutability, CompletionScore)>,
6969

7070
/// The import data to add to completion's edits.
71-
import_to_add: Option<ImportToAdd>,
71+
import_to_add: Option<ImportEdit>,
7272
}
7373

7474
// We use custom debug for CompletionItem to make snapshot tests more readable.
@@ -209,7 +209,7 @@ impl CompletionItem {
209209
score: None,
210210
ref_match: None,
211211
import_to_add: None,
212-
resolve_import_immediately: true,
212+
resolve_import_lazily: false,
213213
}
214214
}
215215

@@ -262,27 +262,46 @@ impl CompletionItem {
262262
self.ref_match
263263
}
264264

265-
pub fn import_to_add(&self) -> Option<&ImportToAdd> {
265+
pub fn import_to_add(&self) -> Option<&ImportEdit> {
266266
self.import_to_add.as_ref()
267267
}
268268
}
269269

270270
/// An extra import to add after the completion is applied.
271271
#[derive(Debug, Clone)]
272-
pub struct ImportToAdd {
272+
pub struct ImportEdit {
273273
pub import_path: ModPath,
274274
pub import_scope: ImportScope,
275275
pub merge_behaviour: Option<MergeBehaviour>,
276276
}
277277

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+
278297
/// A helper to make `CompletionItem`s.
279298
#[must_use]
280299
#[derive(Clone)]
281300
pub(crate) struct Builder {
282301
source_range: TextRange,
283302
completion_kind: CompletionKind,
284-
import_to_add: Option<ImportToAdd>,
285-
resolve_import_immediately: bool,
303+
import_to_add: Option<ImportEdit>,
304+
resolve_import_lazily: bool,
286305
label: String,
287306
insert_text: Option<String>,
288307
insert_text_format: InsertTextFormat,
@@ -304,7 +323,6 @@ impl Builder {
304323
let mut label = self.label;
305324
let mut lookup = self.lookup;
306325
let mut insert_text = self.insert_text;
307-
let mut text_edits = TextEdit::builder();
308326

309327
if let Some(import_to_add) = self.import_to_add.as_ref() {
310328
let mut import_path_without_last_segment = import_to_add.import_path.to_owned();
@@ -319,35 +337,28 @@ impl Builder {
319337
}
320338
label = format!("{}::{}", import_path_without_last_segment, label);
321339
}
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-
}
334340
}
335341

336-
let original_edit = match self.text_edit {
342+
let mut text_edit = match self.text_edit {
337343
Some(it) => it,
338344
None => {
339345
TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
340346
}
341347
};
342348

343-
let mut resulting_edit = text_edits.finish();
344-
resulting_edit.union(original_edit).expect("Failed to unite text edits");
349+
if !self.resolve_import_lazily {
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+
}
345356

346357
CompletionItem {
347358
source_range: self.source_range,
348359
label,
349360
insert_text_format: self.insert_text_format,
350-
text_edit: resulting_edit,
361+
text_edit,
351362
detail: self.detail,
352363
documentation: self.documentation,
353364
lookup,
@@ -422,11 +433,11 @@ impl Builder {
422433
}
423434
pub(crate) fn add_import(
424435
mut self,
425-
import_to_add: Option<ImportToAdd>,
426-
resolve_import_immediately: bool,
436+
import_to_add: Option<ImportEdit>,
437+
resolve_import_lazily: bool,
427438
) -> Builder {
428439
self.import_to_add = import_to_add;
429-
self.resolve_import_immediately = resolve_import_immediately;
440+
self.resolve_import_lazily = resolve_import_lazily;
430441
self
431442
}
432443
pub(crate) fn set_ref_match(

crates/completion/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{completions::Completions, context::CompletionContext, item::Completi
1818

1919
pub use crate::{
2020
config::{CompletionConfig, CompletionResolveCapability},
21-
item::{CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd, InsertTextFormat},
21+
item::{CompletionItem, CompletionItemKind, CompletionScore, ImportEdit, InsertTextFormat},
2222
};
2323

2424
//FIXME: split the following feature into fine-grained features.

crates/completion/src/render.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use syntax::TextRange;
1616
use test_utils::mark;
1717

1818
use crate::{
19-
config::SnippetCap, item::ImportToAdd, CompletionContext, CompletionItem, CompletionItemKind,
19+
config::SnippetCap, item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind,
2020
CompletionKind, CompletionScore,
2121
};
2222

@@ -56,7 +56,7 @@ pub(crate) fn render_resolution_with_import<'a>(
5656
let local_name = import_path.segments.last()?.to_string();
5757
Render::new(ctx).render_resolution(
5858
local_name,
59-
Some(ImportToAdd { import_path, import_scope, merge_behaviour }),
59+
Some(ImportEdit { import_path, import_scope, merge_behaviour }),
6060
resolution,
6161
)
6262
}
@@ -147,7 +147,7 @@ impl<'a> Render<'a> {
147147
fn render_resolution(
148148
self,
149149
local_name: String,
150-
import_to_add: Option<ImportToAdd>,
150+
import_to_add: Option<ImportEdit>,
151151
resolution: &ScopeDef,
152152
) -> Option<CompletionItem> {
153153
let _p = profile::span("render_resolution");
@@ -194,7 +194,10 @@ impl<'a> Render<'a> {
194194
local_name,
195195
)
196196
.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+
)
198201
.build();
199202
return Some(item);
200203
}
@@ -249,7 +252,7 @@ impl<'a> Render<'a> {
249252

250253
let item = item
251254
.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())
253256
.set_documentation(docs)
254257
.set_ref_match(ref_match)
255258
.build();

crates/completion/src/render/enum_variant.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use itertools::Itertools;
55
use test_utils::mark;
66

77
use crate::{
8-
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
8+
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
99
render::{builder_ext::Params, RenderContext},
1010
};
1111

1212
pub(crate) fn render_enum_variant<'a>(
1313
ctx: RenderContext<'a>,
14-
import_to_add: Option<ImportToAdd>,
14+
import_to_add: Option<ImportEdit>,
1515
local_name: Option<String>,
1616
variant: hir::EnumVariant,
1717
path: Option<ModPath>,
@@ -62,7 +62,7 @@ impl<'a> EnumVariantRender<'a> {
6262
}
6363
}
6464

65-
fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem {
65+
fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
6666
let mut builder = CompletionItem::new(
6767
CompletionKind::Reference,
6868
self.ctx.source_range(),
@@ -71,7 +71,7 @@ impl<'a> EnumVariantRender<'a> {
7171
.kind(CompletionItemKind::EnumVariant)
7272
.set_documentation(self.variant.docs(self.ctx.db()))
7373
.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())
7575
.detail(self.detail());
7676

7777
if self.variant_kind == StructKind::Tuple {

crates/completion/src/render/function.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use syntax::{ast::Fn, display::function_declaration};
55
use test_utils::mark;
66

77
use crate::{
8-
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
8+
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
99
render::{builder_ext::Params, RenderContext},
1010
};
1111

1212
pub(crate) fn render_fn<'a>(
1313
ctx: RenderContext<'a>,
14-
import_to_add: Option<ImportToAdd>,
14+
import_to_add: Option<ImportEdit>,
1515
local_name: Option<String>,
1616
fn_: hir::Function,
1717
) -> CompletionItem {
@@ -39,15 +39,15 @@ impl<'a> FunctionRender<'a> {
3939
FunctionRender { ctx, name, func: fn_, ast_node }
4040
}
4141

42-
fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem {
42+
fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
4343
let params = self.params();
4444
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
4545
.kind(self.kind())
4646
.set_documentation(self.ctx.docs(self.func))
4747
.set_deprecated(self.ctx.is_deprecated(self.func))
4848
.detail(self.detail())
4949
.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())
5151
.build()
5252
}
5353

crates/completion/src/render/macro_.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use syntax::display::macro_label;
55
use test_utils::mark;
66

77
use crate::{
8-
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
8+
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit},
99
render::RenderContext,
1010
};
1111

1212
pub(crate) fn render_macro<'a>(
1313
ctx: RenderContext<'a>,
14-
import_to_add: Option<ImportToAdd>,
14+
import_to_add: Option<ImportEdit>,
1515
name: String,
1616
macro_: hir::MacroDef,
1717
) -> Option<CompletionItem> {
@@ -38,7 +38,7 @@ impl<'a> MacroRender<'a> {
3838
MacroRender { ctx, name, macro_, docs, bra, ket }
3939
}
4040

41-
fn render(&self, import_to_add: Option<ImportToAdd>) -> Option<CompletionItem> {
41+
fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
4242
// FIXME: Currently proc-macro do not have ast-node,
4343
// such that it does not have source
4444
if self.macro_.is_proc_macro() {
@@ -50,7 +50,10 @@ impl<'a> MacroRender<'a> {
5050
.kind(CompletionItemKind::Macro)
5151
.set_documentation(self.docs.clone())
5252
.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+
)
5457
.detail(self.detail());
5558

5659
let needs_bang = self.needs_bang();

crates/ide/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub use crate::{
8181
};
8282
pub use completion::{
8383
CompletionConfig, CompletionItem, CompletionItemKind, CompletionResolveCapability,
84-
CompletionScore, ImportToAdd, InsertTextFormat,
84+
CompletionScore, ImportEdit, InsertTextFormat,
8585
};
8686
pub use ide_db::{
8787
call_info::CallInfo,

crates/rust-analyzer/src/caps.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool
104104
}
105105

106106
/// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports.
107-
pub fn enabled_completions_resolve_capabilities(
107+
pub(crate) fn enabled_completions_resolve_capabilities(
108108
caps: &ClientCapabilities,
109109
) -> Option<FxHashSet<CompletionResolveCapability>> {
110110
Some(
@@ -118,13 +118,11 @@ pub fn enabled_completions_resolve_capabilities(
118118
.as_ref()?
119119
.properties
120120
.iter()
121-
.filter_map(|cap_string| {
122-
Some(match cap_string.as_str() {
123-
"additionalTextEdits" => CompletionResolveCapability::AdditionalTextEdits,
124-
"detail" => CompletionResolveCapability::Detail,
125-
"documentation" => CompletionResolveCapability::Documentation,
126-
_unsupported => return None,
127-
})
121+
.filter_map(|cap_string| match cap_string.as_str() {
122+
"additionalTextEdits" => Some(CompletionResolveCapability::AdditionalTextEdits),
123+
"detail" => Some(CompletionResolveCapability::Detail),
124+
"documentation" => Some(CompletionResolveCapability::Documentation),
125+
_unsupported => None,
128126
})
129127
.collect(),
130128
)

crates/rust-analyzer/src/global_state.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{sync::Arc, time::Instant};
77

88
use crossbeam_channel::{unbounded, Receiver, Sender};
99
use flycheck::FlycheckHandle;
10-
use ide::{Analysis, AnalysisHost, Change, CompletionItem, FileId};
10+
use ide::{Analysis, AnalysisHost, Change, FileId, ImportEdit};
1111
use ide_db::base_db::{CrateId, VfsPath};
1212
use lsp_types::{SemanticTokens, Url};
1313
use parking_lot::{Mutex, RwLock};
@@ -53,7 +53,7 @@ pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
5353

5454
pub(crate) struct CompletionResolveData {
5555
pub(crate) file_id: FileId,
56-
pub(crate) item: CompletionItem,
56+
pub(crate) import_edit: ImportEdit,
5757
}
5858

5959
/// `GlobalState` is the primary mutable state of the language server

0 commit comments

Comments
 (0)