1mod content;
2mod rendering;
3mod style;
4
5use content::{KeyValueLine, Line, TextLine};
6use rendering::BorderPainter;
7pub use style::{Color, HeaderLevel, Style};
8
9pub struct Banner<'a> {
10 pub width: u8,
11 pub auto_widen: bool,
12 style: &'a Style,
13 lines: Vec<Box<dyn Line + 'a>>,
14}
15
16impl<'a> Banner<'a> {
17 pub fn new(style: &'a Style) -> Banner<'a> {
19 return Banner {
20 width: 50,
21 auto_widen: true,
22 style: style,
23 lines: Vec::new(),
24 };
25 }
26
27 pub fn add_header<'b>(&'b mut self, text: &'a str, level: HeaderLevel) {
35 let line = TextLine::new(text, &self.style.header_style(&level));
36
37 let line_width = line.width();
39 if self.auto_widen && line_width > self.width {
40 self.width = line_width
41 }
42
43 self.lines.push(Box::new(line));
44 }
45
46 pub fn add_text<'b>(&'b mut self, text: &'a str) {
53 let line = TextLine::new(text, &self.style.text);
54
55 let line_width = line.width();
57 if self.auto_widen && line_width > self.width {
58 self.width = line_width
59 }
60
61 self.lines.push(Box::new(line));
62 }
63
64 pub fn add_key_value<'b>(&'b mut self, key: &'a str, value: &'a str) {
72 let line = KeyValueLine::new(key, value, &self.style.text);
73
74 let line_width = line.width();
76 if self.auto_widen && line_width > self.width {
77 self.width = line_width
78 }
79
80 self.lines.push(Box::new(line));
81 }
82
83 pub fn assemble(self: &Banner<'a>) -> String {
89 let border_painter: BorderPainter =
90 BorderPainter::new(&self.style.border, self.style.no_color_codes, self.width);
91
92 let mut result: String;
93 result = format!("{}\r\n", border_painter.top());
94 for line in self.lines.iter() {
95 let line_text = &(*line).fmt(self.style.no_color_codes);
96 let line_width = (*line).width();
97 result.push_str(&border_painter.left());
99 result.push_str(&format!("{}", line_text)[..]);
101 result.push_str(&format!(
103 "{}",
104 (line_width as usize..self.width as usize)
105 .map(|_| " ")
106 .collect::<String>()
107 ));
108 result.push_str(&border_painter.right());
110 result.push_str("\r\n");
111 }
112 result.push_str(&format!("{}\r\n", border_painter.bottom())[..]);
113
114 result
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::style::Color;
121 use super::*;
122
123 #[test]
127 fn test_assemble_empty_no_color_codes() {
128 let mut style: Style = Style::new();
130 style.no_color_codes = true;
131
132 let mut banner: Banner = Banner::new(&style);
133 banner.width = 4;
134 assert_eq!("┌────┐\r\n└────┘\r\n", banner.assemble());
135 }
136
137 #[test]
139 fn test_assemble_right_padding() {
140 let mut style: Style = Style::new();
142 style.no_color_codes = true;
143
144 let mut banner: Banner = Banner::new(&style);
145 banner.width = 10;
146 banner.add_text("Test");
147
148 assert_eq!("┌──────────┐\r\n│Test │\r\n└──────────┘\r\n", banner.assemble());
149 }
150
151 #[test]
153 fn test_assemble_auto_width() {
154 let mut style: Style = Style::new();
156 style.no_color_codes = true;
157
158 let mut banner: Banner = Banner::new(&style);
159 banner.width = 2; banner.add_text("Test"); assert_eq!("┌────┐\r\n│Test│\r\n└────┘\r\n", banner.assemble());
163 }
164
165 #[test]
166 fn test_assemble_banner_no_color_codes() {
167 let mut style: Style = Style::new();
169 style.no_color_codes = true;
170
171 let mut banner: Banner = Banner::new(&style);
172 banner.width = 12;
173 banner.add_header("Header h1", HeaderLevel::H1);
174 banner.add_header("Header h2", HeaderLevel::H2);
175 banner.add_header("Header h3", HeaderLevel::H3);
176 banner.add_text("Text");
177 banner.add_key_value("Key", "Val");
178
179 let expected = "┌────────────┐\r\n│Header h1 │\r\n│Header h2 │\r\n│Header h3 │\r\n│Text │\r\n│Key: Val │\r\n└────────────┘\r\n";
180 assert_eq!(expected, banner.assemble());
181 }
182
183 #[test]
187 fn test_assemble_empty() {
188 let mut style: Style = Style::new();
190 style.border.color = Color::White;
191
192 let mut banner: Banner = Banner::new(&style);
194 banner.width = 4;
195
196 let expected = "\u{1b}[37m┌────┐\u{1b}[0m\r\n\u{1b}[37m└────┘\u{1b}[0m\r\n";
197 assert_eq!(expected, banner.assemble());
198 }
199
200 #[test]
202 fn test_assemble_simple() {
203 let mut style: Style = Style::new();
205 style.no_color_codes = true;
206
207 let mut banner: Banner = Banner::new(&style);
209 banner.width = 16;
210 banner.add_text("Hello!");
211
212 let expected = "┌────────────────┐\r\n│Hello! │\r\n└────────────────┘\r\n";
213 assert_eq!(expected, banner.assemble());
214 }
215
216 #[test]
218 fn test_assemble_simple_colored() {
219 let mut style: Style = Style::new();
221 style.border.color = Color::White;
222 style.text.content_color = Color::Red;
223
224 let mut banner: Banner = Banner::new(&style);
226 banner.width = 16;
227
228 banner.add_text("Hello, ");
230 banner.add_text("World!");
231
232 let expected = "\u{1b}[37m┌────────────────┐\u{1b}[0m\r\n\u{1b}[37m│\u{1b}[0m\u{1b}[31mHello, \u{1b}[0m \u{1b}[37m│\u{1b}[0m\r\n\u{1b}[37m│\u{1b}[0m\u{1b}[31mWorld!\u{1b}[0m \u{1b}[37m│\u{1b}[0m\r\n\u{1b}[37m└────────────────┘\u{1b}[0m\r\n";
233 assert_eq!(expected, banner.assemble());
234 }
235}