cov_mark::hit!(qualified_path_doc_hidden);
return;
}
- self.add(render_resolution(RenderContext::new(ctx), local_name, resolution));
+ self.add(render_resolution(RenderContext::new(ctx), local_name, resolution).build());
}
pub(crate) fn add_resolution_simple(
if ctx.is_scope_def_hidden(resolution) {
return;
}
- self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution));
+ self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution).build());
}
pub(crate) fn add_macro(
Visible::Editable => true,
Visible::No => return,
};
- self.add(render_macro(
- RenderContext::new(ctx).private_editable(is_private_editable),
- local_name,
- mac,
- ));
+ self.add(
+ render_macro(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ local_name,
+ mac,
+ )
+ .build(),
+ );
}
pub(crate) fn add_function(
Visible::Editable => true,
Visible::No => return,
};
- self.add(render_fn(
- RenderContext::new(ctx).private_editable(is_private_editable),
- local_name,
- func,
- ));
+ self.add(
+ render_fn(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ local_name,
+ func,
+ )
+ .build(),
+ );
}
pub(crate) fn add_method(
Visible::Editable => true,
Visible::No => return,
};
- self.add(render_method(
- RenderContext::new(ctx).private_editable(is_private_editable),
- receiver,
- local_name,
- func,
- ));
+ self.add(
+ render_method(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ receiver,
+ local_name,
+ func,
+ )
+ .build(),
+ );
}
pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) {
variant: hir::Variant,
path: hir::ModPath,
) {
- self.add_opt(render_variant_lit(RenderContext::new(ctx), None, variant, Some(path)));
+ if let Some(builder) =
+ render_variant_lit(RenderContext::new(ctx), None, variant, Some(path))
+ {
+ self.add(builder.build());
+ }
}
pub(crate) fn add_enum_variant(
variant: hir::Variant,
local_name: Option<hir::Name>,
) {
- self.add_opt(render_variant_lit(RenderContext::new(ctx), local_name, variant, None));
+ if let Some(builder) =
+ render_variant_lit(RenderContext::new(ctx), local_name, variant, None)
+ {
+ self.add(builder.build());
+ }
}
pub(crate) fn add_field(
path: Option<hir::ModPath>,
local_name: Option<hir::Name>,
) {
- let item = render_struct_literal(RenderContext::new(ctx), strukt, path, local_name);
- self.add_opt(item);
+ if let Some(builder) =
+ render_struct_literal(RenderContext::new(ctx), strukt, path, local_name)
+ {
+ self.add(builder.build());
+ }
}
pub(crate) fn add_union_literal(
&user_input_lowercased,
)
})
- .filter_map(|import| render_resolution_with_import(RenderContext::new(ctx), import)),
+ .filter_map(|import| render_resolution_with_import(RenderContext::new(ctx), import))
+ .map(|builder| builder.build()),
);
Some(())
}
//! Completion for use trees
use hir::ScopeDef;
+use rustc_hash::FxHashSet;
use syntax::{ast, AstNode};
use crate::{
context::{CompletionContext, PathCompletionCtx, PathKind, PathQualifierCtx},
- Completions,
+ item::Builder,
+ CompletionRelevance, Completions,
};
pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext) {
None => return,
};
+ let mut already_imported_names = FxHashSet::default();
+ if let Some(list) = ctx.token.ancestors().find_map(ast::UseTreeList::cast) {
+ let use_tree = list.parent_use_tree();
+ if use_tree.path().as_ref() == Some(path) {
+ for tree in list.use_trees() {
+ if tree.is_simple_path() {
+ if let Some(name) =
+ tree.path().and_then(|path| path.as_single_name_ref())
+ {
+ already_imported_names.insert(name.to_string());
+ }
+ }
+ }
+ }
+ }
+
match resolution {
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
let module_scope = module.scope(ctx.db, Some(ctx.module));
)
};
for (name, def) in module_scope {
+ let is_name_already_imported =
+ already_imported_names.contains(name.as_text().unwrap().as_str());
+
let add_resolution = match def {
ScopeDef::Unknown if unknown_is_current(&name) => {
// for `use self::foo$0`, don't suggest `foo` as a completion
};
if add_resolution {
- acc.add_resolution(ctx, name, def);
+ let mut builder = Builder::from_resolution(ctx, name, def);
+ builder.set_relevance(CompletionRelevance {
+ is_name_already_imported,
+ ..Default::default()
+ });
+ acc.add(builder.build());
}
}
}
use syntax::{SmolStr, TextRange};
use text_edit::TextEdit;
+use crate::{
+ context::CompletionContext,
+ render::{render_resolution, RenderContext},
+};
+
/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
pub is_local: bool,
/// This is set when trait items are completed in an impl of that trait.
pub is_item_from_trait: bool,
+ /// This is set when an import is suggested whose name is already imported.
+ pub is_name_already_imported: bool,
/// Set for method completions of the `core::ops` and `core::cmp` family.
pub is_op_method: bool,
/// Set for item completions that are private but in the workspace.
type_match,
is_local,
is_item_from_trait,
+ is_name_already_imported,
is_op_method,
is_private_editable,
postfix_match,
if !is_op_method {
score += 10;
}
+ // lower rank for conflicting import names
+ if !is_name_already_imported {
+ score += 1;
+ }
if exact_name_match {
score += 10;
}
}
impl Builder {
+ pub(crate) fn from_resolution(
+ ctx: &CompletionContext,
+ local_name: hir::Name,
+ resolution: hir::ScopeDef,
+ ) -> Self {
+ render_resolution(RenderContext::new(ctx), local_name, resolution)
+ }
+
pub(crate) fn build(self) -> CompletionItem {
let _p = profile::span("item::Builder::build");
use crate::{
context::{PathCompletionCtx, PathKind},
- item::CompletionRelevanceTypeMatch,
+ item::{Builder, CompletionRelevanceTypeMatch},
render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
};
ctx: RenderContext<'_>,
local_name: hir::Name,
resolution: ScopeDef,
-) -> CompletionItem {
+) -> Builder {
render_resolution_(ctx, local_name, None, resolution)
}
ctx: RenderContext<'_>,
local_name: hir::Name,
resolution: ScopeDef,
-) -> CompletionItem {
+) -> Builder {
render_resolution_simple_(ctx, local_name, None, resolution)
}
pub(crate) fn render_resolution_with_import(
ctx: RenderContext<'_>,
import_edit: LocatedImport,
-) -> Option<CompletionItem> {
+) -> Option<Builder> {
let resolution = ScopeDef::from(import_edit.original_item);
let local_name = match resolution {
ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
local_name: hir::Name,
import_to_add: Option<LocatedImport>,
resolution: ScopeDef,
-) -> CompletionItem {
+) -> Builder {
let _p = profile::span("render_resolution");
use hir::ModuleDef::*;
local_name: hir::Name,
import_to_add: Option<LocatedImport>,
resolution: ScopeDef,
-) -> CompletionItem {
+) -> Builder {
let _p = profile::span("render_resolution");
use hir::ModuleDef::*;
if let Some(import_to_add) = ctx.import_to_add {
item.add_import(import_to_add);
}
- item.build()
+ item
}
fn scope_def_docs(db: &RootDatabase, resolution: ScopeDef) -> Option<hir::Documentation> {
),
is_local: false,
is_item_from_trait: false,
+ is_name_already_imported: false,
is_op_method: false,
is_private_editable: false,
postfix_match: None,
),
is_local: false,
is_item_from_trait: false,
+ is_name_already_imported: false,
is_op_method: false,
is_private_editable: false,
postfix_match: None,
),
is_local: false,
is_item_from_trait: false,
+ is_name_already_imported: false,
is_op_method: false,
is_private_editable: false,
postfix_match: None,
ctx: RenderContext<'_>,
local_name: Option<hir::Name>,
func: hir::Function,
-) -> CompletionItem {
+) -> Builder {
let _p = profile::span("render_fn");
render(ctx, local_name, func, FuncKind::Function)
}
receiver: Option<hir::Name>,
local_name: Option<hir::Name>,
func: hir::Function,
-) -> CompletionItem {
+) -> Builder {
let _p = profile::span("render_method");
render(ctx, local_name, func, FuncKind::Method(receiver))
}
local_name: Option<hir::Name>,
func: hir::Function,
func_kind: FuncKind,
-) -> CompletionItem {
+) -> Builder {
let db = completion.db;
let name = local_name.unwrap_or_else(|| func.name(db));
}
}
}
- item.build()
+ item
}
pub(super) fn add_call_parens<'b>(
use crate::{
context::{CompletionContext, PathCompletionCtx},
- item::CompletionItem,
+ item::{Builder, CompletionItem},
render::{
compute_ref_match, compute_type_match,
variant::{
local_name: Option<hir::Name>,
variant: hir::Variant,
path: Option<hir::ModPath>,
-) -> Option<CompletionItem> {
+) -> Option<Builder> {
let _p = profile::span("render_enum_variant");
let db = ctx.db();
strukt: hir::Struct,
path: Option<hir::ModPath>,
local_name: Option<hir::Name>,
-) -> Option<CompletionItem> {
+) -> Option<Builder> {
let _p = profile::span("render_struct_literal");
let db = ctx.db();
thing: Variant,
name: hir::Name,
path: Option<hir::ModPath>,
-) -> Option<CompletionItem> {
+) -> Option<Builder> {
let db = completion.db;
let kind = thing.kind(db);
let has_call_parens =
if let Some(import_to_add) = ctx.import_to_add {
item.add_import(import_to_add);
}
- Some(item.build())
+ Some(item)
}
#[derive(Clone, Copy)]
use ide_db::SymbolKind;
use syntax::SmolStr;
-use crate::{context::PathKind, item::CompletionItem, render::RenderContext};
+use crate::{
+ context::PathKind,
+ item::{Builder, CompletionItem},
+ render::RenderContext,
+};
-pub(crate) fn render_macro(
- ctx: RenderContext<'_>,
- name: hir::Name,
- macro_: hir::Macro,
-) -> CompletionItem {
+pub(crate) fn render_macro(ctx: RenderContext<'_>, name: hir::Name, macro_: hir::Macro) -> Builder {
let _p = profile::span("render_macro");
render(ctx, name, macro_)
}
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
name: hir::Name,
macro_: hir::Macro,
-) -> CompletionItem {
+) -> Builder {
let source_range = if completion.is_immediately_after_macro_bang() {
cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
completion.token.parent().map_or_else(|| ctx.source_range(), |it| it.text_range())
item.add_import(import_to_add);
}
- item.build()
+ item
}
fn label(