Complete enum variants identically to structures.

In particular:
 - unit variants now display in the menu as "Variant", complete to "Variant", and display a detail of "Variant" (was "()")
 - tuple variants now display in the menu as "Variant(…)", complete to "Variant(${1:()})$0" (was "Variant($0)"), and display a detail of "Variant(type)" (was "(type)")
 - record variants now display in the menu as "Variant {…}", complete to "Variant { x: ${1:()} }$0" (was "Variant"), and display a detail of "Variant { x: type }" (was "{x: type}")

This behavior is identical to that of struct completions. In addition, tuple variants no longer set triggers_call_info, as to my understanding it's unnecessary now that we're emitting placeholders.

Tests have been updated to match, and the render::enum_variant::tests::inserts_parens_for_tuple_enums test has been removed entirely as it's covered by other tests (render::enum_detail_includes_{record, tuple}_fields, render::enum_detail_just_name_for_unit, render::pattern::enum_qualified).
This commit is contained in:
Morgan Thomas 2022-03-11 18:26:01 -08:00
parent 1c5b2c7d03
commit 2a22cf8efc
7 changed files with 69 additions and 90 deletions

View file

@ -580,8 +580,8 @@ impl Foo {
}
"#,
expect![[r#"
ev Bar ()
ev Baz ()
ev Bar Bar
ev Baz Baz
me foo() fn(self)
"#]],
);
@ -626,7 +626,7 @@ fn main() {
}
"#,
expect![[r#"
ev Bar ()
ev Bar Bar
"#]],
);
}

View file

@ -429,14 +429,14 @@ fn main() { Foo::Fo$0 }
expect![[r#"
[
CompletionItem {
label: "Foo",
label: "Foo {…}",
source_range: 54..56,
delete: 54..56,
insert: "Foo",
insert: "Foo { x: ${1:()}, y: ${2:()} }$0",
kind: SymbolKind(
Variant,
),
detail: "{x: i32, y: i32}",
detail: "Foo { x: i32, y: i32 }",
},
]
"#]],
@ -444,7 +444,7 @@ fn main() { Foo::Fo$0 }
}
#[test]
fn enum_detail_doesnt_include_tuple_fields() {
fn enum_detail_includes_tuple_fields() {
check(
r#"
enum Foo { Foo (i32, i32) }
@ -458,13 +458,11 @@ fn main() { Foo::Fo$0 }
label: "Foo(…)",
source_range: 46..48,
delete: 46..48,
insert: "Foo($0)",
insert: "Foo(${1:()}, ${2:()})$0",
kind: SymbolKind(
Variant,
),
lookup: "Foo",
detail: "(i32, i32)",
trigger_call_info: true,
detail: "Foo(i32, i32)",
},
]
"#]],
@ -511,7 +509,7 @@ fn main() { fo$0 }
}
#[test]
fn enum_detail_just_parentheses_for_unit() {
fn enum_detail_just_name_for_unit() {
check(
r#"
enum Foo { Foo }
@ -525,11 +523,11 @@ fn main() { Foo::Fo$0 }
label: "Foo",
source_range: 35..37,
delete: 35..37,
insert: "Foo",
insert: "Foo$0",
kind: SymbolKind(
Variant,
),
detail: "()",
detail: "Foo",
},
]
"#]],
@ -573,15 +571,15 @@ fn main() { let _: m::Spam = S$0 }
),
},
CompletionItem {
label: "Spam::Bar(…)",
label: "m::Spam::Bar(…)",
source_range: 75..76,
delete: 75..76,
insert: "Spam::Bar($0)",
insert: "m::Spam::Bar(${1:()})$0",
kind: SymbolKind(
Variant,
),
lookup: "Spam::Bar",
detail: "(i32)",
detail: "m::Spam::Bar(i32)",
relevance: CompletionRelevance {
exact_name_match: false,
type_match: Some(
@ -592,18 +590,17 @@ fn main() { let _: m::Spam = S$0 }
is_private_editable: false,
exact_postfix_snippet_match: false,
},
trigger_call_info: true,
},
CompletionItem {
label: "m::Spam::Foo",
source_range: 75..76,
delete: 75..76,
insert: "m::Spam::Foo",
insert: "m::Spam::Foo$0",
kind: SymbolKind(
Variant,
),
lookup: "Spam::Foo",
detail: "()",
detail: "m::Spam::Foo",
relevance: CompletionRelevance {
exact_name_match: false,
type_match: Some(
@ -788,11 +785,11 @@ use self::E::*;
label: "V",
source_range: 10..12,
delete: 10..12,
insert: "V",
insert: "V$0",
kind: SymbolKind(
Variant,
),
detail: "()",
detail: "V",
documentation: Documentation(
"variant docs",
),

View file

@ -8,6 +8,7 @@ use crate::{context::PathKind, item::Builder, patterns::ImmediateLocation, Compl
#[derive(Debug)]
pub(super) enum Params {
Named(Option<hir::SelfParam>, Vec<hir::Param>),
#[allow(dead_code)]
Anonymous(usize),
}

View file

@ -1,13 +1,15 @@
//! Renderer for `enum` variants.
use hir::{db::HirDatabase, HasAttrs, HirDisplay, StructKind};
use hir::{HasAttrs, StructKind};
use ide_db::SymbolKind;
use itertools::Itertools;
use syntax::SmolStr;
use crate::{
item::{CompletionItem, ImportEdit},
render::{builder_ext::Params, compute_ref_match, compute_type_match, RenderContext},
render::{
compound::{render_record, render_tuple, RenderedCompound},
compute_ref_match, compute_type_match, RenderContext,
},
CompletionRelevance,
};
@ -46,20 +48,46 @@ fn render(
let qualified_name = qualified_name.to_string();
let short_qualified_name: SmolStr = short_qualified_name.to_string().into();
let mut item = CompletionItem::new(SymbolKind::Variant, ctx.source_range(), qualified_name);
let mut rendered = match variant_kind {
StructKind::Tuple => {
render_tuple(db, ctx.snippet_cap(), &variant.fields(db), Some(&qualified_name))
}
StructKind::Record => {
render_record(db, ctx.snippet_cap(), &variant.fields(db), Some(&qualified_name))
}
StructKind::Unit => {
RenderedCompound { literal: qualified_name.clone(), detail: qualified_name.clone() }
}
};
if ctx.snippet_cap().is_some() {
rendered.literal.push_str("$0");
}
let mut item = CompletionItem::new(
SymbolKind::Variant,
ctx.source_range(),
match variant_kind {
StructKind::Tuple => SmolStr::from_iter([&qualified_name, "(…)"]),
StructKind::Record => SmolStr::from_iter([&qualified_name, " {…}"]),
StructKind::Unit => qualified_name.into(),
},
);
item.set_documentation(variant.docs(db))
.set_deprecated(ctx.is_deprecated(variant))
.detail(detail(db, variant, variant_kind));
.detail(rendered.detail);
match ctx.snippet_cap() {
Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal),
None => item.insert_text(rendered.literal),
};
if let Some(import_to_add) = import_to_add {
item.add_import(import_to_add);
}
if variant_kind == hir::StructKind::Tuple {
cov_mark::hit!(inserts_parens_for_tuple_enums);
let params = Params::Anonymous(variant.fields(db).len());
item.add_call_parens(completion, short_qualified_name, params);
} else if qualified {
if qualified {
item.lookup_by(short_qualified_name);
}
@ -75,50 +103,3 @@ fn render(
item.build()
}
fn detail(db: &dyn HirDatabase, variant: hir::Variant, variant_kind: StructKind) -> String {
let detail_types = variant.fields(db).into_iter().map(|field| (field.name(db), field.ty(db)));
match variant_kind {
hir::StructKind::Tuple | hir::StructKind::Unit => {
format!("({})", detail_types.format_with(", ", |(_, t), f| f(&t.display(db))))
}
hir::StructKind::Record => {
format!(
"{{{}}}",
detail_types.format_with(", ", |(n, t), f| {
f(&n)?;
f(&": ")?;
f(&t.display(db))
}),
)
}
}
}
#[cfg(test)]
mod tests {
use crate::tests::check_edit;
#[test]
fn inserts_parens_for_tuple_enums() {
cov_mark::check!(inserts_parens_for_tuple_enums);
check_edit(
"Some",
r#"
enum Option<T> { Some(T), None }
use Option::*;
fn main() -> Option<i32> {
Som$0
}
"#,
r#"
enum Option<T> { Some(T), None }
use Option::*;
fn main() -> Option<i32> {
Some($0)
}
"#,
);
}
}

View file

@ -61,7 +61,7 @@ fn baz() {
fn function() fn()
sc STATIC
un Union
ev TupleV() (u32)
ev TupleV() TupleV(u32)
ct CONST
"#]],
)
@ -171,7 +171,7 @@ impl Unit {
fn function() fn()
sc STATIC
un Union
ev TupleV() (u32)
ev TupleV() TupleV(u32)
ct CONST
"#]],
);
@ -200,7 +200,7 @@ impl Unit {
fn function() fn()
sc STATIC
un Union
ev TupleV() (u32)
ev TupleV() TupleV(u32)
ct CONST
"#]],
);
@ -543,9 +543,9 @@ fn func() {
}
"#,
expect![[r#"
ev TupleV() (u32)
ev RecordV {field: u32}
ev UnitV ()
ev TupleV() TupleV(u32)
ev RecordV {} RecordV { field: u32 }
ev UnitV UnitV
ct ASSOC_CONST const ASSOC_CONST: ()
fn assoc_fn() fn()
ta AssocType type AssocType = ()

View file

@ -218,7 +218,7 @@ fn foo() {
expect![[r#"
kw ref
kw mut
ev E::X ()
ev E::X E::X
en E
ma m!() macro_rules! m
"#]],
@ -291,9 +291,9 @@ fn func() {
}
"#,
expect![[r#"
ev TupleV() (u32)
ev RecordV {field: u32}
ev UnitV ()
ev TupleV() TupleV(u32)
ev RecordV {} RecordV { field: u32 }
ev UnitV UnitV
"#]],
);
}

View file

@ -167,7 +167,7 @@ impl Foo {
}
"#,
expect![[r#"
ev Variant ()
ev Variant Variant
"#]],
);
}