1use super::{Block, Level, Markup};
2
3pub struct Html;
7
8impl Markup for Html {
9 fn markup(blocks: &[Block]) -> String {
10 let mut iter = blocks.iter();
11 let mut block = iter.next();
12 let mut in_list: Option<List> = None;
13
14 std::iter::from_fn(|| {
15 let intermediate = match (in_list.as_ref(), block) {
16 (None, Some(Block::Link(_))) => {
17 in_list = Some(List::Link);
18 Intermediate::OpenList
19 }
20 (None, Some(Block::ListItem(_))) => {
21 in_list = Some(List::Item);
22 Intermediate::OpenList
23 }
24 (Some(_), None) => {
25 in_list = None;
26 Intermediate::CloseList
27 }
28 (Some(List::Link), Some(b)) if !matches!(b, Block::Link(_)) => {
29 in_list = None;
30 Intermediate::CloseList
31 }
32 (Some(List::Item), Some(b)) if !matches!(b, Block::ListItem(_)) => {
33 in_list = None;
34 Intermediate::CloseList
35 }
36 (_, Some(block)) => Intermediate::Block(block),
37 (None, None) => return None,
38 };
39
40 if let Intermediate::Block(_) = intermediate {
41 block = iter.next();
42 }
43
44 Some(intermediate)
45 })
46 .map(|intermediate| match intermediate {
47 Intermediate::Block(block) => generate(block),
48 Intermediate::OpenList => "<ul>\n".to_string(),
49 Intermediate::CloseList => "</ul>\n".to_string(),
50 })
51 .collect::<String>()
52 }
53}
54
55enum List {
56 Link,
57 Item,
58}
59
60enum Intermediate<'a> {
61 Block(&'a Block),
62 OpenList,
63 CloseList,
64}
65
66fn generate(block: &Block) -> String {
67 match block {
68 Block::Text(text) => format!("<p>{}</p>\n", text),
69 Block::Link(link) => match link.label() {
70 Some(label) => {
71 format!("<li><a href=\"{}\">{}</a></li>\n", link.uri(), label)
72 }
73 None => {
74 format!("<li><a href=\"{0}\">{0}</a></li>\n", link.uri())
75 }
76 },
77 Block::Heading(Level::One, text) => format!("<h1>{}</h1>\n", text),
78 Block::Heading(Level::Two, text) => format!("<h2>{}</h2>\n", text),
79 Block::Heading(Level::Three, text) => format!("<h3>{}</h3>\n", text),
80 Block::ListItem(text) => {
81 format!("<li>{}</li>\n", text)
82 }
83 Block::Quote(text) => format!("<blockquote>{}</blockquote>\n", text),
84 Block::Preformatted(pre) => format!("<pre>\n{}\n</pre>\n", pre.text()),
85 Block::Empty => "".to_string(),
87 }
88}