tui_markup/generator/helper/
flatten.rs1use crate::{
2 generator::{Tag, TagConvertor},
3 parser::{Item, ItemC},
4};
5
6use super::unescape;
7
8pub trait FlattenableStyle: Default + Clone {
10 #[must_use]
12 fn patch(self, other: Self) -> Self;
13}
14
15pub trait FlattenableSpan<'a, S: FlattenableStyle> {
17 fn with_style(s: &'a str, style: Option<S>) -> Self;
21}
22
23#[allow(clippy::needless_pass_by_value)] fn plain_text<'a, R, S>(escaped: &'a str, style: Option<S>) -> Vec<R>
25where
26 R: FlattenableSpan<'a, S>,
27 S: FlattenableStyle,
28{
29 unescape(escaped).map(|s| R::with_style(s, style.clone())).collect()
30}
31
32fn element<'a, C, R, S>(tags: Vec<Tag<'a, C>>, children: Vec<ItemC<'a, C>>, style: Option<S>) -> Vec<R>
33where
34 C: TagConvertor<'a>,
35 R: FlattenableSpan<'a, S>,
36 S: FlattenableStyle + From<Tag<'a, C>>,
37{
38 let style = tags.into_iter().map(S::from).fold(style.unwrap_or_default(), S::patch);
39 items(children, Some(style))
40}
41
42fn item<'a, C, R, S>(item: ItemC<'a, C>, style: Option<S>) -> Vec<R>
43where
44 C: TagConvertor<'a>,
45 R: FlattenableSpan<'a, S>,
46 S: FlattenableStyle + From<Tag<'a, C>>,
47{
48 match item {
49 Item::PlainText(t) => plain_text(t.fragment(), style),
50 Item::Element(tags, children) => element(tags, children, style),
51 }
52}
53
54#[allow(clippy::needless_pass_by_value)] fn items<'a, C, R, S>(items: Vec<ItemC<'a, C>>, style: Option<S>) -> Vec<R>
56where
57 C: TagConvertor<'a>,
58 R: FlattenableSpan<'a, S>,
59 S: FlattenableStyle + From<Tag<'a, C>>,
60{
61 items
62 .into_iter()
63 .flat_map(|x| item(x, style.clone()).into_iter())
64 .collect()
65}
66
67pub fn flatten<'a, C, R, S>(line: Vec<ItemC<'a, C>>) -> Vec<R>
87where
88 C: TagConvertor<'a>,
89 R: FlattenableSpan<'a, S>,
90 S: FlattenableStyle + From<Tag<'a, C>>,
91{
92 items(line, None)
93}