use std::path::Path;
use fs_err as fs;
use indicatif::ProgressBar;
use rustdoc_types::{Item, ItemEnum};
use crate::error::Error;
use crate::generator::context::GeneratorContext;
use crate::generator::module::ModuleRenderer;
pub struct FlatGenerator<'a> {
ctx: &'a GeneratorContext<'a>,
output_dir: &'a Path,
progress: &'a ProgressBar,
}
impl<'a> FlatGenerator<'a> {
pub const fn new(
ctx: &'a GeneratorContext<'a>,
output_dir: &'a Path,
progress: &'a ProgressBar,
) -> Self {
Self {
ctx,
output_dir,
progress,
}
}
pub fn generate(&self, root: &Item) -> Result<(), Error> {
let renderer = ModuleRenderer::new(self.ctx, "index.md", true);
let index_content = renderer.render(root);
let index_path = self.output_dir.join("index.md");
fs::write(&index_path, index_content).map_err(Error::FileWrite)?;
self.progress.inc(1);
if let ItemEnum::Module(module) = &root.inner {
for item_id in &module.items {
if let Some(item) = self.ctx.krate.index.get(item_id)
&& let ItemEnum::Module(_) = &item.inner
&& self.ctx.should_include_item(item)
{
self.generate_module(item)?;
}
}
}
Ok(())
}
fn generate_module(&self, item: &Item) -> Result<(), Error> {
let name = item.name.as_deref().unwrap_or("unnamed");
let current_file = format!("{name}.md");
let renderer = ModuleRenderer::new(self.ctx, ¤t_file, false);
let content = renderer.render(item);
let file_path = self.output_dir.join(¤t_file);
fs::write(&file_path, content).map_err(Error::FileWrite)?;
self.progress.inc(1);
if let ItemEnum::Module(module) = &item.inner {
for sub_id in &module.items {
if let Some(sub_item) = self.ctx.krate.index.get(sub_id)
&& let ItemEnum::Module(_) = &sub_item.inner
&& self.ctx.should_include_item(sub_item)
{
let sub_name = sub_item.name.as_deref().unwrap_or("unnamed");
let flat_name = format!("{name}__{sub_name}");
self.generate_module_recursive(sub_item, &flat_name)?;
}
}
}
Ok(())
}
fn generate_module_recursive(&self, item: &Item, prefix: &str) -> Result<(), Error> {
let current_file = format!("{prefix}.md");
let renderer = ModuleRenderer::new(self.ctx, ¤t_file, false);
let content = renderer.render(item);
let file_path = self.output_dir.join(¤t_file);
fs::write(&file_path, content).map_err(Error::FileWrite)?;
self.progress.inc(1);
if let ItemEnum::Module(module) = &item.inner {
for sub_id in &module.items {
if let Some(sub_item) = self.ctx.krate.index.get(sub_id)
&& let ItemEnum::Module(_) = &sub_item.inner
&& self.ctx.should_include_item(sub_item)
{
let sub_name = sub_item.name.as_deref().unwrap_or("unnamed");
let new_prefix = format!("{prefix}__{sub_name}");
self.generate_module_recursive(sub_item, &new_prefix)?;
}
}
}
Ok(())
}
}