use crate::parser::ParserSettings;
use crate::preprocessors::{AstPreprocessor, AstPreprocessorConfig, Error, PreprocessorContext};
use cdoc_parser::ast::visitor::AstVisitor;
use cdoc_parser::ast::{Ast, Block, Inline};
use cdoc_parser::document::Document;
use cowstr::CowStr;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MdLabelsConfig;
pub struct MdLabels;
#[typetag::serde(name = "md_labels")]
impl AstPreprocessorConfig for MdLabelsConfig {
fn build(
&self,
_ctx: &PreprocessorContext,
_settings: &ParserSettings,
) -> anyhow::Result<Box<dyn AstPreprocessor>> {
Ok(Box::new(MdLabels))
}
}
impl AstPreprocessor for MdLabels {
fn name(&self) -> String {
todo!()
}
fn process(&mut self, mut input: Document<Ast>) -> Result<Document<Ast>, Error> {
self.walk_ast(&mut input.content.blocks)?;
Ok(input)
}
}
impl Display for MdLabels {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
impl AstVisitor for MdLabels {
fn visit_block(&mut self, block: &mut Block) -> anyhow::Result<()> {
if let Block::Heading { id, inner, .. } = block {
if let Some(cmd) = inner.iter_mut().find(|i| match i {
Inline::Command(c) => c.function.as_str() == "label",
_ => false,
}) {
if let Inline::Command(label) = cmd {
*id = label.label.clone();
}
*cmd = Inline::Text(CowStr::new());
} else {
*id = Some(CowStr::from(nanoid!()));
}
}
self.walk_block(block)
}
}