Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide_completion/src/render.rs')
| -rw-r--r-- | crates/ide_completion/src/render.rs | 143 |
1 files changed, 125 insertions, 18 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d6fa86b55d..13de818da1 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -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(…) [] |