#[allow(unused_imports)]
use {
crate::{
minimad::*,
*,
},
unicode_width::UnicodeWidthStr,
};
fn follow_up_composite<'s>(fc: &FmtComposite<'s>, skin: &MadSkin) -> FmtComposite<'s> {
let kind = match fc.kind {
CompositeKind::ListItem(l) => CompositeKind::ListItemFollowUp(l),
CompositeKind::OrderedListItem { level, index } => CompositeKind::OrderedListItemFollowUp { level, index },
k => k,
};
let visible_length = match kind {
CompositeKind::ListItemFollowUp(l)
if skin.list_items_indentation_mode == ListItemsIndentationMode::Block =>
{
2 + l as usize
}
CompositeKind::OrderedListItemFollowUp { level, index }
if skin.list_items_indentation_mode == ListItemsIndentationMode::Block =>
{
ordered_item_indent(level, index)
}
CompositeKind::Quote => 2,
_ => 0,
};
FmtComposite {
kind,
compounds: Vec::new(),
visible_length,
spacing: fc.spacing,
}
}
#[must_use]
pub fn composite_kind_widths(
composite_kind: CompositeKind,
skin: &MadSkin,
) -> (usize, usize) {
match composite_kind {
CompositeKind::Paragraph => (0, 0),
CompositeKind::Header(_) => (0, 0),
CompositeKind::ListItem(depth) => {
let indent = 2 + depth as usize;
match skin.list_items_indentation_mode {
ListItemsIndentationMode::FirstLineOnly => (indent, 0),
ListItemsIndentationMode::Block => (indent, indent),
}
}
CompositeKind::ListItemFollowUp(depth) => {
let indent = 2 + depth as usize;
match skin.list_items_indentation_mode {
ListItemsIndentationMode::FirstLineOnly => (0, 0),
ListItemsIndentationMode::Block => (indent, indent),
}
}
CompositeKind::OrderedListItem { level, index } => {
let indent = ordered_item_indent(level, index);
match skin.list_items_indentation_mode {
ListItemsIndentationMode::FirstLineOnly => (indent, 0),
ListItemsIndentationMode::Block => (indent, indent),
}
}
CompositeKind::OrderedListItemFollowUp { level, index } => {
let indent = ordered_item_indent(level, index);
match skin.list_items_indentation_mode {
ListItemsIndentationMode::FirstLineOnly => (indent, 0),
ListItemsIndentationMode::Block => (indent, indent),
}
}
CompositeKind::Code => (0, 0),
CompositeKind::Quote => (2, 2),
}
}
pub fn hard_wrap_composite<'s, 'c>(
src_composite: &'c FmtComposite<'s>,
width: usize,
skin: &MadSkin,
) -> Result<Vec<FmtComposite<'s>>, InsufficientWidthError> {
if width < 3 {
return Err(InsufficientWidthError {
available_width: width,
});
}
debug_assert!(src_composite.visible_length > width); let mut composites: Vec<FmtComposite<'s>> = Vec::new();
let (first_width, other_widths) = composite_kind_widths(src_composite.kind, skin);
let mut dst_composite = FmtComposite {
kind: src_composite.kind,
compounds: Vec::new(),
visible_length: first_width,
spacing: src_composite.spacing,
};
let compounds = &src_composite.compounds;
if (
compounds.len() == 2
&& compounds[0].src.width() + first_width <= width
&& compounds[1].src.width() + other_widths <= width
) || (
compounds.len() == 3
&& compounds[0].src.width() + first_width <= width
&& compounds[2].src.width() + other_widths <= width
&& compounds[1].src.chars().all(char::is_whitespace)
) {
dst_composite.add_compound(compounds[0].clone());
let mut new_dst_composite = follow_up_composite(&dst_composite, skin);
composites.push(dst_composite);
new_dst_composite.add_compound(compounds[compounds.len() - 1].clone());
composites.push(new_dst_composite);
return Ok(composites);
}
let mut tokens = tokenize(&src_composite.compounds, width - first_width);
for token in tokens.drain(..) {
if dst_composite.visible_length + token.width > width {
if !token.blank {
let mut repl_composite = follow_up_composite(&dst_composite, skin);
std::mem::swap(&mut dst_composite, &mut repl_composite);
composites.push(repl_composite);
dst_composite.add_compound(token.to_compound());
}
} else {
dst_composite.add_compound(token.to_compound());
}
}
composites.push(dst_composite);
Ok(composites)
}
pub fn hard_wrap_lines<'s>(
src_lines: Vec<FmtLine<'s>>,
width: usize,
skin: &MadSkin,
) -> Result<Vec<FmtLine<'s>>, InsufficientWidthError> {
let mut src_lines = src_lines;
let mut lines = Vec::new();
for src_line in src_lines.drain(..) {
if let FmtLine::Normal(fc) = src_line {
let (left_margin, right_margin) = skin.line_style(fc.kind).margins_in(Some(width));
if fc.visible_length + left_margin + right_margin <= width {
lines.push(FmtLine::Normal(fc));
} else {
for fc in hard_wrap_composite(&fc, width - left_margin - right_margin, skin)? {
lines.push(FmtLine::Normal(fc));
}
}
} else {
lines.push(src_line);
}
}
Ok(lines)
}