typlite/parser/list.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
//! HTML list parsing module, handling conversion of ordered and unordered lists
use cmark_writer::ast::{ListItem, Node};
use typst::html::{tag, HtmlElement, HtmlNode};
use crate::attributes::{ListItemAttr, TypliteAttrsParser};
use crate::Result;
use super::core::HtmlToAstParser;
/// List parser
pub struct ListParser;
impl ListParser {
/// Convert HTML list to ListItem vector
pub fn convert_list(
parser: &mut HtmlToAstParser,
element: &HtmlElement,
) -> Result<Vec<ListItem>> {
let mut all_items = Vec::new();
let prev_buffer = std::mem::take(&mut parser.inline_buffer);
let is_ordered = element.tag == tag::ol;
for child in &element.children {
if let HtmlNode::Element(li) = child {
if li.tag == tag::li {
let attrs = ListItemAttr::parse(&li.attrs)?;
let mut item_content = Vec::new();
parser.begin_list();
for li_child in &li.children {
match li_child {
HtmlNode::Text(text, _) => {
parser
.inline_buffer
.push(Node::Text(text.as_str().to_string()));
}
HtmlNode::Element(child_elem) => {
if child_elem.tag == tag::ul || child_elem.tag == tag::ol {
// Handle nested lists
if !parser.inline_buffer.is_empty() {
item_content.push(Node::Paragraph(std::mem::take(
&mut parser.inline_buffer,
)));
}
parser.list_level += 1;
let items = Self::convert_list(parser, child_elem)?;
parser.list_level -= 1;
if child_elem.tag == tag::ul {
item_content.push(Node::UnorderedList(items));
} else {
item_content.push(Node::OrderedList { start: 1, items });
}
} else {
parser.convert_element(child_elem)?;
}
}
_ => {}
}
}
parser.end_list();
if !parser.inline_buffer.is_empty() {
item_content
.push(Node::Paragraph(std::mem::take(&mut parser.inline_buffer)));
}
if !item_content.is_empty() {
if is_ordered {
all_items.push(ListItem::Ordered {
number: attrs.value,
content: item_content,
});
} else {
all_items.push(ListItem::Unordered {
content: item_content,
});
}
}
}
}
}
parser.inline_buffer = prev_buffer;
Ok(all_items)
}
}