From 3db64a400c78bbd2708e67ddc07df1001fff3f29 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 17 Feb 2021 17:53:31 +0300 Subject: rename completion -> ide_completion We don't have completion-related PRs in flight, so lets do it --- crates/completion/src/render/builder_ext.rs | 94 -------- crates/completion/src/render/const_.rs | 59 ----- crates/completion/src/render/enum_variant.rs | 131 ---------- crates/completion/src/render/function.rs | 345 --------------------------- crates/completion/src/render/macro_.rs | 214 ----------------- crates/completion/src/render/pattern.rs | 150 ------------ crates/completion/src/render/type_alias.rs | 59 ----- 7 files changed, 1052 deletions(-) delete mode 100644 crates/completion/src/render/builder_ext.rs delete mode 100644 crates/completion/src/render/const_.rs delete mode 100644 crates/completion/src/render/enum_variant.rs delete mode 100644 crates/completion/src/render/function.rs delete mode 100644 crates/completion/src/render/macro_.rs delete mode 100644 crates/completion/src/render/pattern.rs delete mode 100644 crates/completion/src/render/type_alias.rs (limited to 'crates/completion/src/render') diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs deleted file mode 100644 index d053a988b..000000000 --- a/crates/completion/src/render/builder_ext.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! Extensions for `Builder` structure required for item rendering. - -use itertools::Itertools; -use test_utils::mark; - -use crate::{item::Builder, CompletionContext}; - -#[derive(Debug)] -pub(super) enum Params { - Named(Vec), - Anonymous(usize), -} - -impl Params { - pub(super) fn len(&self) -> usize { - match self { - Params::Named(xs) => xs.len(), - Params::Anonymous(len) => *len, - } - } - - pub(super) fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -impl Builder { - fn should_add_parens(&self, ctx: &CompletionContext) -> bool { - if !ctx.config.add_call_parenthesis { - return false; - } - if ctx.use_item_syntax.is_some() { - mark::hit!(no_parens_in_use_item); - return false; - } - if ctx.is_pattern_call { - return false; - } - if ctx.is_call { - return false; - } - - // Don't add parentheses if the expected type is some function reference. - if let Some(ty) = &ctx.expected_type { - if ty.is_fn() { - mark::hit!(no_call_parens_if_fn_ptr_needed); - return false; - } - } - - // Nothing prevents us from adding parentheses - true - } - - pub(super) fn add_call_parens( - mut self, - ctx: &CompletionContext, - name: String, - params: Params, - ) -> Builder { - if !self.should_add_parens(ctx) { - return self; - } - - let cap = match ctx.config.snippet_cap { - Some(it) => it, - None => return self, - }; - // If not an import, add parenthesis automatically. - mark::hit!(inserts_parens_for_function_calls); - - let (snippet, label) = if params.is_empty() { - (format!("{}()$0", name), format!("{}()", name)) - } else { - self = self.trigger_call_info(); - let snippet = match (ctx.config.add_call_argument_snippets, params) { - (true, Params::Named(params)) => { - let function_params_snippet = - params.iter().enumerate().format_with(", ", |(index, param_name), f| { - f(&format_args!("${{{}:{}}}", index + 1, param_name)) - }); - format!("{}({})$0", name, function_params_snippet) - } - _ => { - mark::hit!(suppress_arg_snippets); - format!("{}($0)", name) - } - }; - - (snippet, format!("{}(…)", name)) - }; - self.lookup_by(name).label(label).insert_snippet(cap, snippet) - } -} diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs deleted file mode 100644 index 5010b642a..000000000 --- a/crates/completion/src/render/const_.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Renderer for `const` fields. - -use hir::HasSource; -use ide_db::SymbolKind; -use syntax::{ - ast::{Const, NameOwner}, - display::const_label, -}; - -use crate::{ - item::{CompletionItem, CompletionKind}, - render::RenderContext, -}; - -pub(crate) fn render_const<'a>( - ctx: RenderContext<'a>, - const_: hir::Const, -) -> Option { - ConstRender::new(ctx, const_)?.render() -} - -#[derive(Debug)] -struct ConstRender<'a> { - ctx: RenderContext<'a>, - const_: hir::Const, - ast_node: Const, -} - -impl<'a> ConstRender<'a> { - fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option> { - let ast_node = const_.source(ctx.db())?.value; - Some(ConstRender { ctx, const_, ast_node }) - } - - fn render(self) -> Option { - let name = self.name()?; - let detail = self.detail(); - - let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) - .kind(SymbolKind::Const) - .set_documentation(self.ctx.docs(self.const_)) - .set_deprecated( - self.ctx.is_deprecated(self.const_) - || self.ctx.is_deprecated_assoc_item(self.const_), - ) - .detail(detail) - .build(); - - Some(item) - } - - fn name(&self) -> Option { - self.ast_node.name().map(|name| name.text().to_string()) - } - - fn detail(&self) -> String { - const_label(&self.ast_node) - } -} diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs deleted file mode 100644 index 9214193b4..000000000 --- a/crates/completion/src/render/enum_variant.rs +++ /dev/null @@ -1,131 +0,0 @@ -//! Renderer for `enum` variants. - -use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; -use ide_db::SymbolKind; -use itertools::Itertools; -use test_utils::mark; - -use crate::{ - item::{CompletionItem, CompletionKind, ImportEdit}, - render::{builder_ext::Params, RenderContext}, -}; - -pub(crate) fn render_variant<'a>( - ctx: RenderContext<'a>, - import_to_add: Option, - local_name: Option, - variant: hir::Variant, - path: Option, -) -> CompletionItem { - let _p = profile::span("render_enum_variant"); - EnumRender::new(ctx, local_name, variant, path).render(import_to_add) -} - -#[derive(Debug)] -struct EnumRender<'a> { - ctx: RenderContext<'a>, - name: String, - variant: hir::Variant, - path: Option, - qualified_name: String, - short_qualified_name: String, - variant_kind: StructKind, -} - -impl<'a> EnumRender<'a> { - fn new( - ctx: RenderContext<'a>, - local_name: Option, - variant: hir::Variant, - path: Option, - ) -> EnumRender<'a> { - let name = local_name.unwrap_or_else(|| variant.name(ctx.db()).to_string()); - let variant_kind = variant.kind(ctx.db()); - - let (qualified_name, short_qualified_name) = match &path { - Some(path) => { - let full = path.to_string(); - let segments = path.segments(); - let short = segments[segments.len().saturating_sub(2)..].iter().join("::"); - (full, short) - } - None => (name.to_string(), name.to_string()), - }; - - EnumRender { ctx, name, variant, path, qualified_name, short_qualified_name, variant_kind } - } - - fn render(self, import_to_add: Option) -> CompletionItem { - let mut builder = CompletionItem::new( - CompletionKind::Reference, - self.ctx.source_range(), - self.qualified_name.clone(), - ) - .kind(SymbolKind::Variant) - .set_documentation(self.variant.docs(self.ctx.db())) - .set_deprecated(self.ctx.is_deprecated(self.variant)) - .add_import(import_to_add) - .detail(self.detail()); - - if self.variant_kind == StructKind::Tuple { - mark::hit!(inserts_parens_for_tuple_enums); - let params = Params::Anonymous(self.variant.fields(self.ctx.db()).len()); - builder = - builder.add_call_parens(self.ctx.completion, self.short_qualified_name, params); - } else if self.path.is_some() { - builder = builder.lookup_by(self.short_qualified_name); - } - - builder.build() - } - - fn detail(&self) -> String { - let detail_types = self - .variant - .fields(self.ctx.db()) - .into_iter() - .map(|field| (field.name(self.ctx.db()), field.signature_ty(self.ctx.db()))); - - match self.variant_kind { - StructKind::Tuple | StructKind::Unit => format!( - "({})", - detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ") - ), - StructKind::Record => format!( - "{{ {} }}", - detail_types - .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string())) - .format(", ") - ), - } - } -} - -#[cfg(test)] -mod tests { - use test_utils::mark; - - use crate::test_utils::check_edit; - - #[test] - fn inserts_parens_for_tuple_enums() { - mark::check!(inserts_parens_for_tuple_enums); - check_edit( - "Some", - r#" -enum Option { Some(T), None } -use Option::*; -fn main() -> Option { - Som$0 -} -"#, - r#" -enum Option { Some(T), None } -use Option::*; -fn main() -> Option { - Some($0) -} -"#, - ); - } -} diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs deleted file mode 100644 index e46e21d24..000000000 --- a/crates/completion/src/render/function.rs +++ /dev/null @@ -1,345 +0,0 @@ -//! Renderer for function calls. - -use hir::{HasSource, HirDisplay, Type}; -use ide_db::SymbolKind; -use syntax::ast::Fn; -use test_utils::mark; - -use crate::{ - item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, - render::{builder_ext::Params, RenderContext}, -}; - -pub(crate) fn render_fn<'a>( - ctx: RenderContext<'a>, - import_to_add: Option, - local_name: Option, - fn_: hir::Function, -) -> Option { - let _p = profile::span("render_fn"); - Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add)) -} - -#[derive(Debug)] -struct FunctionRender<'a> { - ctx: RenderContext<'a>, - name: String, - func: hir::Function, - ast_node: Fn, -} - -impl<'a> FunctionRender<'a> { - fn new( - ctx: RenderContext<'a>, - local_name: Option, - fn_: hir::Function, - ) -> Option> { - let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); - let ast_node = fn_.source(ctx.db())?.value; - - Some(FunctionRender { ctx, name, func: fn_, ast_node }) - } - - fn render(self, import_to_add: Option) -> CompletionItem { - let params = self.params(); - CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) - .kind(self.kind()) - .set_documentation(self.ctx.docs(self.func)) - .set_deprecated( - self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), - ) - .detail(self.detail()) - .add_call_parens(self.ctx.completion, self.name, params) - .add_import(import_to_add) - .build() - } - - fn detail(&self) -> String { - let ty = self.func.ret_type(self.ctx.db()); - format!("-> {}", ty.display(self.ctx.db())) - } - - fn add_arg(&self, arg: &str, ty: &Type) -> String { - if let Some(derefed_ty) = ty.remove_ref() { - for (name, local) in self.ctx.completion.locals.iter() { - if name == arg && local.ty(self.ctx.db()) == derefed_ty { - let mutability = if ty.is_mutable_reference() { "&mut " } else { "&" }; - return format!("{}{}", mutability, arg); - } - } - } - arg.to_string() - } - - fn params(&self) -> Params { - let ast_params = match self.ast_node.param_list() { - Some(it) => it, - None => return Params::Named(Vec::new()), - }; - - let mut params_pats = Vec::new(); - let params_ty = if self.ctx.completion.dot_receiver.is_some() { - self.func.method_params(self.ctx.db()).unwrap_or_default() - } else { - if let Some(s) = ast_params.self_param() { - mark::hit!(parens_for_method_call_as_assoc_fn); - params_pats.push(Some(s.to_string())); - } - self.func.assoc_fn_params(self.ctx.db()) - }; - params_pats - .extend(ast_params.params().into_iter().map(|it| it.pat().map(|it| it.to_string()))); - - let params = params_pats - .into_iter() - .zip(params_ty) - .flat_map(|(pat, param_ty)| { - let pat = pat?; - let name = pat; - let arg = name.trim_start_matches("mut ").trim_start_matches('_'); - Some(self.add_arg(arg, param_ty.ty())) - }) - .collect(); - Params::Named(params) - } - - fn kind(&self) -> CompletionItemKind { - if self.func.self_param(self.ctx.db()).is_some() { - CompletionItemKind::Method - } else { - SymbolKind::Function.into() - } - } -} - -#[cfg(test)] -mod tests { - use test_utils::mark; - - use crate::{ - test_utils::{check_edit, check_edit_with_config, TEST_CONFIG}, - CompletionConfig, - }; - - #[test] - fn inserts_parens_for_function_calls() { - mark::check!(inserts_parens_for_function_calls); - check_edit( - "no_args", - r#" -fn no_args() {} -fn main() { no_$0 } -"#, - r#" -fn no_args() {} -fn main() { no_args()$0 } -"#, - ); - - check_edit( - "with_args", - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_$0 } -"#, - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_args(${1:x}, ${2:y})$0 } -"#, - ); - - check_edit( - "foo", - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn bar(s: &S) { s.f$0 } -"#, - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn bar(s: &S) { s.foo()$0 } -"#, - ); - - check_edit( - "foo", - r#" -struct S {} -impl S { - fn foo(&self, x: i32) {} -} -fn bar(s: &S) { - s.f$0 -} -"#, - r#" -struct S {} -impl S { - fn foo(&self, x: i32) {} -} -fn bar(s: &S) { - s.foo(${1:x})$0 -} -"#, - ); - } - - #[test] - fn parens_for_method_call_as_assoc_fn() { - mark::check!(parens_for_method_call_as_assoc_fn); - check_edit( - "foo", - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn main() { S::f$0 } -"#, - r#" -struct S; -impl S { - fn foo(&self) {} -} -fn main() { S::foo(${1:&self})$0 } -"#, - ); - } - - #[test] - fn suppress_arg_snippets() { - mark::check!(suppress_arg_snippets); - check_edit_with_config( - CompletionConfig { add_call_argument_snippets: false, ..TEST_CONFIG }, - "with_args", - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_$0 } -"#, - r#" -fn with_args(x: i32, y: String) {} -fn main() { with_args($0) } -"#, - ); - } - - #[test] - fn strips_underscores_from_args() { - check_edit( - "foo", - r#" -fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { f$0 } -"#, - r#" -fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {} -fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 } -"#, - ); - } - - #[test] - fn insert_ref_when_matching_local_in_scope() { - check_edit( - "ref_arg", - r#" -struct Foo {} -fn ref_arg(x: &Foo) {} -fn main() { - let x = Foo {}; - ref_ar$0 -} -"#, - r#" -struct Foo {} -fn ref_arg(x: &Foo) {} -fn main() { - let x = Foo {}; - ref_arg(${1:&x})$0 -} -"#, - ); - } - - #[test] - fn insert_mut_ref_when_matching_local_in_scope() { - check_edit( - "ref_arg", - r#" -struct Foo {} -fn ref_arg(x: &mut Foo) {} -fn main() { - let x = Foo {}; - ref_ar$0 -} -"#, - r#" -struct Foo {} -fn ref_arg(x: &mut Foo) {} -fn main() { - let x = Foo {}; - ref_arg(${1:&mut x})$0 -} -"#, - ); - } - - #[test] - fn insert_ref_when_matching_local_in_scope_for_method() { - check_edit( - "apply_foo", - r#" -struct Foo {} -struct Bar {} -impl Bar { - fn apply_foo(&self, x: &Foo) {} -} - -fn main() { - let x = Foo {}; - let y = Bar {}; - y.$0 -} -"#, - r#" -struct Foo {} -struct Bar {} -impl Bar { - fn apply_foo(&self, x: &Foo) {} -} - -fn main() { - let x = Foo {}; - let y = Bar {}; - y.apply_foo(${1:&x})$0 -} -"#, - ); - } - - #[test] - fn trim_mut_keyword_in_func_completion() { - check_edit( - "take_mutably", - r#" -fn take_mutably(mut x: &i32) {} - -fn main() { - take_m$0 -} -"#, - r#" -fn take_mutably(mut x: &i32) {} - -fn main() { - take_mutably(${1:x})$0 -} -"#, - ); - } -} diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs deleted file mode 100644 index a4535786f..000000000 --- a/crates/completion/src/render/macro_.rs +++ /dev/null @@ -1,214 +0,0 @@ -//! Renderer for macro invocations. - -use hir::{Documentation, HasSource}; -use ide_db::SymbolKind; -use syntax::display::macro_label; -use test_utils::mark; - -use crate::{ - item::{CompletionItem, CompletionKind, ImportEdit}, - render::RenderContext, -}; - -pub(crate) fn render_macro<'a>( - ctx: RenderContext<'a>, - import_to_add: Option, - name: String, - macro_: hir::MacroDef, -) -> Option { - let _p = profile::span("render_macro"); - MacroRender::new(ctx, name, macro_).render(import_to_add) -} - -#[derive(Debug)] -struct MacroRender<'a> { - ctx: RenderContext<'a>, - name: String, - macro_: hir::MacroDef, - docs: Option, - bra: &'static str, - ket: &'static str, -} - -impl<'a> MacroRender<'a> { - fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> { - let docs = ctx.docs(macro_); - let docs_str = docs.as_ref().map_or("", |s| s.as_str()); - let (bra, ket) = guess_macro_braces(&name, docs_str); - - MacroRender { ctx, name, macro_, docs, bra, ket } - } - - fn render(&self, import_to_add: Option) -> Option { - let mut builder = - CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) - .kind(SymbolKind::Macro) - .set_documentation(self.docs.clone()) - .set_deprecated(self.ctx.is_deprecated(self.macro_)) - .add_import(import_to_add) - .set_detail(self.detail()); - - let needs_bang = self.needs_bang(); - builder = match self.ctx.snippet_cap() { - Some(cap) if needs_bang => { - let snippet = self.snippet(); - let lookup = self.lookup(); - builder.insert_snippet(cap, snippet).lookup_by(lookup) - } - None if needs_bang => builder.insert_text(self.banged_name()), - _ => { - mark::hit!(dont_insert_macro_call_parens_unncessary); - builder.insert_text(&self.name) - } - }; - - Some(builder.build()) - } - - fn needs_bang(&self) -> bool { - self.ctx.completion.use_item_syntax.is_none() && !self.ctx.completion.is_macro_call - } - - fn label(&self) -> String { - if self.needs_bang() && self.ctx.snippet_cap().is_some() { - format!("{}!{}…{}", self.name, self.bra, self.ket) - } else { - self.banged_name() - } - } - - fn snippet(&self) -> String { - format!("{}!{}$0{}", self.name, self.bra, self.ket) - } - - fn lookup(&self) -> String { - self.banged_name() - } - - fn banged_name(&self) -> String { - format!("{}!", self.name) - } - - fn detail(&self) -> Option { - let ast_node = self.macro_.source(self.ctx.db())?.value; - Some(macro_label(&ast_node)) - } -} - -fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) { - let mut votes = [0, 0, 0]; - for (idx, s) in docs.match_indices(¯o_name) { - let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); - // Ensure to match the full word - if after.starts_with('!') - && !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric()) - { - // It may have spaces before the braces like `foo! {}` - match after[1..].chars().find(|&c| !c.is_whitespace()) { - Some('{') => votes[0] += 1, - Some('[') => votes[1] += 1, - Some('(') => votes[2] += 1, - _ => {} - } - } - } - - // Insert a space before `{}`. - // We prefer the last one when some votes equal. - let (_vote, (bra, ket)) = votes - .iter() - .zip(&[(" {", "}"), ("[", "]"), ("(", ")")]) - .max_by_key(|&(&vote, _)| vote) - .unwrap(); - (*bra, *ket) -} - -#[cfg(test)] -mod tests { - use test_utils::mark; - - use crate::test_utils::check_edit; - - #[test] - fn dont_insert_macro_call_parens_unncessary() { - mark::check!(dont_insert_macro_call_parens_unncessary); - check_edit( - "frobnicate!", - r#" -//- /main.rs crate:main deps:foo -use foo::$0; -//- /foo/lib.rs crate:foo -#[macro_export] -macro_rules! frobnicate { () => () } -"#, - r#" -use foo::frobnicate; -"#, - ); - - check_edit( - "frobnicate!", - r#" -macro_rules! frobnicate { () => () } -fn main() { frob$0!(); } -"#, - r#" -macro_rules! frobnicate { () => () } -fn main() { frobnicate!(); } -"#, - ); - } - - #[test] - fn guesses_macro_braces() { - check_edit( - "vec!", - r#" -/// Creates a [`Vec`] containing the arguments. -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -macro_rules! vec { () => {} } - -fn fn main() { v$0 } -"#, - r#" -/// Creates a [`Vec`] containing the arguments. -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -macro_rules! vec { () => {} } - -fn fn main() { vec![$0] } -"#, - ); - - check_edit( - "foo!", - r#" -/// Foo -/// -/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, -/// call as `let _=foo! { hello world };` -macro_rules! foo { () => {} } -fn main() { $0 } -"#, - r#" -/// Foo -/// -/// Don't call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`, -/// call as `let _=foo! { hello world };` -macro_rules! foo { () => {} } -fn main() { foo! {$0} } -"#, - ) - } -} diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs deleted file mode 100644 index 465dfe00c..000000000 --- a/crates/completion/src/render/pattern.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! Renderer for patterns. - -use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; -use ide_db::helpers::SnippetCap; -use itertools::Itertools; - -use crate::{item::CompletionKind, render::RenderContext, CompletionItem, CompletionItemKind}; - -fn visible_fields( - ctx: &RenderContext<'_>, - fields: &[hir::Field], - item: impl HasAttrs, -) -> Option<(Vec, bool)> { - let module = ctx.completion.scope.module()?; - let n_fields = fields.len(); - let fields = fields - .into_iter() - .filter(|field| field.is_visible_from(ctx.db(), module)) - .copied() - .collect::>(); - - let fields_omitted = - n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); - Some((fields, fields_omitted)) -} - -pub(crate) fn render_struct_pat( - ctx: RenderContext<'_>, - strukt: hir::Struct, - local_name: Option, -) -> Option { - let _p = profile::span("render_struct_pat"); - - let fields = strukt.fields(ctx.db()); - let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?; - - if visible_fields.is_empty() { - // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields - return None; - } - - let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); - let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?; - - Some(build_completion(ctx, name, pat, strukt)) -} - -pub(crate) fn render_variant_pat( - ctx: RenderContext<'_>, - variant: hir::Variant, - local_name: Option, - path: Option, -) -> Option { - let _p = profile::span("render_variant_pat"); - - let fields = variant.fields(ctx.db()); - let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?; - - let name = match &path { - Some(path) => path.to_string(), - None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(), - }; - let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?; - - Some(build_completion(ctx, name, pat, variant)) -} - -fn build_completion( - ctx: RenderContext<'_>, - name: String, - pat: String, - item: impl HasAttrs + Copy, -) -> CompletionItem { - let completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) - .kind(CompletionItemKind::Binding) - .set_documentation(ctx.docs(item)) - .set_deprecated(ctx.is_deprecated(item)) - .detail(&pat); - let completion = if let Some(snippet_cap) = ctx.snippet_cap() { - completion.insert_snippet(snippet_cap, pat) - } else { - completion.insert_text(pat) - }; - completion.build() -} - -fn render_pat( - ctx: &RenderContext<'_>, - name: &str, - kind: StructKind, - fields: &[hir::Field], - fields_omitted: bool, -) -> Option { - let mut pat = match kind { - StructKind::Tuple if ctx.snippet_cap().is_some() => { - render_tuple_as_pat(&fields, &name, fields_omitted) - } - StructKind::Record => { - render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted) - } - _ => return None, - }; - - if ctx.completion.is_param { - pat.push(':'); - pat.push(' '); - pat.push_str(&name); - } - if ctx.snippet_cap().is_some() { - pat.push_str("$0"); - } - Some(pat) -} - -fn render_record_as_pat( - db: &dyn HirDatabase, - snippet_cap: Option, - fields: &[hir::Field], - name: &str, - fields_omitted: bool, -) -> String { - let fields = fields.iter(); - if snippet_cap.is_some() { - format!( - "{name} {{ {}{} }}", - fields - .enumerate() - .map(|(idx, field)| format!("{}${}", field.name(db), idx + 1)) - .format(", "), - if fields_omitted { ", .." } else { "" }, - name = name - ) - } else { - format!( - "{name} {{ {}{} }}", - fields.map(|field| field.name(db)).format(", "), - if fields_omitted { ", .." } else { "" }, - name = name - ) - } -} - -fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String { - format!( - "{name}({}{})", - fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "), - if fields_omitted { ", .." } else { "" }, - name = name - ) -} diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs deleted file mode 100644 index bd97c3692..000000000 --- a/crates/completion/src/render/type_alias.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Renderer for type aliases. - -use hir::HasSource; -use ide_db::SymbolKind; -use syntax::{ - ast::{NameOwner, TypeAlias}, - display::type_label, -}; - -use crate::{ - item::{CompletionItem, CompletionKind}, - render::RenderContext, -}; - -pub(crate) fn render_type_alias<'a>( - ctx: RenderContext<'a>, - type_alias: hir::TypeAlias, -) -> Option { - TypeAliasRender::new(ctx, type_alias)?.render() -} - -#[derive(Debug)] -struct TypeAliasRender<'a> { - ctx: RenderContext<'a>, - type_alias: hir::TypeAlias, - ast_node: TypeAlias, -} - -impl<'a> TypeAliasRender<'a> { - fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option> { - let ast_node = type_alias.source(ctx.db())?.value; - Some(TypeAliasRender { ctx, type_alias, ast_node }) - } - - fn render(self) -> Option { - let name = self.name()?; - let detail = self.detail(); - - let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) - .kind(SymbolKind::TypeAlias) - .set_documentation(self.ctx.docs(self.type_alias)) - .set_deprecated( - self.ctx.is_deprecated(self.type_alias) - || self.ctx.is_deprecated_assoc_item(self.type_alias), - ) - .detail(detail) - .build(); - - Some(item) - } - - fn name(&self) -> Option { - self.ast_node.name().map(|name| name.text().to_string()) - } - - fn detail(&self) -> String { - type_label(&self.ast_node) - } -} -- cgit v1.2.3