1use markdown_it::{generics::inline::emph_pair, MarkdownIt, Node, NodeValue, Renderer};
18
19#[derive(Debug)]
20pub struct Sub;
21
22impl NodeValue for Sub {
23 fn render(&self, node: &Node, fmt: &mut dyn Renderer) {
24 fmt.open("sub", &node.attrs);
25 fmt.contents(&node.children);
26 fmt.close("sub");
27 }
28}
29
30pub fn add(md: &mut MarkdownIt) {
32 emph_pair::add_with::<'~', 1, true>(md, || Node::new(Sub));
33}
34
35#[cfg(test)]
36mod test {
37 use super::add;
38 use markdown_it::{
39 plugins::{cmark, extra},
40 MarkdownIt,
41 };
42 use rstest::rstest;
43 use std::sync::LazyLock;
44
45 static MARKDOWN_PARSER: LazyLock<MarkdownIt> = LazyLock::new(|| {
46 let mut parser = MarkdownIt::new();
47 cmark::add(&mut parser);
48 extra::add(&mut parser);
49 add(&mut parser);
50
51 parser
52 });
53
54 #[rstest]
55 #[case("~foo~", "<p><sub>foo</sub></p>\n")]
56 #[case("foo~", "<p>foo~</p>\n")]
57 #[case("~foo", "<p>~foo</p>\n")]
58 #[case("foo~bar~", "<p>foo<sub>bar</sub></p>\n")]
59 #[case("~~foo~bar~~~", "<p><s>foo<sub>bar</sub></s></p>\n")]
60 #[case("\\~foo~", "<p>~foo~</p>\n")]
61 #[case("~foo\\~", "<p>~foo~</p>\n")]
62 fn test(#[case] md_str: &str, #[case] expected: &str) {
63 let result = MARKDOWN_PARSER.parse(md_str).xrender();
64
65 assert_eq!(result, String::from(expected));
66 }
67}