From 72b28d75c9cf5b6a3115838ecd6de6f834af07b1 Mon Sep 17 00:00:00 2001 From: Bill Fraser Date: Sun, 26 Nov 2023 20:24:02 -0800 Subject: [PATCH] skip some redundant items --- src/browser_rustdoc.rs | 60 +++++++++++++++++++++++++++++++++++++++++- tests/browser_test.rs | 7 ++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/browser_rustdoc.rs b/src/browser_rustdoc.rs index 2555422..85b9dda 100644 --- a/src/browser_rustdoc.rs +++ b/src/browser_rustdoc.rs @@ -22,7 +22,14 @@ impl RustdocBrowser { Struct(_) => "struct", StructField(f) => return format!("{}: {}", name, type_label(f)), Enum(_) => "enum", - Variant(_) => "variant", + Variant(v) => { + if let Some(ty) = self.single_element_tuple_variant(v, id) { + // Include the name of the wrapped type in the label. + // list_items() will skip the redundant type later. + return format!("variant {name}({})", type_label(ty)); + } + "variant" + } Function(_) => "fn", // TODO: include signature? Trait(_) => "trait", TraitAlias(_) => "trait alias", @@ -65,6 +72,25 @@ impl RustdocBrowser { }; format!("{prefix} {name}") } + + fn single_element_tuple_variant<'a>( + &'a self, + v: &'a rustdoc_types::Variant, + id: ItemId<'a>, + ) -> Option<&'a rustdoc_types::Type> { + if let rustdoc_types::VariantKind::Tuple(t) = &v.kind { + if let Some(Some(inner_id)) = t.first() { + if let Some((_id, Item::Item(item))) = + self.analysis.get_item(id.crate_sibling(inner_id)) + { + if let rustdoc_types::ItemEnum::StructField(ty) = &item.inner { + return Some(ty); + } + } + } + } + None + } } impl<'a> Browser for &'a RustdocBrowser { @@ -85,6 +111,29 @@ impl<'a> Browser for &'a RustdocBrowser { } fn list_items(&self, parent_id: &ItemId<'a>) -> Vec<(String, (ItemId<'a>, Item<'a>))> { + // If true, skip showing this element's children and show the children of the first child + // instead. Basically, skip one level of nesting. Use when the item is redundant. + let mut use_first_child = false; + if let Some((_, Item::Item(parent))) = self.analysis.get_item(parent_id.clone()) { + match &parent.inner { + rustdoc_types::ItemEnum::Variant(v) + if self + .single_element_tuple_variant(v, parent_id.clone()) + .is_some() => + { + // Single-element tuple variant. The only child is a StructField for field "0". + // This adds nothing because the type name is already in the Variant's label. + use_first_child = true; + } + rustdoc_types::ItemEnum::StructField(_) => { + // StructField's only child is the type, which adds nothing, as the type name is + // already in the StructField's label. + use_first_child = true; + } + _ => (), + } + } + let mut items = self .analysis .items(parent_id) @@ -107,6 +156,15 @@ impl<'a> Browser for &'a RustdocBrowser { .collect::>(); sort_by_label(&mut items); + if use_first_child && !items.is_empty() { + assert_eq!( + items.len(), + 1, + "use_first_child on non-singleton children list: {items:#?}" + ); + return self.list_items(&items[0].1 .0); + } + items } diff --git a/tests/browser_test.rs b/tests/browser_test.rs index 6e83b5a..862c3f1 100644 --- a/tests/browser_test.rs +++ b/tests/browser_test.rs @@ -125,7 +125,7 @@ fn list_items() { x_e_items.labels(), &[ "variant StructVariant", - "variant TupleVariant", + "variant TupleVariant(S)", "variant UnitVariant", ] ); @@ -159,9 +159,10 @@ fn list_items() { let x_e_unit_items = BROWSER.list_items(&x_e_unit.0); assert_eq!(x_e_unit_items.labels(), &[] as &[&str]); - let x_e_tuple = x_e_items.by_label("variant TupleVariant"); + let x_e_tuple = x_e_items.by_label("variant TupleVariant(S)"); let x_e_tuple_items = BROWSER.list_items(&x_e_tuple.0); - assert_eq!(x_e_tuple_items.labels(), &["0: S"] as &[&str]); + // Skip the struct field and the struct, go straight to its items: + assert_eq!(x_e_tuple_items.labels(), x_s_items.labels()); let x_e_struct = x_e_items.by_label("variant StructVariant"); let x_e_struct_items = BROWSER.list_items(&x_e_struct.0);