Layout lists

This commit is contained in:
mars 2022-10-09 02:52:59 -06:00
parent 8ae57a2413
commit d7c93ee776
3 changed files with 84 additions and 6 deletions

View File

@ -41,6 +41,18 @@ lines.")
(ol
(li "List entry 1")
(ul
(li "Unordered list subentry")
(li "Unordered list subentry")
(li "Unordered list subentry")
(li "Unordered list subentry"))
(li "List entry 2")
(li "List entry 3"))
(ol
(li "Ordered list subentry")
(li "Ordered list subentry"))
(li "List entry 3")
(ul
(li "Super long list item: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
))
)

View File

@ -2,9 +2,13 @@ use crate::style::Stylesheet;
use crate::tag::*;
impl TextTag {
pub fn layout(&self, style: &Stylesheet, available_width: usize) -> Vec<String> {
pub fn layout<'a>(
&self,
style: &Stylesheet,
options: impl Into<textwrap::Options<'a>>,
) -> Vec<String> {
let styled = self.style(style);
textwrap::wrap(&styled, available_width)
textwrap::wrap(&styled, options)
.into_iter()
.map(|s| s.to_string())
.collect()
@ -88,13 +92,75 @@ impl BlockTag {
.collect()
}
P => self.layout_text_children(style, available_width),
Ul => self.layout_list_items(style, available_width, false),
Ol => self.layout_list_items(style, available_width, true),
Li | Tr | Td => panic!("{:?} tag cannot be directly laid out", self.kind),
_ => unimplemented!(),
}
}
pub fn layout_text_children(&self, style: &Stylesheet, available_width: usize) -> Vec<String> {
pub fn layout_list_items(
&self,
style: &Stylesheet,
available_width: usize,
ordered: bool,
) -> Vec<String> {
let indent = style.list_indent;
let mut lines = Vec::new();
let mut index = 1;
let spacer: String = std::iter::repeat(" ").take(indent).collect();
let mut prefix = format!("{:>width$} ", style.ul_prefix, width = indent - 2);
let available_width = if available_width > indent {
available_width - indent
} else {
0
};
for child in self.children.iter() {
if ordered {
prefix = format!("{:>width$}. ", index, width = indent - 2);
}
let options = textwrap::Options::new(available_width)
.initial_indent(&prefix)
.subsequent_indent(&spacer);
match child {
BlockNode::Text(tag) => {
index += 1;
let mut li = tag.layout(style, options);
lines.append(&mut li);
}
BlockNode::Block(tag) => {
let li = match tag.kind {
BlockTagKind::Ol => tag.layout_list_items(style, available_width, true),
BlockTagKind::Ul => tag.layout_list_items(style, available_width, false),
BlockTagKind::Li => {
index += 1;
let mut li = tag.layout_text_children(style, options);
lines.append(&mut li);
continue;
}
_ => panic!("Unexpected {:?} in {:?}", tag.kind, self.kind),
};
lines.extend(li.into_iter().map(|line| format!("{}{}", spacer, line)));
}
BlockNode::Leaf(_) => panic!("Unexpected leaf tag in {:?}", self.kind),
}
}
lines
}
pub fn layout_text_children<'a>(
&self,
style: &Stylesheet,
options: impl Into<textwrap::Options<'a>>,
) -> Vec<String> {
let styled = self.style_text_children(style);
textwrap::wrap(&styled, available_width)
textwrap::wrap(&styled, options)
.into_iter()
.map(|s| s.to_string())
.collect()

View File

@ -29,7 +29,7 @@ impl Default for Stylesheet {
italic: Style::new().italic(),
strikethrough: Style::new().strikethrough(),
bullet: Black.into(),
ul_prefix: "* ".to_string(),
ul_prefix: "*".to_string(),
list_indent: 4,
}
}