use rustdoc_types::ItemKind;
use super::*;
const GROUP_ORDER: &[(&str, &[ItemKind])] = &[
("Modules", &[ItemKind::Module]),
("Structs", &[ItemKind::Struct]),
("Enums", &[ItemKind::Enum]),
("Traits", &[ItemKind::Trait]),
("Unions", &[ItemKind::Union]),
("Type Aliases", &[ItemKind::TypeAlias]),
("Functions", &[ItemKind::Function]),
("Constants", &[ItemKind::Constant]),
("Statics", &[ItemKind::Static]),
(
"Macros",
&[
ItemKind::Macro,
ItemKind::ProcAttribute,
ItemKind::ProcDerive,
],
),
("Primitives", &[ItemKind::Primitive]),
("Variants", &[ItemKind::Variant]),
];
#[derive(Debug)]
struct FlatItem<'a> {
path: String,
item: DocRef<'a, Item>,
}
impl<'a> Request<'a> {
#[allow(clippy::mutable_key_type)]
fn collect_flat_items(
&mut self,
collected: &mut Vec<FlatItem<'a>>,
visited: &mut std::collections::HashSet<DocRef<'a, Item>>,
path: Option<String>,
item: DocRef<'a, Item>,
context: &FormatContext,
) {
for child in self.children(item) {
if let Some(item_name) = child.name()
&& context.filter_match_kind(child.kind())
{
let path = path.as_deref().map_or_else(
|| item_name.to_string(),
|path| format!("{path}::{item_name}"),
);
collected.push(FlatItem {
path: path.clone(),
item: child,
});
if context.is_recursive() && visited.insert(child) {
self.collect_flat_items(collected, visited, Some(path), child, context);
}
}
}
}
fn format_grouped_flat_items(&self, items: &[FlatItem], context: &FormatContext) -> String {
if items.is_empty() {
return "\nNo items match the current filters.\n".to_string();
}
let mut groups: HashMap<ItemKind, Vec<&FlatItem>> = HashMap::new();
for flat_item in items {
let kind = flat_item.item.kind();
groups.entry(kind).or_default().push(flat_item);
}
let mut result = String::new();
for (group_name, kinds) in GROUP_ORDER {
let mut group_items: Vec<&FlatItem> = kinds
.iter()
.filter_map(|kind| groups.remove(kind))
.flatten()
.collect();
if group_items.is_empty() {
continue;
}
result.write_fmt(format_args!("\n{group_name}:\n"));
group_items.sort_by_key(|a| &a.path);
for flat_item in group_items {
result.push_str(&self.format_flat_item_line(flat_item, context));
}
}
let mut remaining: Vec<_> = groups.into_iter().collect();
remaining.sort_by_key(|(kind, _)| format!("{kind:?}"));
for (kind, mut group_items) in remaining {
result.write_fmt(format_args!("\n{kind:?}:\n"));
group_items.sort_by_key(|a| &a.path);
for flat_item in group_items {
result.push_str(&self.format_flat_item_line(flat_item, context));
}
}
result
}
fn format_flat_item_line(&self, flat_item: &FlatItem, context: &FormatContext) -> String {
let mut line = flat_item.path.to_string();
if let Some(docs) = self.docs_to_show(flat_item.item, true, context) {
line.push_str(" // ");
line.push_str(&docs);
}
line.push('\n');
line
}
#[allow(clippy::mutable_key_type)] pub(super) fn format_module(
&mut self,
item: DocRef<'a, Item>,
context: &FormatContext,
) -> String {
let mut result = String::new();
let mut collected = Vec::new();
let mut visited = std::collections::HashSet::new();
visited.insert(item);
self.collect_flat_items(&mut collected, &mut visited, None, item, context);
result.push_str(&self.format_grouped_flat_items(&collected, context));
result
}
}