1 //! Code common to structs, unions, and enum variants.
3 use crate::context::CompletionContext;
4 use hir::{db::HirDatabase, HasAttrs, HasVisibility, HirDisplay, StructKind};
5 use ide_db::SnippetCap;
6 use itertools::Itertools;
9 /// A rendered struct, union, or enum variant, split into fields for actual
10 /// auto-completion (`literal`, using `field: ()`) and display in the
11 /// completions menu (`detail`, using `field: type`).
12 pub(crate) struct RenderedLiteral {
13 pub(crate) literal: String,
14 pub(crate) detail: String,
17 /// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for
18 /// the `name` argument for an anonymous type.
19 pub(crate) fn render_record_lit(
21 snippet_cap: Option<SnippetCap>,
22 fields: &[hir::Field],
24 ) -> RenderedLiteral {
25 let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
26 if snippet_cap.is_some() {
27 f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1))
29 f(&format_args!("{}: ()", field.name(db)))
33 let types = fields.iter().format_with(", ", |field, f| {
34 f(&format_args!("{}: {}", field.name(db), field.ty(db).display(db)))
38 literal: format!("{} {{ {} }}", path, completions),
39 detail: format!("{} {{ {} }}", path, types),
43 /// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for
44 /// the `name` argument for an anonymous type.
45 pub(crate) fn render_tuple_lit(
47 snippet_cap: Option<SnippetCap>,
48 fields: &[hir::Field],
50 ) -> RenderedLiteral {
51 let completions = fields.iter().enumerate().format_with(", ", |(idx, _), f| {
52 if snippet_cap.is_some() {
53 f(&format_args!("${{{}:()}}", idx + 1))
55 f(&format_args!("()"))
59 let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db)));
62 literal: format!("{}({})", path, completions),
63 detail: format!("{}({})", path, types),
67 /// Find all the visible fields in a given list. Returns the list of visible
68 /// fields, plus a boolean for whether the list is comprehensive (contains no
69 /// private fields and its item is not marked `#[non_exhaustive]`).
70 pub(crate) fn visible_fields(
71 ctx: &CompletionContext,
72 fields: &[hir::Field],
74 ) -> Option<(Vec<hir::Field>, bool)> {
75 let module = ctx.module;
76 let n_fields = fields.len();
79 .filter(|field| field.is_visible_from(ctx.db, module))
84 n_fields - fields.len() > 0 || item.attrs(ctx.db).by_key("non_exhaustive").exists();
85 Some((fields, fields_omitted))
88 /// Format a struct, etc. literal option for display in the completions menu.
89 pub(crate) fn format_literal_label(name: &str, kind: StructKind) -> SmolStr {
91 StructKind::Tuple => SmolStr::from_iter([name, "(…)"]),
92 StructKind::Record => SmolStr::from_iter([name, " {…}"]),
93 StructKind::Unit => name.into(),