diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 84f03d111f27..c276e87786dd 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -188,28 +188,7 @@ impl HirDisplay for Struct { StructKind::Record => { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - let fields = self.fields(f.db); - let count = fields.len().min(limit); - f.write_char(if !has_where_clause { ' ' } else { '\n' })?; - if count == 0 { - if fields.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } - } else { - f.write_str(" {\n")?; - for field in &fields[..count] { - f.write_str(" ")?; - field.hir_fmt(f)?; - f.write_str(",\n")?; - } - - if fields.len() > count { - f.write_str(" /* … */\n")?; - } - f.write_str("}")?; - } + display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } } StructKind::Unit => _ = write_where_clause(def_id, f)?, @@ -226,18 +205,10 @@ impl HirDisplay for Enum { write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); write_generic_params(def_id, f)?; - let has_where_clause = write_where_clause(def_id, f)?; - let variants = self.variants(f.db); - if !variants.is_empty() { - f.write_char(if !has_where_clause { ' ' } else { '\n' })?; - f.write_str("{\n")?; - for variant in variants { - f.write_str(" ")?; - variant.hir_fmt(f)?; - f.write_str(",\n")?; - } - f.write_str("}")?; + let has_where_clause = write_where_clause(def_id, f)?; + if let Some(limit) = f.entity_limit { + display_variants(&self.variants(f.db), has_where_clause, limit, f)?; } Ok(()) @@ -251,22 +222,102 @@ impl HirDisplay for Union { write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); write_generic_params(def_id, f)?; + let has_where_clause = write_where_clause(def_id, f)?; + if let Some(limit) = f.entity_limit { + display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + } + Ok(()) + } +} + +fn display_fields( + fields: &[Field], + has_where_clause: bool, + limit: usize, + in_line: bool, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + let count = fields.len().min(limit); + let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; + f.write_char(if !has_where_clause { ' ' } else { separator })?; + if count == 0 { + if fields.is_empty() { + f.write_str("{}")?; + } else { + f.write_str("{ /* … */ }")?; + } + } else { + f.write_char('{')?; - let fields = self.fields(f.db); if !fields.is_empty() { - f.write_char(if !has_where_clause { ' ' } else { '\n' })?; - f.write_str("{\n")?; - for field in self.fields(f.db) { - f.write_str(" ")?; + f.write_char(separator)?; + for field in &fields[..count] { + f.write_str(indent)?; field.hir_fmt(f)?; - f.write_str(",\n")?; + f.write_char(',')?; + f.write_char(separator)?; + } + + if fields.len() > count { + f.write_str(indent)?; + f.write_str("/* … */")?; + f.write_char(separator)?; } - f.write_str("}")?; } - Ok(()) + f.write_str("}")?; + } + + Ok(()) +} + +fn display_variants( + variants: &[Variant], + has_where_clause: bool, + limit: usize, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + let count = variants.len().min(limit); + f.write_char(if !has_where_clause { ' ' } else { '\n' })?; + if count == 0 { + if variants.is_empty() { + f.write_str("{}")?; + } else { + f.write_str("{ /* … */ }")?; + } + } else { + f.write_str("{\n")?; + for variant in &variants[..count] { + f.write_str(" ")?; + write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?; + match variant.kind(f.db) { + StructKind::Tuple => { + if variant.fields(f.db).is_empty() { + f.write_str("()")?; + } else { + f.write_str("( /* … */ )")?; + } + } + StructKind::Record => { + if variant.fields(f.db).is_empty() { + f.write_str(" {}")?; + } else { + f.write_str(" { /* … */ }")?; + } + } + StructKind::Unit => {} + } + f.write_str(",\n")?; + } + + if variants.len() > count { + f.write_str(" /* … */\n")?; + } + f.write_str("}")?; } + + Ok(()) } impl HirDisplay for Field { @@ -304,21 +355,10 @@ impl HirDisplay for Variant { } f.write_char(')')?; } - VariantData::Record(fields) => { - f.write_str(" {")?; - let mut first = true; - for (_, field) in fields.iter() { - if first { - first = false; - f.write_char(' ')?; - } else { - f.write_str(", ")?; - } - // Enum variant fields must be pub. - write!(f, "{}: ", field.name.display(f.db.upcast()))?; - field.type_ref.hir_fmt(f)?; + VariantData::Record(_) => { + if let Some(limit) = f.entity_limit { + display_fields(&self.fields(f.db), false, limit, true, f)?; } - f.write_str(" }")?; } } Ok(()) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 822751c0e4ce..cd76ee4d7bdd 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -33,7 +33,8 @@ pub struct HoverConfig { pub keywords: bool, pub format: HoverDocFormat, pub max_trait_assoc_items_count: Option, - pub max_struct_field_count: Option, + pub max_fields_count: Option, + pub max_enum_variants_count: Option, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 7579d4d6d8b9..0809ea81d757 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -410,8 +410,21 @@ pub(super) fn definition( Definition::Trait(trait_) => { trait_.display_limited(db, config.max_trait_assoc_items_count).to_string() } - Definition::Adt(Adt::Struct(struct_)) => { - struct_.display_limited(db, config.max_struct_field_count).to_string() + Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => { + adt.display_limited(db, config.max_fields_count).to_string() + } + Definition::Variant(variant) => { + variant.display_limited(db, config.max_fields_count).to_string() + } + Definition::Adt(adt @ Adt::Enum(_)) => { + adt.display_limited(db, config.max_enum_variants_count).to_string() + } + Definition::SelfType(impl_def) => { + let self_ty = &impl_def.self_ty(db); + match self_ty.as_adt() { + Some(adt) => adt.display_limited(db, config.max_fields_count).to_string(), + None => self_ty.display(db).to_string(), + } } _ => def.label(db), }; diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 67f10f0374d8..52e57d788923 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -18,7 +18,8 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { format: HoverDocFormat::Markdown, keywords: true, max_trait_assoc_items_count: None, - max_struct_field_count: None, + max_fields_count: Some(5), + max_enum_variants_count: Some(5), }; fn check_hover_no_result(ra_fixture: &str) { @@ -51,13 +52,43 @@ fn check(ra_fixture: &str, expect: Expect) { } #[track_caller] -fn check_hover_struct_limit(count: usize, ra_fixture: &str, expect: Expect) { +fn check_hover_fields_limit( + fields_count: impl Into>, + ra_fixture: &str, + expect: Expect, +) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, - max_struct_field_count: Some(count), + max_fields_count: fields_count.into(), + ..HOVER_BASE_CONFIG + }, + FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + ) + .unwrap() + .unwrap(); + + let content = analysis.db.file_text(position.file_id); + let hovered_element = &content[hover.range]; + + let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); + expect.assert_eq(&actual) +} + +#[track_caller] +fn check_hover_enum_variants_limit( + variants_count: impl Into>, + ra_fixture: &str, + expect: Expect, +) { + let (analysis, position) = fixture::position(ra_fixture); + let hover = analysis + .hover( + &HoverConfig { + links_in_hover: true, + max_enum_variants_count: variants_count.into(), ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, @@ -876,7 +907,9 @@ struct Foo$0 { field: u32 } ```rust // size = 4, align = 4 - struct Foo + struct Foo { + field: u32, + } ``` "#]], ); @@ -896,6 +929,9 @@ struct Foo$0 where u32: Copy { field: u32 } struct Foo where u32: Copy, + { + field: u32, + } ``` "#]], ); @@ -903,7 +939,7 @@ struct Foo$0 where u32: Copy { field: u32 } #[test] fn hover_record_struct_limit() { - check_hover_struct_limit( + check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32, b: i32, c: i32 } @@ -917,7 +953,7 @@ fn hover_record_struct_limit() { ```rust // size = 12 (0xC), align = 4 - struct Foo { + struct Foo { a: u32, b: i32, c: i32, @@ -925,7 +961,7 @@ fn hover_record_struct_limit() { ``` "#]], ); - check_hover_struct_limit( + check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32 } @@ -939,13 +975,13 @@ fn hover_record_struct_limit() { ```rust // size = 4, align = 4 - struct Foo { + struct Foo { a: u32, } ``` "#]], ); - check_hover_struct_limit( + check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32, b: i32, c: i32, d: u32 } @@ -959,7 +995,7 @@ fn hover_record_struct_limit() { ```rust // size = 16 (0x10), align = 4 - struct Foo { + struct Foo { a: u32, b: i32, c: i32, @@ -968,6 +1004,338 @@ fn hover_record_struct_limit() { ``` "#]], ); + check_hover_fields_limit( + None, + r#" + struct Foo$0 { a: u32, b: i32, c: i32 } + "#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 12 (0xC), align = 4 + struct Foo + ``` + "#]], + ); + check_hover_fields_limit( + 0, + r#" + struct Foo$0 { a: u32, b: i32, c: i32 } + "#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 12 (0xC), align = 4 + struct Foo { /* … */ } + ``` + "#]], + ); + + // No extra spaces within `{}` when there are no fields + check_hover_fields_limit( + 5, + r#" + struct Foo$0 {} + "#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + struct Foo {} + ``` + "#]], + ); +} + +#[test] +fn hover_record_variant_limit() { + check_hover_fields_limit( + 3, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 12 (0xC), align = 4 + A { a: u32, b: i32, c: i32, } + ``` + "#]], + ); + check_hover_fields_limit( + 3, + r#" + enum Foo { A$0 { a: u32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 4, align = 4 + A { a: u32, } + ``` + "#]], + ); + check_hover_fields_limit( + 3, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32, d: u32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 16 (0x10), align = 4 + A { a: u32, b: i32, c: i32, /* … */ } + ``` + "#]], + ); + check_hover_fields_limit( + None, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 12 (0xC), align = 4 + A + ``` + "#]], + ); + check_hover_fields_limit( + 0, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 12 (0xC), align = 4 + A { /* … */ } + ``` + "#]], + ); +} + +#[test] +fn hover_enum_limit() { + check_hover_enum_variants_limit( + 5, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo { + A, + B, + } + ``` + "#]], + ); + check_hover_enum_variants_limit( + 1, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo { + A, + /* … */ + } + ``` + "#]], + ); + check_hover_enum_variants_limit( + 0, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo { /* … */ } + ``` + "#]], + ); + check_hover_enum_variants_limit( + None, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo + ``` + "#]], + ); + check_hover_enum_variants_limit( + 7, + r#"enum Enum$0 { + Variant {}, + Variant2 { field: i32 }, + Variant3 { field: i32, field2: i32 }, + Variant4(), + Variant5(i32), + Variant6(i32, i32), + Variant7, + Variant8, + }"#, + expect![[r#" + *Enum* + + ```rust + test + ``` + + ```rust + // size = 12 (0xC), align = 4, niches = 4294967288 + enum Enum { + Variant {}, + Variant2 { /* … */ }, + Variant3 { /* … */ }, + Variant4(), + Variant5( /* … */ ), + Variant6( /* … */ ), + Variant7, + /* … */ + } + ``` + "#]], + ); +} + +#[test] +fn hover_union_limit() { + check_hover_fields_limit( + 5, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo { + a: u32, + b: i32, + } + ``` + "#]], + ); + check_hover_fields_limit( + 1, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo { + a: u32, + /* … */ + } + ``` + "#]], + ); + check_hover_fields_limit( + 0, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo { /* … */ } + ``` + "#]], + ); + check_hover_fields_limit( + None, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo + ``` + "#]], + ); } #[test] @@ -1431,11 +1799,14 @@ impl Thing { ``` ```rust - struct Thing + struct Thing { + x: u32, + } ``` "#]], ); - check( + check_hover_fields_limit( + None, r#" struct Thing { x: u32 } impl Thing { @@ -1456,9 +1827,9 @@ impl Thing { ); check( r#" -enum Thing { A } +struct Thing { x: u32 } impl Thing { - pub fn new() -> Self$0 { Thing::A } + fn new() -> Self$0 { Self { x: 0 } } } "#, expect![[r#" @@ -1469,8 +1840,8 @@ impl Thing { ``` ```rust - enum Thing { - A, + struct Thing { + x: u32, } ``` "#]], @@ -1478,23 +1849,44 @@ impl Thing { check( r#" enum Thing { A } +impl Thing { + pub fn new() -> Self$0 { Thing::A } +} +"#, + expect![[r#" + *Self* + + ```rust + test + ``` + + ```rust + enum Thing { + A, + } + ``` + "#]], + ); + check( + r#" +enum Thing { A } impl Thing { pub fn thing(a: Self$0) {} } "#, expect![[r#" - *Self* + *Self* - ```rust - test - ``` + ```rust + test + ``` - ```rust - enum Thing { - A, - } - ``` - "#]], + ```rust + enum Thing { + A, + } + ``` + "#]], ); check( r#" @@ -2382,8 +2774,8 @@ fn test_hover_layout_of_enum() { ```rust // size = 16 (0x10), align = 8, niches = 254 enum Foo { - Variant1(u8, u16), - Variant2(i32, u8, i64), + Variant1( /* … */ ), + Variant2( /* … */ ), } ``` "#]], @@ -6554,7 +6946,7 @@ enum Enum { ```rust // size = 4, align = 4 - RecordV { field: u32 } + RecordV { field: u32, } ``` "#]], ); @@ -7936,7 +8328,9 @@ struct Pedro$0<'a> { ```rust // size = 16 (0x10), align = 8, niches = 1 - struct Pedro<'a> + struct Pedro<'a> { + hola: &str, + } ``` "#]], ) diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 3fef16df25e3..df625f740480 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -167,7 +167,8 @@ impl StaticIndex<'_> { keywords: true, format: crate::HoverDocFormat::Markdown, max_trait_assoc_items_count: None, - max_struct_field_count: None, + max_fields_count: Some(5), + max_enum_variants_count: Some(5), }; let tokens = tokens.filter(|token| { matches!( diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 14a418565429..52c09fb3945b 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -312,8 +312,10 @@ config_data! { /// How to render the size information in a memory layout hover. hover_memoryLayout_size: Option = Some(MemoryLayoutHoverRenderKindDef::Both), - /// How many fields of a struct to display when hovering a struct. - hover_show_structFields: Option = None, + /// How many variants of an enum to display when hovering on. Show none if empty. + hover_show_enumVariants: Option = Some(5), + /// How many fields of a struct, variant or union to display when hovering on. Show none if empty. + hover_show_fields: Option = Some(5), /// How many associated items of a trait to display when hovering a trait. hover_show_traitAssocItems: Option = None, @@ -1112,7 +1114,8 @@ impl Config { }, keywords: self.hover_documentation_keywords_enable().to_owned(), max_trait_assoc_items_count: self.hover_show_traitAssocItems().to_owned(), - max_struct_field_count: self.hover_show_structFields().to_owned(), + max_fields_count: self.hover_show_fields().to_owned(), + max_enum_variants_count: self.hover_show_enumVariants().to_owned(), } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index af4483a2cc31..ebacc5b7016e 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -533,10 +533,15 @@ How to render the offset information in a memory layout hover. -- How to render the size information in a memory layout hover. -- -[[rust-analyzer.hover.show.structFields]]rust-analyzer.hover.show.structFields (default: `null`):: +[[rust-analyzer.hover.show.enumVariants]]rust-analyzer.hover.show.enumVariants (default: `5`):: + -- -How many fields of a struct to display when hovering a struct. +How many variants of an enum to display when hovering on. Show none if empty. +-- +[[rust-analyzer.hover.show.fields]]rust-analyzer.hover.show.fields (default: `5`):: ++ +-- +How many fields of a struct, variant or union to display when hovering on. Show none if empty. -- [[rust-analyzer.hover.show.traitAssocItems]]rust-analyzer.hover.show.traitAssocItems (default: `null`):: + diff --git a/editors/code/package.json b/editors/code/package.json index c387e72a0c6f..aed0d9f898f9 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1152,9 +1152,18 @@ } ] }, - "rust-analyzer.hover.show.structFields": { - "markdownDescription": "How many fields of a struct to display when hovering a struct.", - "default": null, + "rust-analyzer.hover.show.enumVariants": { + "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.", + "default": 5, + "type": [ + "null", + "integer" + ], + "minimum": 0 + }, + "rust-analyzer.hover.show.fields": { + "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if empty.", + "default": 5, "type": [ "null", "integer"