mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 15:15:24 +00:00
Simplify completion render functionality
This commit is contained in:
parent
4fe5f03c7f
commit
02b401b130
14 changed files with 490 additions and 345 deletions
|
@ -3,13 +3,12 @@
|
|||
|
||||
pub(crate) mod macro_;
|
||||
pub(crate) mod function;
|
||||
pub(crate) mod enum_variant;
|
||||
pub(crate) mod const_;
|
||||
pub(crate) mod pattern;
|
||||
pub(crate) mod type_alias;
|
||||
pub(crate) mod struct_literal;
|
||||
pub(crate) mod variant;
|
||||
pub(crate) mod union_literal;
|
||||
pub(crate) mod literal;
|
||||
|
||||
use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
|
||||
use ide_db::{helpers::item_name, RootDatabase, SnippetCap, SymbolKind};
|
||||
|
@ -18,22 +17,30 @@ use syntax::{SmolStr, SyntaxKind, TextRange};
|
|||
use crate::{
|
||||
context::{PathCompletionCtx, PathKind},
|
||||
item::{CompletionRelevanceTypeMatch, ImportEdit},
|
||||
render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
|
||||
render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
|
||||
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
|
||||
};
|
||||
/// Interface for data and methods required for items rendering.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct RenderContext<'a> {
|
||||
completion: &'a CompletionContext<'a>,
|
||||
is_private_editable: bool,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
}
|
||||
|
||||
impl<'a> RenderContext<'a> {
|
||||
pub(crate) fn new(
|
||||
completion: &'a CompletionContext<'a>,
|
||||
is_private_editable: bool,
|
||||
) -> RenderContext<'a> {
|
||||
RenderContext { completion, is_private_editable }
|
||||
pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> {
|
||||
RenderContext { completion, is_private_editable: false, import_to_add: None }
|
||||
}
|
||||
|
||||
pub(crate) fn private_editable(mut self, private_editable: bool) -> Self {
|
||||
self.is_private_editable = private_editable;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn import_to_add(mut self, import_to_add: Option<ImportEdit>) -> Self {
|
||||
self.import_to_add = import_to_add;
|
||||
self
|
||||
}
|
||||
|
||||
fn snippet_cap(&self) -> Option<SnippetCap> {
|
||||
|
@ -139,6 +146,14 @@ pub(crate) fn render_resolution(
|
|||
render_resolution_(ctx, local_name, None, resolution)
|
||||
}
|
||||
|
||||
pub(crate) fn render_resolution_simple(
|
||||
ctx: RenderContext<'_>,
|
||||
local_name: hir::Name,
|
||||
resolution: ScopeDef,
|
||||
) -> CompletionItem {
|
||||
render_resolution_simple_(ctx, local_name, None, resolution)
|
||||
}
|
||||
|
||||
pub(crate) fn render_resolution_with_import(
|
||||
ctx: RenderContext<'_>,
|
||||
import_edit: ImportEdit,
|
||||
|
@ -163,24 +178,26 @@ fn render_resolution_(
|
|||
use hir::ModuleDef::*;
|
||||
|
||||
let db = ctx.db();
|
||||
|
||||
let ctx = ctx.import_to_add(import_to_add);
|
||||
let kind = match resolution {
|
||||
ScopeDef::ModuleDef(Function(func)) => {
|
||||
return render_fn(ctx, import_to_add, Some(local_name), func);
|
||||
return render_fn(ctx, Some(local_name), func);
|
||||
}
|
||||
ScopeDef::ModuleDef(Variant(var)) if ctx.completion.pattern_ctx.is_none() => {
|
||||
return render_variant(ctx, import_to_add, Some(local_name), var, None);
|
||||
}
|
||||
ScopeDef::ModuleDef(Macro(mac)) => {
|
||||
return render_macro(ctx, import_to_add, local_name, mac)
|
||||
if let Some(item) = render_variant_lit(ctx.clone(), Some(local_name.clone()), var, None)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
CompletionItemKind::SymbolKind(SymbolKind::Variant)
|
||||
}
|
||||
ScopeDef::ModuleDef(Macro(mac)) => return render_macro(ctx, local_name, mac),
|
||||
ScopeDef::Unknown => {
|
||||
let mut item = CompletionItem::new(
|
||||
CompletionItemKind::UnresolvedReference,
|
||||
ctx.source_range(),
|
||||
local_name.to_smol_str(),
|
||||
);
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
if let Some(import_to_add) = ctx.import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
return item.build();
|
||||
|
@ -253,7 +270,95 @@ fn render_resolution_(
|
|||
item.set_documentation(scope_def_docs(db, resolution))
|
||||
.set_deprecated(scope_def_is_deprecated(&ctx, resolution));
|
||||
|
||||
if let Some(import_to_add) = import_to_add {
|
||||
if let Some(import_to_add) = ctx.import_to_add {
|
||||
item.add_import(import_to_add);
|
||||
}
|
||||
item.build()
|
||||
}
|
||||
|
||||
fn render_resolution_simple_(
|
||||
ctx: RenderContext<'_>,
|
||||
local_name: hir::Name,
|
||||
import_to_add: Option<ImportEdit>,
|
||||
resolution: ScopeDef,
|
||||
) -> CompletionItem {
|
||||
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 {
|
||||
ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,
|
||||
ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),
|
||||
ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
|
||||
ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro),
|
||||
ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
|
||||
ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
|
||||
hir::Adt::Struct(_) => SymbolKind::Struct,
|
||||
hir::Adt::Union(_) => SymbolKind::Union,
|
||||
hir::Adt::Enum(_) => SymbolKind::Enum,
|
||||
}),
|
||||
ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
|
||||
ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
|
||||
ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
|
||||
ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),
|
||||
ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
|
||||
ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
|
||||
hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
|
||||
hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
|
||||
hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
|
||||
}),
|
||||
ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
|
||||
ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
|
||||
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());
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// Add `<>` for generic types
|
||||
let type_path_no_ty_args = matches!(
|
||||
ctx.completion.path_context,
|
||||
Some(PathCompletionCtx { kind: Some(PathKind::Type), has_type_args: false, .. })
|
||||
) && ctx.completion.config.add_call_parenthesis;
|
||||
if type_path_no_ty_args {
|
||||
if let Some(cap) = ctx.snippet_cap() {
|
||||
let has_non_default_type_params = match resolution {
|
||||
ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(db),
|
||||
ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(db),
|
||||
_ => false,
|
||||
};
|
||||
if has_non_default_type_params {
|
||||
cov_mark::hit!(inserts_angle_brackets_for_generics);
|
||||
item.lookup_by(local_name.clone())
|
||||
.label(SmolStr::from_iter([&local_name, "<…>"]))
|
||||
.insert_snippet(cap, format!("{}<$0>", local_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
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.build()
|
||||
|
@ -577,7 +682,7 @@ fn main() { let _: m::Spam = S$0 }
|
|||
kind: SymbolKind(
|
||||
Variant,
|
||||
),
|
||||
lookup: "Spam::Bar",
|
||||
lookup: "Spam::Bar(…)",
|
||||
detail: "m::Spam::Bar(i32)",
|
||||
relevance: CompletionRelevance {
|
||||
exact_name_match: false,
|
||||
|
@ -1156,6 +1261,7 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
lc s [type+name+local]
|
||||
st S [type]
|
||||
st S []
|
||||
fn main() []
|
||||
fn foo(…) []
|
||||
|
@ -1172,6 +1278,7 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
lc ssss [type+local]
|
||||
st S [type]
|
||||
st S []
|
||||
fn main() []
|
||||
fn foo(…) []
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue