use super::block::TextSpan;
use super::wrap::WrapPolicy;
pub type SpanLine = Vec<TextSpan>;
pub fn wrap(line: &[TextSpan], width: u16, policy: &dyn WrapPolicy) -> Vec<SpanLine> {
let mut text = String::new();
let bounds = line
.iter()
.map(|span| {
let start = text.len();
text.push_str(&span.content);
(start..text.len(), span)
})
.collect::<Vec<_>>();
policy
.wrap(&text, width)
.into_iter()
.map(|visual| {
bounds
.iter()
.filter_map(|(range, span)| {
let start = range.start.max(visual.range.start);
let end = range.end.min(visual.range.end);
(start < end).then(|| span.with_content(&text[start..end]))
})
.collect()
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ui::controller::settings::theme::groups::HLGroup;
use crate::ui::wrap::WordWrap;
fn line() -> SpanLine {
vec![
TextSpan::new("hello ", HLGroup::Keyword),
TextSpan::new("world", HLGroup::Variable),
]
}
#[test]
fn wrapping_divides_a_straddling_span_and_keeps_its_group() {
let rows = wrap(&line(), 8, &WordWrap);
assert_eq!(rows.len(), 2);
assert_eq!(rows[0][0].content, "hello");
assert_eq!(rows[0][0].kind, HLGroup::Keyword);
assert_eq!(rows[1][0].content, "world");
assert_eq!(rows[1][0].kind, HLGroup::Variable);
}
#[test]
fn a_row_narrower_than_a_span_splits_it_without_losing_its_group() {
let rows = wrap(
&[TextSpan::new("abcdefgh", HLGroup::Variable)],
4,
&WordWrap,
);
assert_eq!(rows.len(), 2);
assert_eq!(rows[0][0].content, "abcd");
assert_eq!(rows[1][0].content, "efgh");
assert!(rows.iter().all(|row| row[0].kind == HLGroup::Variable));
}
}