diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index b5bf6b5514..a2662d2932 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs @@ -260,8 +260,8 @@ fn foo() { let _ = lib::S::$0 } "#, expect![[r#" fn public_method() fn() - ct PUBLIC_CONST pub const PUBLIC_CONST: u32 = 1; - ta PublicType pub type PublicType = u32; + ct PUBLIC_CONST pub const PUBLIC_CONST: u32; + ta PublicType pub type PublicType; "#]], ); } @@ -392,10 +392,10 @@ impl Sub for Wrap { expect![[r#" ta SubTy (as Sub) type SubTy; ta Ty (as Super) type Ty; - ct CONST (as Super) const CONST: u8 = 0; + ct CONST (as Super) const CONST: u8; fn func() (as Super) fn() me method(…) (as Super) fn(&self) - ct C2 (as Sub) const C2: () = (); + ct C2 (as Sub) const C2: (); fn subfunc() (as Sub) fn() me submethod(…) (as Sub) fn(&self) "#]], @@ -626,7 +626,7 @@ impl u8 { } "#, expect![[r#" - ct MAX pub const MAX: Self = 255; + ct MAX pub const MAX: Self; me func(…) fn(self) "#]], ); diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs index 12bccfae11..02f711f51d 100644 --- a/crates/ide_completion/src/completions/snippet.rs +++ b/crates/ide_completion/src/completions/snippet.rs @@ -115,7 +115,7 @@ fn add_custom_completions( for import in imports.into_iter() { builder.add_import(import); } - builder.detail(snip.description.as_deref().unwrap_or_default()); + builder.set_detail(snip.description.clone()); builder.add_to(acc); }, ); diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index a1d4eb998f..d4f35b5dcd 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -433,7 +433,7 @@ fn main() { Foo::Fo$0 } kind: SymbolKind( Variant, ), - detail: "{ x: i32, y: i32 }", + detail: "{x: i32, y: i32}", }, ] "#]], diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index 728e0e2a17..26cb73d09c 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs @@ -1,10 +1,10 @@ //! Renderer for `enum` variants. -use std::iter; +use std::{iter, mem}; use hir::{HasAttrs, HirDisplay}; use ide_db::SymbolKind; -use itertools::Itertools; +use stdx::format_to; use crate::{ item::{CompletionItem, ImportEdit}, @@ -105,18 +105,31 @@ impl<'a> EnumRender<'a> { .into_iter() .map(|field| (field.name(self.ctx.db()), field.ty(self.ctx.db()))); + let mut b = String::new(); + let mut first_run = true; match self.variant_kind { - hir::StructKind::Tuple | hir::StructKind::Unit => format!( - "({})", - detail_types.map(|(_, t)| t.display(self.ctx.db()).to_string()).format(", ") - ), - hir::StructKind::Record => format!( - "{{ {} }}", - detail_types - .map(|(n, t)| format!("{}: {}", n, t.display(self.ctx.db()).to_string())) - .format(", ") - ), + hir::StructKind::Tuple | hir::StructKind::Unit => { + format_to!(b, "("); + for (_, t) in detail_types { + if !mem::take(&mut first_run) { + format_to!(b, ", "); + } + format_to!(b, "{}", t.display(self.ctx.db())); + } + format_to!(b, ")"); + } + hir::StructKind::Record => { + format_to!(b, "{{"); + for (n, t) in detail_types { + if !mem::take(&mut first_run) { + format_to!(b, ", "); + } + format_to!(b, "{}: {}", n, t.display(self.ctx.db())); + } + format_to!(b, "}}"); + } } + b } } diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index f598b414a7..86dfbf7fc8 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs @@ -4,6 +4,7 @@ use either::Either; use hir::{AsAssocItem, HasSource, HirDisplay}; use ide_db::SymbolKind; use itertools::Itertools; +use stdx::format_to; use syntax::ast; use crate::{ @@ -122,14 +123,11 @@ impl<'a> FunctionRender<'a> { fn detail(&self) -> String { let ret_ty = self.func.ret_type(self.ctx.db()); - let ret = if ret_ty.is_unit() { - // Omit the return type if it is the unit type - String::new() - } else { - format!(" {}", self.ty_display()) - }; - - format!("fn({}){}", self.params_display(), ret) + let mut detail = format!("fn({})", self.params_display()); + if !ret_ty.is_unit() { + format_to!(detail, " -> {}", ret_ty.display(self.ctx.db())); + } + detail } fn params_display(&self) -> String { @@ -153,12 +151,6 @@ impl<'a> FunctionRender<'a> { } } - fn ty_display(&self) -> String { - let ret_ty = self.func.ret_type(self.ctx.db()); - - format!("-> {}", ret_ty.display(self.ctx.db())) - } - fn params(&self) -> Params { let ast_params = match self.ast_node.param_list() { Some(it) => it, diff --git a/crates/ide_completion/src/snippet.rs b/crates/ide_completion/src/snippet.rs index bcaa1ded8f..1a3f42b839 100644 --- a/crates/ide_completion/src/snippet.rs +++ b/crates/ide_completion/src/snippet.rs @@ -176,6 +176,9 @@ fn validate_snippet( imports.push(green); } let snippet = snippet.iter().join("\n"); - let description = if description.is_empty() { None } else { Some(description.into()) }; + let description = (!description.is_empty()) + .then(|| description.split_once('\n').map_or(description, |(it, _)| it)) + .map(ToOwned::to_owned) + .map(Into::into); Some((imports.into_boxed_slice(), snippet, description)) } diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs index a634808734..eba2a5e1ef 100644 --- a/crates/ide_completion/src/tests/expression.rs +++ b/crates/ide_completion/src/tests/expression.rs @@ -544,11 +544,11 @@ fn func() { "#, expect![[r#" ev TupleV(…) (u32) - ev RecordV { field: u32 } + ev RecordV {field: u32} ev UnitV () - ct ASSOC_CONST const ASSOC_CONST: () = (); + ct ASSOC_CONST const ASSOC_CONST: (); fn assoc_fn() fn() - ta AssocType type AssocType = (); + ta AssocType type AssocType; "#]], ); } diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs index 6dd1b66998..81c45c64cc 100644 --- a/crates/ide_completion/src/tests/pattern.rs +++ b/crates/ide_completion/src/tests/pattern.rs @@ -286,11 +286,11 @@ fn func() { "#, expect![[r#" ev TupleV(…) (u32) - ev RecordV { field: u32 } + ev RecordV {field: u32} ev UnitV () - ct ASSOC_CONST const ASSOC_CONST: () = (); + ct ASSOC_CONST const ASSOC_CONST: (); fn assoc_fn() fn() - ta AssocType type AssocType = (); + ta AssocType type AssocType; "#]], ); } diff --git a/crates/ide_completion/src/tests/type_pos.rs b/crates/ide_completion/src/tests/type_pos.rs index a03f1e7ff8..a76f97f3da 100644 --- a/crates/ide_completion/src/tests/type_pos.rs +++ b/crates/ide_completion/src/tests/type_pos.rs @@ -199,7 +199,7 @@ impl Enum { fn func(_: Enum::$0) {} "#, expect![[r#" - ta AssocType type AssocType = (); + ta AssocType type AssocType; "#]], ); } diff --git a/crates/syntax/src/display.rs b/crates/syntax/src/display.rs index 95e37944cc..e2115cbd2b 100644 --- a/crates/syntax/src/display.rs +++ b/crates/syntax/src/display.rs @@ -1,10 +1,6 @@ -//! This module contains utilities for turning SyntaxNodes and HIR types -//! into types that may be used to render in a UI. +//! This module contains utilities for rendering syntax nodes into a string representing their signature. -use crate::{ - ast::{self, AstNode, HasAttrs, HasGenericParams, HasName}, - SyntaxKind::{ATTR, COMMENT}, -}; +use crate::ast::{self, HasAttrs, HasGenericParams, HasName}; use ast::HasVisibility; use stdx::format_to; @@ -55,25 +51,39 @@ pub fn function_declaration(node: &ast::Fn) -> String { } pub fn const_label(node: &ast::Const) -> String { - let label: String = node - .syntax() - .children_with_tokens() - .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) - .map(|node| node.to_string()) - .collect(); - - label.trim().to_owned() + let mut s = String::new(); + if let Some(vis) = node.visibility() { + format_to!(s, "{} ", vis); + } + format_to!(s, "const "); + if let Some(name) = node.name() { + format_to!(s, "{}", name); + } else { + format_to!(s, "?"); + } + format_to!(s, ": "); + if let Some(ty) = node.ty() { + format_to!(s, "{}", ty); + } else { + format_to!(s, "?"); + } + format_to!(s, ";"); + s } pub fn type_label(node: &ast::TypeAlias) -> String { - let label: String = node - .syntax() - .children_with_tokens() - .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) - .map(|node| node.to_string()) - .collect(); - - label.trim().to_owned() + let mut s = String::new(); + if let Some(vis) = node.visibility() { + format_to!(s, "{} ", vis); + } + format_to!(s, "type "); + if let Some(name) = node.name() { + format_to!(s, "{}", name); + } else { + format_to!(s, "?"); + } + format_to!(s, ";"); + s } pub fn macro_label(node: &ast::Macro) -> String {