From ddf2a8a948ed91bda14fef398c850c71c403ab59 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 9 Jan 2019 18:09:49 +0300 Subject: add completion detail --- crates/ra_ide_api/src/completion/completion_item.rs | 12 ++++++++++++ crates/ra_lsp_server/src/conv.rs | 1 + 2 files changed, 13 insertions(+) diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index a25b87bee..d707a84ef 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -11,6 +11,7 @@ pub struct CompletionItem { /// completion. completion_kind: CompletionKind, label: String, + detail: Option, lookup: Option, snippet: Option, kind: Option, @@ -51,6 +52,7 @@ impl CompletionItem { Builder { completion_kind, label, + detail: None, lookup: None, snippet: None, kind: None, @@ -60,6 +62,10 @@ impl CompletionItem { pub fn label(&self) -> &str { &self.label } + /// Short one-line additional information, like a type + pub fn detail(&self) -> Option<&str> { + self.detail.as_ref().map(|it| it.as_str()) + } /// What string is used for filtering. pub fn lookup(&self) -> &str { self.lookup @@ -87,6 +93,7 @@ impl CompletionItem { pub(crate) struct Builder { completion_kind: CompletionKind, label: String, + detail: Option, lookup: Option, snippet: Option, kind: Option, @@ -100,6 +107,7 @@ impl Builder { pub(crate) fn build(self) -> CompletionItem { CompletionItem { label: self.label, + detail: self.detail, lookup: self.lookup, snippet: self.snippet, kind: self.kind, @@ -118,6 +126,10 @@ impl Builder { self.kind = Some(kind); self } + pub(crate) fn detail(mut self, detail: impl Into) -> Builder { + self.detail = Some(detail.into()); + self + } pub(super) fn from_resolution( mut self, ctx: &CompletionContext, diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 5c8b3c194..35c679a4a 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -75,6 +75,7 @@ impl Conv for CompletionItem { fn conv(self) -> ::Output { let mut res = ::languageserver_types::CompletionItem { label: self.label().to_string(), + detail: self.detail().map(|it| it.to_string()), filter_text: Some(self.lookup().to_string()), kind: self.kind().map(|it| it.conv()), ..Default::default() -- cgit v1.2.3 From 56b2138d82620db946fe08ddc164c5e7e22be625 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 9 Jan 2019 18:46:02 +0300 Subject: show field types in completion --- crates/ra_hir/src/adt.rs | 55 +++++++++++++++++- crates/ra_hir/src/code_model_api.rs | 67 ++++++---------------- crates/ra_hir/src/lib.rs | 2 +- crates/ra_ide_api/src/completion/complete_dot.rs | 14 ++--- .../ra_ide_api/src/completion/completion_item.rs | 11 +++- 5 files changed, 88 insertions(+), 61 deletions(-) diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 602e7db74..d30390f25 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -4,7 +4,7 @@ use ra_db::Cancelable; use ra_syntax::ast::{self, NameOwner, StructFlavor, AstNode}; use crate::{ - DefId, Name, AsName, Struct, Enum, VariantData, StructField, HirDatabase, DefKind, + DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind, type_ref::TypeRef, }; @@ -12,6 +12,10 @@ impl Struct { pub(crate) fn new(def_id: DefId) -> Self { Struct { def_id } } + + pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Cancelable> { + Ok(db.struct_data(self.def_id)?.variant_data.clone()) + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -83,6 +87,51 @@ impl EnumData { } } +/// A single field of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StructField { + pub(crate) name: Name, + pub(crate) type_ref: TypeRef, +} + +/// Fields of an enum variant or struct +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum VariantData { + Struct(Vec), + Tuple(Vec), + Unit, +} + +impl VariantData { + pub fn fields(&self) -> &[StructField] { + match self { + VariantData::Struct(fields) | VariantData::Tuple(fields) => fields, + _ => &[], + } + } + + pub fn is_struct(&self) -> bool { + match self { + VariantData::Struct(..) => true, + _ => false, + } + } + + pub fn is_tuple(&self) -> bool { + match self { + VariantData::Tuple(..) => true, + _ => false, + } + } + + pub fn is_unit(&self) -> bool { + match self { + VariantData::Unit => true, + _ => false, + } + } +} + impl VariantData { fn new(flavor: StructFlavor) -> Self { match flavor { @@ -114,7 +163,7 @@ impl VariantData { pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> { self.fields() .iter() - .find(|f| f.name() == field_name) - .map(|f| f.type_ref()) + .find(|f| f.name == *field_name) + .map(|f| &f.type_ref) } } diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 66c016180..fa3e4baa7 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -5,12 +5,13 @@ use ra_db::{CrateId, Cancelable, FileId}; use ra_syntax::{ast, TreePtr, SyntaxNode}; use crate::{ - Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, + Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, type_ref::TypeRef, nameres::ModuleScope, db::HirDatabase, expr::BodySyntaxMapping, ty::InferenceResult, + adt::VariantData, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -137,58 +138,18 @@ impl Module { } } -/// A single field of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StructField { - pub(crate) name: Name, - pub(crate) type_ref: TypeRef, + struct_: Struct, + name: Name, } impl StructField { pub fn name(&self) -> &Name { &self.name } - - pub fn type_ref(&self) -> &TypeRef { - &self.type_ref - } -} - -/// Fields of an enum variant or struct -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum VariantData { - Struct(Vec), - Tuple(Vec), - Unit, -} - -impl VariantData { - pub fn fields(&self) -> &[StructField] { - match self { - VariantData::Struct(fields) | VariantData::Tuple(fields) => fields, - _ => &[], - } - } - - pub fn is_struct(&self) -> bool { - match self { - VariantData::Struct(..) => true, - _ => false, - } - } - - pub fn is_tuple(&self) -> bool { - match self { - VariantData::Tuple(..) => true, - _ => false, - } - } - - pub fn is_unit(&self) -> bool { - match self { - VariantData::Unit => true, - _ => false, - } + pub fn ty(&self, db: &impl HirDatabase) -> Cancelable> { + db.type_for_field(self.struct_.def_id, self.name.clone()) } } @@ -206,8 +167,18 @@ impl Struct { Ok(db.struct_data(self.def_id)?.name.clone()) } - pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable> { - Ok(db.struct_data(self.def_id)?.variant_data.clone()) + pub fn fields(&self, db: &impl HirDatabase) -> Cancelable> { + let res = db + .struct_data(self.def_id)? + .variant_data + .fields() + .iter() + .map(|it| StructField { + struct_: self.clone(), + name: it.name.clone(), + }) + .collect(); + Ok(res) } } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index ca7f395a8..1b6b72c98 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -56,6 +56,6 @@ pub use self::code_model_api::{ Crate, CrateDependency, Def, Module, ModuleSource, Problem, - Struct, Enum, VariantData, StructField, + Struct, Enum, Function, FnSignature, }; diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 5d4e60dc5..65bba6dc7 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -28,13 +28,13 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) Ty::Adt { def_id, .. } => { match def_id.resolve(ctx.db)? { Def::Struct(s) => { - let variant_data = s.variant_data(ctx.db)?; - for field in variant_data.fields() { + for field in s.fields(ctx.db)? { CompletionItem::new( CompletionKind::Reference, field.name().to_string(), ) .kind(CompletionItemKind::Field) + .set_detail(field.ty(ctx.db)?.map(|ty| ty.to_string())) .add_to(acc); } } @@ -72,7 +72,7 @@ mod tests { a.<|> } ", - r#"the_field"#, + r#"the_field "u32""#, ); } @@ -80,14 +80,14 @@ mod tests { fn test_struct_field_completion_self() { check_ref_completion( r" - struct A { the_field: u32 } + struct A { the_field: (u32,) } impl A { fn foo(self) { self.<|> } } ", - r#"the_field"#, + r#"the_field "(u32,)""#, ); } @@ -95,14 +95,14 @@ mod tests { fn test_struct_field_completion_autoderef() { check_ref_completion( r" - struct A { the_field: u32 } + struct A { the_field: (u32, i32) } impl A { fn foo(&self) { self.<|> } } ", - r#"the_field"#, + r#"the_field "(u32, i32)""#, ); } diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index d707a84ef..334449fae 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -126,8 +126,12 @@ impl Builder { self.kind = Some(kind); self } - pub(crate) fn detail(mut self, detail: impl Into) -> Builder { - self.detail = Some(detail.into()); + #[allow(unused)] + pub(crate) fn detail(self, detail: impl Into) -> Builder { + self.set_detail(Some(detail)) + } + pub(crate) fn set_detail(mut self, detail: Option>) -> Builder { + self.detail = detail.map(Into::into); self } pub(super) fn from_resolution( @@ -239,6 +243,9 @@ impl Completions { } else { res.push_str(&c.label); } + if let Some(detail) = &c.detail { + res.push_str(&format!(" {:?}", detail)); + } if let Some(snippet) = &c.snippet { res.push_str(&format!(" {:?}", snippet)); } -- cgit v1.2.3