use std::mem;
use crate::style;
use crate::Context;
use crate::Mm;
pub struct Wrapper<'c, 's, I: Iterator<Item = style::StyledStr<'s>>> {
iter: I,
context: &'c Context,
width: Mm,
x: Mm,
buf: Vec<style::StyledCow<'s>>,
}
impl<'c, 's, I: Iterator<Item = style::StyledStr<'s>>> Wrapper<'c, 's, I> {
pub fn new(iter: I, context: &'c Context, width: Mm) -> Wrapper<'c, 's, I> {
Wrapper {
iter,
context,
width,
x: Mm(0.0),
buf: Vec::new(),
}
}
}
impl<'c, 's, I: Iterator<Item = style::StyledStr<'s>>> Iterator for Wrapper<'c, 's, I> {
type Item = (Vec<style::StyledCow<'s>>, usize);
fn next(&mut self) -> Option<(Vec<style::StyledCow<'s>>, usize)> {
while let Some(s) = self.iter.next() {
let mut width = s.width(&self.context.font_cache);
if self.x + width > self.width {
let mut delta = 0;
let s = if let Some((start, end)) = split(self.context, s, self.width - self.x) {
delta = start.s.len() + end.s.len() - s.s.len();
self.buf.push(start);
width = end.width(&self.context.font_cache);
end
} else {
s.into()
};
if width > self.width {
break;
}
let v = std::mem::take(&mut self.buf);
self.buf.push(s);
self.x = width;
return Some((v, delta));
} else {
self.buf.push(s.into());
self.x += width;
}
}
if self.buf.is_empty() {
None
} else {
Some((mem::take(&mut self.buf), 0))
}
}
}
#[cfg(not(feature = "hyphenation"))]
fn split<'s>(
_context: &Context,
_s: style::StyledStr<'s>,
_len: Mm,
) -> Option<(style::StyledCow<'s>, style::StyledCow<'s>)> {
None
}
#[cfg(feature = "hyphenation")]
fn split<'s>(
context: &Context,
s: style::StyledStr<'s>,
width: Mm,
) -> Option<(style::StyledCow<'s>, style::StyledCow<'s>)> {
use hyphenation::{Hyphenator, Iter};
let hyphenator = if let Some(hyphenator) = &context.hyphenator {
hyphenator
} else {
return None;
};
let mark = "-";
let mark_width = s.style.str_width(&context.font_cache, mark);
let hyphenated = hyphenator.hyphenate(s.s);
let segments: Vec<_> = hyphenated.iter().segments().collect();
let idx = segments
.iter()
.scan(Mm(0.0), |acc, t| {
*acc += s.style.str_width(&context.font_cache, t);
Some(*acc)
})
.position(|w| w + mark_width > width)
.unwrap_or_default();
if idx > 0 {
let idx = hyphenated.breaks[idx - 1];
let start = s.s[..idx].to_owned() + mark;
let end = &s.s[idx..];
Some((
style::StyledCow::new(start, s.style),
style::StyledCow::new(end, s.style),
))
} else {
None
}
}
pub struct Words<I: Iterator<Item = style::StyledString>> {
iter: I,
s: Option<style::StyledString>,
}
impl<I: Iterator<Item = style::StyledString>> Words<I> {
pub fn new<IntoIter: IntoIterator<Item = style::StyledString, IntoIter = I>>(
iter: IntoIter,
) -> Words<I> {
Words {
iter: iter.into_iter(),
s: None,
}
}
}
impl<I: Iterator<Item = style::StyledString>> Iterator for Words<I> {
type Item = style::StyledString;
fn next(&mut self) -> Option<style::StyledString> {
if self.s.as_ref().map(|s| s.s.is_empty()).unwrap_or(true) {
self.s = self.iter.next();
}
if let Some(s) = &mut self.s {
let n = s.s.find(' ').map(|i| i + 1).unwrap_or_else(|| s.s.len());
let mut tmp = s.s.split_off(n);
mem::swap(&mut tmp, &mut s.s);
Some(style::StyledString::new(tmp, s.style))
} else {
None
}
}
}