use std::fmt::Debug;
use crate::parser::core::CoreRule;
use crate::parser::extset::MarkdownThatExt;
use crate::plugins::cmark::block::heading::ATXHeading;
use crate::plugins::cmark::block::lheading::SetextHeader;
use crate::{MarkdownThat, Node};
pub fn add(md: &mut MarkdownThat, slugify: fn(&str) -> String) {
md.ext.insert(SlugifyFunction(slugify));
md.add_rule::<AddHeadingAnchors>();
}
pub fn simple_slugify_fn(s: &str) -> String {
s.chars()
.map(|x| {
if x.is_alphanumeric() {
x.to_ascii_lowercase()
} else {
'-'
}
})
.collect()
}
#[derive(Clone, Copy)]
struct SlugifyFunction(fn(&str) -> String);
impl MarkdownThatExt for SlugifyFunction {}
impl Default for SlugifyFunction {
fn default() -> Self {
Self(simple_slugify_fn)
}
}
impl Debug for SlugifyFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SlugifyFunction").finish()
}
}
pub struct AddHeadingAnchors;
impl CoreRule for AddHeadingAnchors {
fn run(root: &mut Node, md: &MarkdownThat) {
let slugify = md
.ext
.get::<SlugifyFunction>()
.copied()
.unwrap_or_default()
.0;
root.walk_mut(|node, _| {
if node.is::<ATXHeading>() || node.is::<SetextHeader>() {
node.attrs.push(("id", slugify(&node.collect_text())));
}
});
}
}