Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide-completion/src/completions.rs54
-rw-r--r--crates/ide-completion/src/completions/attribute.rs8
-rw-r--r--crates/ide-completion/src/completions/attribute/derive.rs8
-rw-r--r--crates/ide-completion/src/completions/dot.rs16
-rw-r--r--crates/ide-completion/src/completions/expr.rs2
-rw-r--r--crates/ide-completion/src/completions/flyimport.rs64
-rw-r--r--crates/ide-completion/src/completions/item_list.rs8
-rw-r--r--crates/ide-completion/src/completions/pattern.rs19
-rw-r--r--crates/ide-completion/src/completions/record.rs14
-rw-r--r--crates/ide-completion/src/completions/type.rs2
-rw-r--r--crates/ide-completion/src/completions/use_.rs4
-rw-r--r--crates/ide-completion/src/completions/vis.rs4
-rw-r--r--crates/ide-completion/src/context.rs2
-rw-r--r--crates/ide-completion/src/context/analysis.rs1
-rw-r--r--crates/ide-completion/src/item.rs18
-rw-r--r--crates/ide-completion/src/render.rs173
-rw-r--r--crates/ide-completion/src/render/function.rs97
-rw-r--r--crates/ide-completion/src/render/literal.rs3
-rw-r--r--crates/ide-completion/src/render/macro_.rs23
-rw-r--r--crates/ide-completion/src/tests/pattern.rs5
-rw-r--r--crates/rust-analyzer/src/to_proto.rs39
21 files changed, 352 insertions, 212 deletions
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 4f522ee761..147563ef10 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -36,9 +36,9 @@ use crate::{
const_::render_const,
function::{render_fn, render_method},
literal::{render_struct_literal, render_variant_lit},
- macro_::render_macro,
+ macro_::{render_macro, render_macro_pat},
pattern::{render_struct_pat, render_variant_pat},
- render_field, render_path_resolution, render_resolution_simple, render_tuple_field,
+ render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
type_alias::{render_type_alias, render_type_alias_with_eq},
union_literal::render_union_literal,
RenderContext,
@@ -134,10 +134,14 @@ impl Completions {
item.add_to(self);
}
- pub(crate) fn add_crate_roots(&mut self, ctx: &CompletionContext) {
+ pub(crate) fn add_crate_roots(
+ &mut self,
+ ctx: &CompletionContext,
+ path_ctx: &PathCompletionCtx,
+ ) {
ctx.process_all_names(&mut |name, res| match res {
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
- self.add_module(ctx, m, name);
+ self.add_module(ctx, path_ctx, m, name);
}
_ => (),
});
@@ -160,25 +164,36 @@ impl Completions {
);
}
- pub(crate) fn add_resolution_simple(
+ pub(crate) fn add_pattern_resolution(
&mut self,
ctx: &CompletionContext,
+ pattern_ctx: &PatternContext,
local_name: hir::Name,
resolution: hir::ScopeDef,
) {
if ctx.is_scope_def_hidden(resolution) {
+ cov_mark::hit!(qualified_path_doc_hidden);
return;
}
- self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution).build());
+ self.add(
+ render_pattern_resolution(RenderContext::new(ctx), pattern_ctx, local_name, resolution)
+ .build(),
+ );
}
pub(crate) fn add_module(
&mut self,
ctx: &CompletionContext,
+ path_ctx: &PathCompletionCtx,
module: hir::Module,
local_name: hir::Name,
) {
- self.add_resolution_simple(ctx, local_name, hir::ScopeDef::ModuleDef(module.into()));
+ self.add_path_resolution(
+ ctx,
+ path_ctx,
+ local_name,
+ hir::ScopeDef::ModuleDef(module.into()),
+ );
}
pub(crate) fn add_macro(
@@ -204,6 +219,29 @@ impl Completions {
);
}
+ pub(crate) fn add_macro_pat(
+ &mut self,
+ ctx: &CompletionContext,
+ pattern_ctx: &PatternContext,
+ mac: hir::Macro,
+ local_name: hir::Name,
+ ) {
+ let is_private_editable = match ctx.is_visible(&mac) {
+ Visible::Yes => false,
+ Visible::Editable => true,
+ Visible::No => return,
+ };
+ self.add(
+ render_macro_pat(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ pattern_ctx,
+ local_name,
+ mac,
+ )
+ .build(),
+ );
+ }
+
pub(crate) fn add_function(
&mut self,
ctx: &CompletionContext,
@@ -341,6 +379,7 @@ impl Completions {
pub(crate) fn add_field(
&mut self,
ctx: &CompletionContext,
+ dot_access: &DotAccess,
receiver: Option<hir::Name>,
field: hir::Field,
ty: &hir::Type,
@@ -352,6 +391,7 @@ impl Completions {
};
let item = render_field(
RenderContext::new(ctx).private_editable(is_private_editable),
+ dot_access,
receiver,
field,
ty,
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index 1c4f9a3113..154c096f4d 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -95,7 +95,7 @@ pub(crate) fn complete_attribute_path(
acc.add_macro(ctx, path_ctx, m, name)
}
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
- acc.add_module(ctx, m, name)
+ acc.add_module(ctx, path_ctx, m, name)
}
_ => (),
}
@@ -103,14 +103,16 @@ pub(crate) fn complete_attribute_path(
return;
}
// fresh use tree with leading colon2, only show crate roots
- Qualified::Absolute => acc.add_crate_roots(ctx),
+ Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
// only show modules in a fresh UseTree
Qualified::No => {
ctx.process_all_names(&mut |name, def| match def {
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
acc.add_macro(ctx, path_ctx, m, name)
}
- hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
+ hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
+ acc.add_module(ctx, path_ctx, m, name)
+ }
_ => (),
});
acc.add_nameref_keywords_with_colon(ctx);
diff --git a/crates/ide-completion/src/completions/attribute/derive.rs b/crates/ide-completion/src/completions/attribute/derive.rs
index 21298b6ca5..48eb76029f 100644
--- a/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/crates/ide-completion/src/completions/attribute/derive.rs
@@ -35,12 +35,14 @@ pub(crate) fn complete_derive_path(
{
acc.add_macro(ctx, path_ctx, mac, name)
}
- ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
+ ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
+ acc.add_module(ctx, path_ctx, m, name)
+ }
_ => (),
}
}
}
- Qualified::Absolute => acc.add_crate_roots(ctx),
+ Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
// only show modules in a fresh UseTree
Qualified::No => {
ctx.process_all_names(&mut |name, def| {
@@ -51,7 +53,7 @@ pub(crate) fn complete_derive_path(
mac
}
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
- return acc.add_module(ctx, m, name);
+ return acc.add_module(ctx, path_ctx, m, name);
}
_ => return,
};
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index b58a9f39f2..bf0bce2198 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -29,7 +29,7 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext, dot_a
acc,
ctx,
&receiver_ty,
- |acc, field, ty| acc.add_field(ctx, None, field, &ty),
+ |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty),
|acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
);
}
@@ -64,7 +64,19 @@ pub(crate) fn complete_undotted_self(
acc,
ctx,
&ty,
- |acc, field, ty| acc.add_field(ctx, Some(hir::known::SELF_PARAM), field, &ty),
+ |acc, field, ty| {
+ acc.add_field(
+ ctx,
+ &DotAccess {
+ receiver: None,
+ receiver_ty: None,
+ kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
+ },
+ Some(hir::known::SELF_PARAM),
+ field,
+ &ty,
+ )
+ },
|acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty),
);
complete_methods(ctx, &ty, |func| {
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 9c003be6af..6b36801205 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -152,7 +152,7 @@ pub(crate) fn complete_expr_path(
_ => (),
}
}
- Qualified::Absolute => acc.add_crate_roots(ctx),
+ Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
Qualified::No => {
acc.add_nameref_keywords_with_colon(ctx);
if let Some(adt) =
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index 129910465c..fa8c0eb77a 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -12,7 +12,7 @@ use crate::{
CompletionContext, DotAccess, PathCompletionCtx, PathKind, PatternContext, Qualified,
TypeLocation,
},
- render::{render_resolution_with_import, RenderContext},
+ render::{render_resolution_with_import, render_resolution_with_import_pat, RenderContext},
};
use super::Completions;
@@ -149,30 +149,22 @@ pub(crate) fn import_on_the_fly_path(
pub(crate) fn import_on_the_fly_pat(
acc: &mut Completions,
ctx: &CompletionContext,
- pat_ctx: &PatternContext,
+ pattern_ctx: &PatternContext,
) -> Option<()> {
if !ctx.config.enable_imports_on_the_fly {
return None;
}
- if let PatternContext { record_pat: Some(_), .. } = pat_ctx {
+ if let PatternContext { record_pat: Some(_), .. } = pattern_ctx {
return None;
}
let potential_import_name = import_name(ctx);
let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
- import_on_the_fly(
+ import_on_the_fly_pat2(
acc,
ctx,
- &PathCompletionCtx {
- has_call_parens: false,
- has_macro_bang: false,
- qualified: Qualified::No,
- parent: None,
- kind: crate::context::PathKind::Pat { pat_ctx: pat_ctx.clone() },
- has_type_args: false,
- use_tree_parent: false,
- },
+ pattern_ctx,
import_assets,
ctx.original_token.parent()?,
potential_import_name,
@@ -287,6 +279,50 @@ fn import_on_the_fly(
Some(())
}
+fn import_on_the_fly_pat2(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ pattern_ctx: &PatternContext,
+ import_assets: ImportAssets,
+ position: SyntaxNode,
+ potential_import_name: String,
+) -> Option<()> {
+ let _p = profile::span("import_on_the_fly_pat").detail(|| potential_import_name.clone());
+
+ if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
+ return None;
+ }
+
+ let ns_filter = |import: &LocatedImport| match import.original_item {
+ ItemInNs::Macros(mac) => mac.is_fn_like(ctx.db),
+ ItemInNs::Types(_) => true,
+ ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
+ };
+ let user_input_lowercased = potential_import_name.to_lowercase();
+
+ acc.add_all(
+ import_assets
+ .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
+ .into_iter()
+ .filter(ns_filter)
+ .filter(|import| {
+ !ctx.is_item_hidden(&import.item_to_import)
+ && !ctx.is_item_hidden(&import.original_item)
+ })
+ .sorted_by_key(|located_import| {
+ compute_fuzzy_completion_order_key(
+ &located_import.import_path,
+ &user_input_lowercased,
+ )
+ })
+ .filter_map(|import| {
+ render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import)
+ })
+ .map(|builder| builder.build()),
+ );
+ Some(())
+}
+
fn import_on_the_fly_method(
acc: &mut Completions,
ctx: &CompletionContext,
@@ -295,7 +331,7 @@ fn import_on_the_fly_method(
position: SyntaxNode,
potential_import_name: String,
) -> Option<()> {
- let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
+ let _p = profile::span("import_on_the_fly_method").detail(|| potential_import_name.clone());
if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
return None;
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 329d08a9e7..4a32e0ebf5 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -45,7 +45,7 @@ pub(crate) fn complete_item_list(
acc.add_macro(ctx, path_ctx, m, name)
}
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
- acc.add_module(ctx, m, name)
+ acc.add_module(ctx, path_ctx, m, name)
}
_ => (),
}
@@ -55,13 +55,15 @@ pub(crate) fn complete_item_list(
acc.add_keyword(ctx, "super::");
}
}
- Qualified::Absolute => acc.add_crate_roots(ctx),
+ Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
Qualified::No if ctx.qualifier_ctx.none() => {
ctx.process_all_names(&mut |name, def| match def {
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
acc.add_macro(ctx, path_ctx, m, name)
}
- hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
+ hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
+ acc.add_module(ctx, path_ctx, m, name)
+ }
_ => (),
});
acc.add_nameref_keywords_with_colon(ctx);
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 91d5356541..4ea80a5077 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -82,20 +82,7 @@ pub(crate) fn complete_pattern(
hir::ModuleDef::Const(..) => refutable,
hir::ModuleDef::Module(..) => true,
hir::ModuleDef::Macro(mac) if mac.is_fn_like(ctx.db) => {
- return acc.add_macro(
- ctx,
- &PathCompletionCtx {
- has_call_parens: false,
- has_macro_bang: false,
- qualified: Qualified::No,
- parent: None,
- kind: crate::context::PathKind::Pat { pat_ctx: pattern_ctx.clone() },
- has_type_args: false,
- use_tree_parent: false,
- },
- mac,
- name,
- )
+ return acc.add_macro_pat(ctx, pattern_ctx, mac, name);
}
_ => false,
},
@@ -116,7 +103,7 @@ pub(crate) fn complete_pattern(
| ScopeDef::Unknown => false,
};
if add_simple_path {
- acc.add_resolution_simple(ctx, name, res);
+ acc.add_pattern_resolution(ctx, pattern_ctx, name, res);
}
});
}
@@ -205,7 +192,7 @@ pub(crate) fn complete_pattern_path(
}
}
// qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
- Qualified::Absolute => acc.add_crate_roots(ctx),
+ Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
Qualified::No => {
ctx.process_all_names(&mut |name, res| {
// FIXME: properly filter here
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 9f834e1ca1..8cef3a7018 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -3,7 +3,7 @@ use ide_db::SymbolKind;
use syntax::ast::{self, Expr};
use crate::{
- context::{ExprCtx, PathCompletionCtx, PatternContext, Qualified},
+ context::{DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, PatternContext, Qualified},
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
CompletionRelevancePostfixMatch, Completions,
};
@@ -107,7 +107,17 @@ fn complete_fields(
missing_fields: Vec<(hir::Field, hir::Type)>,
) {
for (field, ty) in missing_fields {
- acc.add_field(ctx, None, field, &ty);
+ acc.add_field(
+ ctx,
+ &DotAccess {
+ receiver: None,
+ receiver_ty: None,
+ kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
+ },
+ None,
+ field,
+ &ty,
+ );
}
}
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index dea0c701b8..c5b65d36ae 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -141,7 +141,7 @@ pub(crate) fn complete_type_path(
_ => (),
}
}
- Qualified::Absolute => acc.add_crate_roots(ctx),
+ Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
Qualified::No => {
acc.add_nameref_keywords_with_colon(ctx);
if let TypeLocation::TypeBound = location {
diff --git a/crates/ide-completion/src/completions/use_.rs b/crates/ide-completion/src/completions/use_.rs
index 2c039d5018..c98590f136 100644
--- a/crates/ide-completion/src/completions/use_.rs
+++ b/crates/ide-completion/src/completions/use_.rs
@@ -89,7 +89,7 @@ pub(crate) fn complete_use_path(
// fresh use tree with leading colon2, only show crate roots
Qualified::Absolute => {
cov_mark::hit!(use_tree_crate_roots_only);
- acc.add_crate_roots(ctx);
+ acc.add_crate_roots(ctx, path_ctx);
}
// only show modules and non-std enum in a fresh UseTree
Qualified::No => {
@@ -97,7 +97,7 @@ pub(crate) fn complete_use_path(
ctx.process_all_names(&mut |name, res| {
match res {
ScopeDef::ModuleDef(hir::ModuleDef::Module(module)) => {
- acc.add_module(ctx, module, name);
+ acc.add_module(ctx, path_ctx, module, name);
}
ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
// exclude prelude enum
diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs
index 30de0e94f7..6621aafe4b 100644
--- a/crates/ide-completion/src/completions/vis.rs
+++ b/crates/ide-completion/src/completions/vis.rs
@@ -8,7 +8,7 @@ use crate::{
pub(crate) fn complete_vis_path(
acc: &mut Completions,
ctx: &CompletionContext,
- PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
+ path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
&has_in_token: &bool,
) {
match qualified {
@@ -23,7 +23,7 @@ pub(crate) fn complete_vis_path(
if let Some(next) = next_towards_current {
if let Some(name) = next.name(ctx.db) {
cov_mark::hit!(visibility_qualified);
- acc.add_module(ctx, next, name);
+ acc.add_module(ctx, path_ctx, next, name);
}
}
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 441f7ad70b..8ea03358ae 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -61,6 +61,8 @@ pub(crate) struct PathCompletionCtx {
pub(super) qualified: Qualified,
/// The parent of the path we are completing.
pub(super) parent: Option<ast::Path>,
+ /// The path of which we are completing the segment
+ pub(super) path: ast::Path,
pub(super) kind: PathKind,
/// Whether the path segment has type args or not.
pub(super) has_type_args: bool,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 7e6c842b1e..e13950d56a 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -556,6 +556,7 @@ impl<'a> CompletionContext<'a> {
has_macro_bang: false,
qualified: Qualified::No,
parent: path.parent_path(),
+ path: path.clone(),
kind: PathKind::Item { kind: ItemListKind::SourceFile },
has_type_args: false,
use_tree_parent: false,
diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs
index 4774fe9db7..2b10dccb80 100644
--- a/crates/ide-completion/src/item.rs
+++ b/crates/ide-completion/src/item.rs
@@ -6,7 +6,7 @@ use hir::{Documentation, Mutability};
use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind};
use smallvec::SmallVec;
use stdx::{impl_from, never};
-use syntax::{SmolStr, TextRange};
+use syntax::{SmolStr, TextRange, TextSize};
use text_edit::TextEdit;
use crate::{
@@ -68,7 +68,7 @@ pub struct CompletionItem {
/// Indicates that a reference or mutable reference to this variable is a
/// possible match.
- ref_match: Option<Mutability>,
+ ref_match: Option<(Mutability, TextSize)>,
/// The import data to add to completion's edits.
import_to_add: SmallVec<[LocatedImport; 1]>,
@@ -104,8 +104,8 @@ impl fmt::Debug for CompletionItem {
s.field("relevance", &self.relevance);
}
- if let Some(mutability) = &self.ref_match {
- s.field("ref_match", &format!("&{}", mutability.as_keyword_for_ref()));
+ if let Some((mutability, offset)) = &self.ref_match {
+ s.field("ref_match", &format!("&{}@{offset:?}", mutability.as_keyword_for_ref()));
}
if self.trigger_call_info {
s.field("trigger_call_info", &true);
@@ -395,14 +395,14 @@ impl CompletionItem {
self.trigger_call_info
}
- pub fn ref_match(&self) -> Option<(Mutability, CompletionRelevance)> {
+ pub fn ref_match(&self) -> Option<(Mutability, TextSize, CompletionRelevance)> {
// Relevance of the ref match should be the same as the original
// match, but with exact type match set because self.ref_match
// is only set if there is an exact type match.
let mut relevance = self.relevance;
relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact);
- self.ref_match.map(|mutability| (mutability, relevance))
+ self.ref_match.map(|(mutability, offset)| (mutability, offset, relevance))
}
pub fn imports_to_add(&self) -> &[LocatedImport] {
@@ -428,7 +428,7 @@ pub(crate) struct Builder {
deprecated: bool,
trigger_call_info: bool,
relevance: CompletionRelevance,
- ref_match: Option<Mutability>,
+ ref_match: Option<(Mutability, TextSize)>,
}
impl Builder {
@@ -548,8 +548,8 @@ impl Builder {
self.imports_to_add.push(import_to_add);
self
}
- pub(crate) fn ref_match(&mut self, mutability: Mutability) -> &mut Builder {
- self.ref_match = Some(mutability);
+ pub(crate) fn ref_match(&mut self, mutability: Mutability, offset: TextSize) -> &mut Builder {
+ self.ref_match = Some((mutability, offset));
self
}
}
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index 9c339a13e7..6571e67352 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -14,12 +14,16 @@ use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
use ide_db::{
helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind,
};
-use syntax::{SmolStr, SyntaxKind, TextRange};
+use syntax::{AstNode, SmolStr, SyntaxKind, TextRange};
use crate::{
- context::{PathCompletionCtx, PathKind},
+ context::{DotAccess, PathCompletionCtx, PathKind, PatternContext},
item::{Builder, CompletionRelevanceTypeMatch},
- render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
+ render::{
+ function::render_fn,
+ literal::render_variant_lit,
+ macro_::{render_macro, render_macro_pat},
+ },
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
};
/// Interface for data and methods required for items rendering.
@@ -106,6 +110,7 @@ impl<'a> RenderContext<'a> {
pub(crate) fn render_field(
ctx: RenderContext<'_>,
+ dot_access: &DotAccess,
receiver: Option<hir::Name>,
field: hir::Field,
ty: &hir::Type,
@@ -130,10 +135,10 @@ pub(crate) fn render_field(
if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") {
item.insert_text(format!("r#{}", name));
}
- if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
- // FIXME
- // For now we don't properly calculate the edits for ref match
- // completions on struct fields, so we've disabled them. See #8058.
+ if let Some(receiver) = &dot_access.receiver {
+ if let Some(ref_match) = compute_ref_match(ctx.completion, ty) {
+ item.ref_match(ref_match, receiver.syntax().text_range().start());
+ }
}
item.build()
}
@@ -153,21 +158,29 @@ pub(crate) fn render_tuple_field(
item.build()
}
+pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext) -> CompletionItem {
+ let mut builder =
+ CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string);
+ builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() });
+ builder.build()
+}
+
pub(crate) fn render_path_resolution(
ctx: RenderContext<'_>,
path_ctx: &PathCompletionCtx,
local_name: hir::Name,
resolution: ScopeDef,
) -> Builder {
- render_resolution_(ctx, path_ctx, local_name, None, resolution)
+ render_resolution_path(ctx, path_ctx, local_name, None, resolution)
}
-pub(crate) fn render_resolution_simple(
+pub(crate) fn render_pattern_resolution(
ctx: RenderContext<'_>,
+ pattern_ctx: &PatternContext,
local_name: hir::Name,
resolution: ScopeDef,
) -> Builder {
- render_resolution_simple_(ctx, local_name, None, resolution)
+ render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution)
}
pub(crate) fn render_resolution_with_import(
@@ -176,23 +189,56 @@ pub(crate) fn render_resolution_with_import(
import_edit: LocatedImport,
) -> Option<Builder> {
let resolution = ScopeDef::from(import_edit.original_item);
- let local_name = match resolution {
+ let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
+
+ Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution))
+}
+
+pub(crate) fn render_resolution_with_import_pat(
+ ctx: RenderContext<'_>,
+ pattern_ctx: &PatternContext,
+ import_edit: LocatedImport,
+) -> Option<Builder> {
+ let resolution = ScopeDef::from(import_edit.original_item);
+ let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?;
+ Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution))
+}
+
+fn scope_def_to_name(
+ resolution: ScopeDef,
+ ctx: &RenderContext,
+ import_edit: &LocatedImport,
+) -> Option<hir::Name> {
+ Some(match resolution {
ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
_ => item_name(ctx.db(), import_edit.original_item)?,
- };
- Some(render_resolution_(ctx, path_ctx, local_name, Some(import_edit), resolution))
+ })
}
-pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext) -> CompletionItem {
- let mut builder =
- CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string);
- builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() });
- builder.build()
+fn render_resolution_pat(
+ ctx: RenderContext<'_>,
+ pattern_ctx: &PatternContext,
+ local_name: hir::Name,
+ import_to_add: Option<LocatedImport>,
+ resolution: ScopeDef,
+) -> Builder {
+ let _p = profile::span("render_resolution");
+ use hir::ModuleDef::*;
+
+ match resolution {
+ ScopeDef::ModuleDef(Macro(mac)) => {
+ let ctx = ctx.import_to_add(import_to_add);
+ return render_macro_pat(ctx, pattern_ctx, local_name, mac);
+ }
+ _ => (),
+ }
+
+ render_resolution_simple_(ctx, local_name, import_to_add, resolution)
}
-fn render_resolution_(
+fn render_resolution_path(
ctx: RenderContext<'_>,
path_ctx: &PathCompletionCtx,
local_name: hir::Name,
@@ -221,19 +267,12 @@ fn render_resolution_(
}
_ => (),
}
- render_resolution_simple_type(ctx, path_ctx, local_name, import_to_add, resolution)
-}
-fn render_resolution_simple_type(
- ctx: RenderContext<'_>,
- path_ctx: &PathCompletionCtx,
- local_name: hir::Name,
- import_to_add: Option<LocatedImport>,
- resolution: ScopeDef,
-) -> Builder {
+ let completion = ctx.completion;
let cap = ctx.snippet_cap();
- let db = ctx.completion.db;
- let config = ctx.completion.config;
+ let db = completion.db;
+ let config = completion.config;
+
let name = local_name.to_smol_str();
let mut item = render_resolution_simple_(ctx, local_name, import_to_add, resolution);
// Add `<>` for generic types
@@ -250,6 +289,7 @@ fn render_resolution_simple_type(
}
_ => false,
};
+
if has_non_default_type_params {
cov_mark::hit!(inserts_angle_brackets_for_generics);
item.lookup_by(name.clone())
@@ -259,6 +299,23 @@ fn render_resolution_simple_type(
}
}
}
+ if let ScopeDef::Local(local) = resolution {
+ let ty = local.ty(db);
+ if !ty.is_unknown() {
+ item.detail(ty.display(db).to_string());
+ }
+
+ item.set_relevance(CompletionRelevance {
+ type_match: compute_type_match(completion, &ty),
+ exact_name_match: compute_exact_name_match(completion, &name),
+ is_local: true,
+ ..CompletionRelevance::default()
+ });
+
+ if let Some(ref_match) = compute_ref_match(completion, &ty) {
+ item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
+ }
+ };
item
}
@@ -269,11 +326,25 @@ fn render_resolution_simple_(
resolution: ScopeDef,
) -> Builder {
let _p = profile::span("render_resolution");
- use hir::ModuleDef::*;
let db = ctx.db();
let ctx = ctx.import_to_add(import_to_add);
- let kind = match resolution {
+ let kind = res_to_kind(resolution);
+
+ let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.to_smol_str());
+ item.set_relevance(ctx.completion_relevance())
+ .set_documentation(scope_def_docs(db, resolution))
+ .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
+
+ if let Some(import_to_add) = ctx.import_to_add {
+ item.add_import(import_to_add);
+ }
+ item
+}
+
+fn res_to_kind(resolution: ScopeDef) -> CompletionItemKind {
+ use hir::ModuleDef::*;
+ match resolution {
ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,
ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),
ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
@@ -299,36 +370,7 @@ fn render_resolution_simple_(
ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
}
- };
-
- let local_name = local_name.to_smol_str();
- let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
- item.set_relevance(ctx.completion_relevance());
- if let ScopeDef::Local(local) = resolution {
- let ty = local.ty(db);
- if !ty.is_unknown() {
- item.detail(ty.display(db).to_string());
- }
-
- item.set_relevance(CompletionRelevance {
- type_match: compute_type_match(ctx.completion, &ty),
- exact_name_match: compute_exact_name_match(ctx.completion, &local_name),
- is_local: true,
- ..CompletionRelevance::default()
- });
-
- if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) {
- item.ref_match(ref_match);
- }
- };
-
- item.set_documentation(scope_def_docs(db, resolution))
- .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
-
- if let Some(import_to_add) = ctx.import_to_add {
- item.add_import(import_to_add);
}
- item
}
fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
@@ -455,7 +497,7 @@ mod tests {
let relevance = display_relevance(it.relevance());
items.push(format!("{} {} {}\n", tag, it.label(), relevance));
- if let Some((mutability, relevance)) = it.ref_match() {
+ if let Some((mutability, _offset, relevance)) = it.ref_match() {
let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label());
let relevance = display_relevance(relevance);
@@ -1494,9 +1536,6 @@ impl Foo { fn baz(&self) -> u32 { 0 } }
fn foo(f: Foo) { let _: &u32 = f.b$0 }
"#,
&[CompletionItemKind::Method, CompletionItemKind::SymbolKind(SymbolKind::Field)],
- // FIXME
- // Ideally we'd also suggest &f.bar and &f.baz() as exact
- // type matches. See #8058.
expect![[r#"
[
CompletionItem {
@@ -1507,6 +1546,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
kind: Method,
lookup: "baz",
detail: "fn(&self) -> u32",
+ ref_match: "&@96",
},
CompletionItem {
label: "bar",
@@ -1517,6 +1557,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
Field,
),
detail: "u32",
+ ref_match: "&@96",
},
]
"#]],
@@ -1525,7 +1566,6 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
#[test]
fn qualified_path_ref() {
- // disabled right now because it doesn't render correctly, #8058
check_kinds(
r#"
struct S;
@@ -1554,6 +1594,7 @@ fn main() {
),
lookup: "foo",
detail: "fn() -> S",
+ ref_match: "&@92",
},
]
"#]],
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index 3666ee40e2..37486e4d93 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -4,20 +4,19 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
use ide_db::{SnippetCap, SymbolKind};
use itertools::Itertools;
use stdx::{format_to, to_lower_snake_case};
-use syntax::SmolStr;
+use syntax::{AstNode, SmolStr};
use crate::{
- context::{
- CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, Qualified,
- },
+ context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind},
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
CallableSnippets,
};
-enum FuncKind {
- Function,
- Method(Option<hir::Name>),
+#[derive(Debug)]
+enum FuncKind<'ctx> {
+ Function(&'ctx PathCompletionCtx),
+ Method(&'ctx DotAccess, Option<hir::Name>),
}
pub(crate) fn render_fn(
@@ -27,29 +26,7 @@ pub(crate) fn render_fn(
func: hir::Function,
) -> Builder {
let _p = profile::span("render_fn");
- let func_kind = FuncKind::Function;
- let params = match ctx.completion.config.snippet_cap {
- Some(_) => {
- if !matches!(
- path_ctx,
- PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }
- | PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }
- ) {
- params(ctx.completion, func, &func_kind, false)
- } else {
- None
- }
- }
- _ => None,
- };
- render(
- ctx,
- local_name,
- func,
- func_kind,
- params,
- matches!(path_ctx.qualified, Qualified::With { .. }),
- )
+ render(ctx, local_name, func, FuncKind::Function(path_ctx))
}
pub(crate) fn render_method(
@@ -60,16 +37,7 @@ pub(crate) fn render_method(
func: hir::Function,
) -> Builder {
let _p = profile::span("render_method");
- let func_kind = FuncKind::Method(receiver);
- let params = match ctx.completion.config.snippet_cap {
- Some(_) => match dot_access {
- DotAccess { kind: DotAccessKind::Method { has_parens: true }, .. } => None,
- _ => params(ctx.completion, func, &func_kind, true),
- },
- _ => None,
- };
-
- render(ctx, local_name, func, func_kind, params, false)
+ render(ctx, local_name, func, FuncKind::Method(dot_access, receiver))
}
fn render(
@@ -77,15 +45,13 @@ fn render(
local_name: Option<hir::Name>,
func: hir::Function,
func_kind: FuncKind,
- params: Option<(Option<hir::SelfParam>, Vec<hir::Param>)>,
- qualified_path: bool,
) -> Builder {
let db = completion.db;
let name = local_name.unwrap_or_else(|| func.name(db));
let call = match &func_kind {
- FuncKind::Method(Some(receiver)) => format!("{}.{}", receiver, &name).into(),
+ FuncKind::Method(_, Some(receiver)) => format!("{}.{}", receiver, &name).into(),
_ => name.to_smol_str(),
};
let mut item = CompletionItem::new(
@@ -111,11 +77,14 @@ fn render(
});
if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
- // FIXME For now we don't properly calculate the edits for ref match
- // completions on methods or qualified paths, so we've disabled them.
- // See #8058.
- if matches!(func_kind, FuncKind::Function) && !qualified_path {
- item.ref_match(ref_match);
+ match func_kind {
+ FuncKind::Function(path_ctx) => {
+ item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
+ }
+ FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
+ item.ref_match(ref_match, receiver.syntax().text_range().start());
+ }
+ _ => (),
}
}
@@ -124,12 +93,34 @@ fn render(
.detail(detail(db, func))
.lookup_by(name.to_smol_str());
- match completion.config.snippet_cap.zip(params) {
- Some((cap, (self_param, params))) => {
- add_call_parens(&mut item, completion, cap, call, self_param, params);
+ match ctx.completion.config.snippet_cap {
+ Some(cap) => {
+ let complete_params = match func_kind {
+ FuncKind::Function(PathCompletionCtx {
+ kind: PathKind::Expr { .. },
+ has_call_parens: false,
+ ..
+ }) => Some(false),
+ FuncKind::Method(
+ DotAccess {
+ kind:
+ DotAccessKind::Method { has_parens: false } | DotAccessKind::Field { .. },
+ ..
+ },
+ _,
+ ) => Some(true),
+ _ => None,
+ };
+ if let Some(has_dot_receiver) = complete_params {
+ if let Some((self_param, params)) =
+ params(ctx.completion, func, &func_kind, has_dot_receiver)
+ {
+ add_call_parens(&mut item, completion, cap, call, self_param, params);
+ }
+ }
}
_ => (),
- }
+ };
match ctx.import_to_add {
Some(import_to_add) => {
@@ -291,7 +282,7 @@ fn params(
}
}
- let self_param = if has_dot_receiver || matches!(func_kind, FuncKind::Method(Some(_))) {
+ let self_param = if has_dot_receiver || matches!(func_kind, FuncKind::Method(_, Some(_))) {
None
} else {
func.self_param(ctx.db)
diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs
index b89030990e..7b0555d5a4 100644
--- a/crates/ide-completion/src/render/literal.rs
+++ b/crates/ide-completion/src/render/literal.rs
@@ -2,6 +2,7 @@
use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
use ide_db::SymbolKind;
+use syntax::AstNode;
use crate::{
context::{CompletionContext, PathCompletionCtx, PathKind},
@@ -117,7 +118,7 @@ fn render(
..ctx.completion_relevance()
});
if let Some(ref_match) = compute_ref_match(completion, &ty) {
- item.ref_match(ref_match);
+ item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
}
if let Some(import_to_add) = ctx.import_to_add {
diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs
index 6da7bb3193..ac2091eca9 100644
--- a/crates/ide-completion/src/render/macro_.rs
+++ b/crates/ide-completion/src/render/macro_.rs
@@ -5,24 +5,37 @@ use ide_db::SymbolKind;
use syntax::SmolStr;
use crate::{
- context::{PathCompletionCtx, PathKind},
+ context::{PathCompletionCtx, PathKind, PatternContext},
item::{Builder, CompletionItem},
render::RenderContext,
};
pub(crate) fn render_macro(
ctx: RenderContext<'_>,
- path_ctx: &PathCompletionCtx,
+ PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
+
+ name: hir::Name,
+ macro_: hir::Macro,
+) -> Builder {
+ let _p = profile::span("render_macro");
+ render(ctx, *kind == PathKind::Use, *has_macro_bang, *has_call_parens, name, macro_)
+}
+
+pub(crate) fn render_macro_pat(
+ ctx: RenderContext<'_>,
+ _pattern_ctx: &PatternContext,
name: hir::Name,
macro_: hir::Macro,
) -> Builder {
let _p = profile::span("render_macro");
- render(ctx, path_ctx, name, macro_)
+ render(ctx, false, false, false, name, macro_)
}
fn render(
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
- PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
+ is_use_path: bool,
+ has_macro_bang: bool,
+ has_call_parens: bool,
name: hir::Name,
macro_: hir::Macro,
) -> Builder {
@@ -39,7 +52,7 @@ fn render(
let is_fn_like = macro_.is_fn_like(completion.db);
let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
- let needs_bang = is_fn_like && *kind != PathKind::Use && !has_macro_bang;
+ let needs_bang = is_fn_like && !is_use_path && !has_macro_bang;
let mut item = CompletionItem::new(
SymbolKind::from(macro_.kind(completion.db)),
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index da9e5e2028..8953f1b2fd 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -399,6 +399,7 @@ fn foo() {
#[test]
fn completes_no_delims_if_existing() {
+ // FIXME: We should not complete functions here
check_empty(
r#"
struct Bar(u32);
@@ -409,7 +410,7 @@ fn foo() {
}
"#,
expect![[r#"
- fn foo() fn()
+ fn foo fn()
st Bar
bt u32
kw crate::
@@ -427,7 +428,7 @@ fn foo() {
}
"#,
expect![[r#"
- fn foo() fn()
+ fn foo fn()
st Foo
bt u32
kw crate::
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 3d702fe8dc..cdd152ccf5 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -224,6 +224,7 @@ fn completion_item(
max_relevance: u32,
item: CompletionItem,
) {
+ let insert_replace_support = config.insert_replace_support().then(|| tdpp.position);
let mut additional_text_edits = Vec::new();
// LSP does not allow arbitrary edits in completion, so we have to do a
@@ -233,7 +234,6 @@ fn completion_item(
let source_range = item.source_range();
for indel in item.text_edit().iter() {
if indel.delete.contains_range(source_range) {
- let insert_replace_support = config.insert_replace_support().then(|| tdpp.position);
text_edit = Some(if indel.delete == source_range {
self::completion_text_edit(line_index, insert_replace_support, indel.clone())
} else {
@@ -254,6 +254,14 @@ fn completion_item(
text_edit.unwrap()
};
+ let insert_text_format = item.is_snippet().then(|| lsp_types::InsertTextFormat::SNIPPET);
+ let tags = item.deprecated().then(|| vec![lsp_types::CompletionItemTag::DEPRECATED]);
+ let command = if item.trigger_call_info() && config.client_commands().trigger_parameter_hints {
+ Some(command::trigger_parameter_hints())
+ } else {
+ None
+ };
+
let mut lsp_item = lsp_types::CompletionItem {
label: item.label().to_string(),
detail: item.detail().map(|it| it.to_string()),
@@ -263,22 +271,14 @@ fn completion_item(
additional_text_edits: Some(additional_text_edits),
documentation: item.documentation().map(documentation),
deprecated: Some(item.deprecated()),
+ tags,
+ command,
+ insert_text_format,
..Default::default()
};
set_score(&mut lsp_item, max_relevance, item.relevance());
- if item.deprecated() {
- lsp_item.tags = Some(vec![lsp_types::CompletionItemTag::DEPRECATED])
- }
-
- if item.trigger_call_info() && config.client_commands().trigger_parameter_hints {
- lsp_item.command = Some(command::trigger_parameter_hints());
- }
-
- if item.is_snippet() {
- lsp_item.insert_text_format = Some(lsp_types::InsertTextFormat::SNIPPET);
- }
if config.completion().enable_imports_on_the_fly {
if let imports @ [_, ..] = item.imports_to_add() {
let imports: Vec<_> = imports
@@ -299,18 +299,17 @@ fn completion_item(
}
}
- if let Some((mutability, relevance)) = item.ref_match() {
+ if let Some((mutability, offset, relevance)) = item.ref_match() {
let mut lsp_item_with_ref = lsp_item.clone();
set_score(&mut lsp_item_with_ref, max_relevance, relevance);
lsp_item_with_ref.label =
format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
- if let Some(it) = &mut lsp_item_with_ref.text_edit {
- let new_text = match it {
- lsp_types::CompletionTextEdit::Edit(it) => &mut it.new_text,
- lsp_types::CompletionTextEdit::InsertAndReplace(it) => &mut it.new_text,
- };
- *new_text = format!("&{}{}", mutability.as_keyword_for_ref(), new_text);
- }
+ lsp_item_with_ref.additional_text_edits.get_or_insert_with(Default::default).push(
+ self::text_edit(
+ line_index,
+ Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())),
+ ),
+ );
acc.push(lsp_item_with_ref);
};