tui_markup/generator/tag.rs
1use crate::{
2 generator::Generator,
3 parser::{Item, ItemC},
4};
5
6/// Tag of a [Element][crate::parser::Item::Element] after tag conversion stage.
7///
8/// Fg/Bg/Modifier variant is so-called builtin tag, Custom variant contains custom tag type.
9#[derive(Debug, Clone)]
10pub enum Tag<'a, C: TagConvertor<'a> + ?Sized> {
11 /// Tag for change foreground color.
12 Fg(C::Color),
13 /// Tag for change background color.
14 Bg(C::Color),
15 /// Tag for use style modifier.
16 Modifier(C::Modifier),
17 /// A custom tag.
18 Custom(C::Custom),
19}
20
21/// Tag type for a generator G.
22pub type TagG<'a, G> = Tag<'a, <G as Generator<'a>>::Convertor>;
23
24/// Trait for convert a raw tag string to [`Tag`] type.
25///
26/// Each generator has it own tag convertor, because different backend(show the final output)
27/// supports different kind of tags.
28///
29/// This Trait has three assoc type:
30///
31/// - Color: for foreground or background color
32/// - Modifier: for style modifier(like bold, italic, etc.)
33/// - Custom: for custom tag
34///
35/// The Generator with this convertor `C` will received a series of
36/// [`Item`]<[`Tag`]<C>>, and convert it into final output.
37pub trait TagConvertor<'a> {
38 /// Color type for foreground and background typed tag.
39 type Color;
40 /// Modifier type for modifier typed tag.
41 type Modifier;
42 /// Custom tag type. Usually is the final type represent a style, can be converted from Color
43 /// and Modifier.
44 type Custom;
45
46 /// Parse string to color type.
47 fn parse_color(&mut self, s: &str) -> Option<Self::Color>;
48
49 /// Parse string to modifier type.
50 fn parse_modifier(&mut self, s: &str) -> Option<Self::Modifier>;
51
52 /// Parse string to custom type.
53 ///
54 /// Only if this call fails, a convertor try to parse the raw tag string to a built-in tag.
55 /// So the custom tag always have higher priority.
56 fn parse_custom_tag(&mut self, s: &str) -> Option<Self::Custom>;
57
58 /// Parse string to a builtin tag type.
59 fn parse_built_in_tag(&mut self, s: &str) -> Option<Tag<'a, Self>> {
60 let mut ty_value = s.split(':');
61 let mut ty = ty_value.next()?;
62 let value = ty_value.next().unwrap_or_else(|| {
63 let value = ty;
64 ty = "";
65 value
66 });
67
68 if ty_value.next().is_some() {
69 return None;
70 }
71
72 Some(match ty {
73 "fg" => Tag::Fg(self.parse_color(value)?),
74 "bg" => Tag::Bg(self.parse_color(value)?),
75 "mod" => Tag::Modifier(self.parse_modifier(value)?),
76 "" => {
77 if let Some(color) = self.parse_color(value) {
78 Tag::Fg(color)
79 } else if let Some(modifier) = self.parse_modifier(value) {
80 Tag::Modifier(modifier)
81 } else {
82 return None;
83 }
84 }
85 _ => return None,
86 })
87 }
88
89 /// convert the tag string to [Tag] type
90 fn convert_tag(&mut self, s: &'a str) -> Option<Tag<'a, Self>> {
91 self.parse_custom_tag(s)
92 .map(Tag::Custom)
93 .or_else(|| self.parse_built_in_tag(s))
94 }
95
96 /// Convert item with raw tag string to item with [Tag] type.
97 ///
98 /// It will filtered out all tags that fail to parse.
99 fn convert_item(&mut self, item: Item<'a>) -> ItemC<'a, Self> {
100 match item {
101 Item::PlainText(pt) => Item::PlainText(pt),
102 Item::Element(spans, items) => {
103 let tags = spans
104 .into_iter()
105 .filter_map(|span| self.convert_tag(span))
106 .collect();
107
108 let subitems = self.convert_line(items);
109
110 Item::Element(tags, subitems)
111 }
112 }
113 }
114
115 /// Convert a line of items with raw tag string to items with [Tag] type.
116 ///
117 /// It will filtered out all tags that fail to parse.
118 fn convert_line(&mut self, items: Vec<Item<'a>>) -> Vec<ItemC<'a, Self>> {
119 items
120 .into_iter()
121 .map(|item| self.convert_item(item))
122 .collect()
123 }
124
125 /// Convert all item with raw tag string of a ast into items with [Tag] type.
126 ///
127 /// It will filtered out all tags that fail to parse.
128 fn convert_ast(&mut self, ast: Vec<Vec<Item<'a>>>) -> Vec<Vec<ItemC<'a, Self>>> {
129 ast.into_iter()
130 .map(|line| self.convert_line(line))
131 .collect()
132 }
133}