1 | //! This module contains [`RawStyle`] structure, which is analogues to [`Style`] but not generic, |
2 | //! so sometimes it can be used more conviently. |
3 | |
4 | use std::collections::HashMap; |
5 | |
6 | use crate::{ |
7 | grid::{color::AnsiColor, config, config::Borders, config::ColoredConfig, records::Records}, |
8 | settings::{Color, TableOption}, |
9 | }; |
10 | |
11 | use super::{Border, HorizontalLine, Line, Style, VerticalLine}; |
12 | |
13 | /// A raw style data, which can be produced safely from [`Style`]. |
14 | /// |
15 | /// It can be useful in order to not have a generics and be able to use it as a variable more conveniently. |
16 | #[derive (Default, Debug, Clone)] |
17 | pub struct RawStyle { |
18 | borders: Borders<char>, |
19 | colors: Borders<AnsiColor<'static>>, |
20 | horizontals: HashMap<usize, Line>, |
21 | verticals: HashMap<usize, Line>, |
22 | } |
23 | |
24 | impl RawStyle { |
25 | /// Set a top border character. |
26 | pub fn set_top(&mut self, s: Option<char>) -> &mut Self { |
27 | self.borders.top = s; |
28 | self |
29 | } |
30 | |
31 | /// Set a top border color. |
32 | pub fn set_color_top(&mut self, color: Color) -> &mut Self { |
33 | self.colors.top = Some(color.into()); |
34 | self |
35 | } |
36 | |
37 | /// Set a bottom border character. |
38 | pub fn set_bottom(&mut self, s: Option<char>) -> &mut Self { |
39 | self.borders.bottom = s; |
40 | self |
41 | } |
42 | |
43 | /// Set a bottom border color. |
44 | pub fn set_color_bottom(&mut self, color: Color) -> &mut Self { |
45 | self.colors.bottom = Some(color.into()); |
46 | self |
47 | } |
48 | |
49 | /// Set a left border character. |
50 | pub fn set_left(&mut self, s: Option<char>) -> &mut Self { |
51 | self.borders.left = s; |
52 | self |
53 | } |
54 | |
55 | /// Set a left border color. |
56 | pub fn set_color_left(&mut self, color: Color) -> &mut Self { |
57 | self.colors.left = Some(color.into()); |
58 | self |
59 | } |
60 | |
61 | /// Set a right border character. |
62 | pub fn set_right(&mut self, s: Option<char>) -> &mut Self { |
63 | self.borders.right = s; |
64 | self |
65 | } |
66 | |
67 | /// Set a right border color. |
68 | pub fn set_color_right(&mut self, color: Color) -> &mut Self { |
69 | self.colors.right = Some(color.into()); |
70 | self |
71 | } |
72 | |
73 | /// Set a top intersection character. |
74 | pub fn set_intersection_top(&mut self, s: Option<char>) -> &mut Self { |
75 | self.borders.top_intersection = s; |
76 | self |
77 | } |
78 | |
79 | /// Set a top intersection color. |
80 | pub fn set_color_intersection_top(&mut self, color: Color) -> &mut Self { |
81 | self.colors.top_intersection = Some(color.into()); |
82 | self |
83 | } |
84 | |
85 | /// Set a bottom intersection character. |
86 | pub fn set_intersection_bottom(&mut self, s: Option<char>) -> &mut Self { |
87 | self.borders.bottom_intersection = s; |
88 | self |
89 | } |
90 | |
91 | /// Set a bottom intersection color. |
92 | pub fn set_color_intersection_bottom(&mut self, color: Color) -> &mut Self { |
93 | self.colors.bottom_intersection = Some(color.into()); |
94 | self |
95 | } |
96 | |
97 | /// Set a left split character. |
98 | pub fn set_intersection_left(&mut self, s: Option<char>) -> &mut Self { |
99 | self.borders.left_intersection = s; |
100 | self |
101 | } |
102 | |
103 | /// Set a bottom intersection color. |
104 | pub fn set_color_intersection_left(&mut self, color: Color) -> &mut Self { |
105 | self.colors.left_intersection = Some(color.into()); |
106 | self |
107 | } |
108 | |
109 | /// Set a right split character. |
110 | pub fn set_intersection_right(&mut self, s: Option<char>) -> &mut Self { |
111 | self.borders.right_intersection = s; |
112 | self |
113 | } |
114 | |
115 | /// Set a bottom intersection color. |
116 | pub fn set_color_intersection_right(&mut self, color: Color) -> &mut Self { |
117 | self.colors.right_intersection = Some(color.into()); |
118 | self |
119 | } |
120 | |
121 | /// Set an internal character. |
122 | pub fn set_intersection(&mut self, s: Option<char>) -> &mut Self { |
123 | self.borders.intersection = s; |
124 | self |
125 | } |
126 | |
127 | /// Set a bottom intersection color. |
128 | pub fn set_color_intersection(&mut self, color: Color) -> &mut Self { |
129 | self.colors.intersection = Some(color.into()); |
130 | self |
131 | } |
132 | |
133 | /// Set a vertical character. |
134 | pub fn set_vertical(&mut self, s: Option<char>) -> &mut Self { |
135 | self.borders.vertical = s; |
136 | self |
137 | } |
138 | |
139 | /// Set a bottom intersection color. |
140 | pub fn set_color_vertical(&mut self, color: Color) -> &mut Self { |
141 | self.colors.vertical = Some(color.into()); |
142 | self |
143 | } |
144 | |
145 | /// Set a horizontal character. |
146 | pub fn set_horizontal(&mut self, s: Option<char>) -> &mut Self { |
147 | self.borders.horizontal = s; |
148 | self |
149 | } |
150 | |
151 | /// Set a bottom intersection color. |
152 | pub fn set_color_horizontal(&mut self, color: Color) -> &mut Self { |
153 | self.colors.horizontal = Some(color.into()); |
154 | self |
155 | } |
156 | |
157 | /// Set a character for a top left corner. |
158 | pub fn set_corner_top_left(&mut self, s: Option<char>) -> &mut Self { |
159 | self.borders.top_left = s; |
160 | self |
161 | } |
162 | /// Set a bottom intersection color. |
163 | pub fn set_color_corner_top_left(&mut self, color: Color) -> &mut Self { |
164 | self.colors.top_left = Some(color.into()); |
165 | self |
166 | } |
167 | |
168 | /// Set a character for a top right corner. |
169 | pub fn set_corner_top_right(&mut self, s: Option<char>) -> &mut Self { |
170 | self.borders.top_right = s; |
171 | self |
172 | } |
173 | |
174 | /// Set a bottom intersection color. |
175 | pub fn set_color_corner_top_right(&mut self, color: Color) -> &mut Self { |
176 | self.colors.top_right = Some(color.into()); |
177 | self |
178 | } |
179 | |
180 | /// Set a character for a bottom left corner. |
181 | pub fn set_corner_bottom_left(&mut self, s: Option<char>) -> &mut Self { |
182 | self.borders.bottom_left = s; |
183 | self |
184 | } |
185 | /// Set a bottom intersection color. |
186 | pub fn set_color_corner_bottom_left(&mut self, color: Color) -> &mut Self { |
187 | self.colors.bottom_left = Some(color.into()); |
188 | self |
189 | } |
190 | |
191 | /// Set a character for a bottom right corner. |
192 | pub fn set_corner_bottom_right(&mut self, s: Option<char>) -> &mut Self { |
193 | self.borders.bottom_right = s; |
194 | self |
195 | } |
196 | /// Set a bottom intersection color. |
197 | pub fn set_color_corner_bottom_right(&mut self, color: Color) -> &mut Self { |
198 | self.colors.bottom_right = Some(color.into()); |
199 | self |
200 | } |
201 | |
202 | /// Set horizontal border lines. |
203 | /// |
204 | /// # Example |
205 | /// |
206 | /// ``` |
207 | /// use std::collections::HashMap; |
208 | /// use tabled::{Table, settings::style::{Style, Line, RawStyle}}; |
209 | /// |
210 | /// let mut style = RawStyle::from(Style::re_structured_text()); |
211 | /// |
212 | /// let mut lines = HashMap::new(); |
213 | /// lines.insert(1, Style::extended().get_horizontal()); |
214 | /// style.set_horizontals(lines); |
215 | /// |
216 | /// let table = Table::new((0..3).map(|i| ("Hello" , i))) |
217 | /// .with(style) |
218 | /// .to_string(); |
219 | /// |
220 | /// assert_eq!( |
221 | /// table, |
222 | /// concat!( |
223 | /// " ======= ===== \n" , |
224 | /// " &str i32 \n" , |
225 | /// "╠═══════╬═════╣ \n" , |
226 | /// " Hello 0 \n" , |
227 | /// " Hello 1 \n" , |
228 | /// " Hello 2 \n" , |
229 | /// " ======= ===== " , |
230 | /// ), |
231 | /// ) |
232 | /// ``` |
233 | pub fn set_horizontals(&mut self, lines: HashMap<usize, Line>) -> &mut Self { |
234 | self.horizontals = lines; |
235 | self |
236 | } |
237 | |
238 | /// Insert a horizontal line to a specific row location. |
239 | pub fn insert_horizontal(&mut self, row: usize, line: Line) -> &mut Self { |
240 | let _ = self.horizontals.insert(row, line); |
241 | self |
242 | } |
243 | |
244 | /// Insert a horizontal line to a specific row location. |
245 | pub fn get_horizontal(&self, row: usize) -> Option<Line> { |
246 | self.horizontals.get(&row).cloned() |
247 | } |
248 | |
249 | /// Set vertical border lines. |
250 | /// |
251 | /// # Example |
252 | /// |
253 | /// ``` |
254 | /// use std::collections::HashMap; |
255 | /// use tabled::{Table, settings::style::{Style, Line, RawStyle}}; |
256 | /// |
257 | /// let mut style = RawStyle::from(Style::re_structured_text()); |
258 | /// |
259 | /// let mut lines = HashMap::new(); |
260 | /// lines.insert(1, Style::extended().get_horizontal()); |
261 | /// style.set_verticals(lines); |
262 | /// |
263 | /// let table = Table::new((0..3).map(|i| ("Hello" , i))) |
264 | /// .with(style) |
265 | /// .to_string(); |
266 | /// |
267 | /// assert_eq!( |
268 | /// table, |
269 | /// concat!( |
270 | /// "=======╠===== \n" , |
271 | /// " &str ═ i32 \n" , |
272 | /// "======= ===== \n" , |
273 | /// " Hello ═ 0 \n" , |
274 | /// " Hello ═ 1 \n" , |
275 | /// " Hello ═ 2 \n" , |
276 | /// "=======╣=====" , |
277 | /// ), |
278 | /// ) |
279 | /// ``` |
280 | pub fn set_verticals(&mut self, lines: HashMap<usize, Line>) -> &mut Self { |
281 | self.verticals = lines; |
282 | self |
283 | } |
284 | |
285 | /// Insert a vertical line into specific column location. |
286 | pub fn insert_vertical(&mut self, column: usize, line: Line) -> &mut Self { |
287 | let _ = self.verticals.insert(column, line); |
288 | self |
289 | } |
290 | |
291 | /// Get a left char. |
292 | pub fn get_left(&self) -> Option<char> { |
293 | self.borders.left |
294 | } |
295 | |
296 | /// Get a left intersection char. |
297 | pub fn get_left_intersection(&self) -> Option<char> { |
298 | self.borders.left_intersection |
299 | } |
300 | |
301 | /// Get a right char. |
302 | pub fn get_right(&self) -> Option<char> { |
303 | self.borders.right |
304 | } |
305 | |
306 | /// Get a right intersection char. |
307 | pub fn get_right_intersection(&self) -> Option<char> { |
308 | self.borders.right_intersection |
309 | } |
310 | |
311 | /// Get a top char. |
312 | pub fn get_top(&self) -> Option<char> { |
313 | self.borders.top |
314 | } |
315 | |
316 | /// Get a top left char. |
317 | pub fn get_top_left(&self) -> Option<char> { |
318 | self.borders.top_left |
319 | } |
320 | |
321 | /// Get a top right char. |
322 | pub fn get_top_right(&self) -> Option<char> { |
323 | self.borders.top_right |
324 | } |
325 | |
326 | /// Get a top intersection char. |
327 | pub fn get_top_intersection(&self) -> Option<char> { |
328 | self.borders.top_intersection |
329 | } |
330 | |
331 | /// Get a bottom intersection char. |
332 | pub fn get_bottom(&self) -> Option<char> { |
333 | self.borders.bottom |
334 | } |
335 | |
336 | /// Get a bottom intersection char. |
337 | pub fn get_bottom_left(&self) -> Option<char> { |
338 | self.borders.bottom_left |
339 | } |
340 | |
341 | /// Get a bottom intersection char. |
342 | pub fn get_bottom_right(&self) -> Option<char> { |
343 | self.borders.bottom_right |
344 | } |
345 | |
346 | /// Get a bottom intersection char. |
347 | pub fn get_bottom_intersection(&self) -> Option<char> { |
348 | self.borders.bottom_intersection |
349 | } |
350 | |
351 | /// Returns an outer border of the style. |
352 | pub fn get_frame(&self) -> Border { |
353 | Border::from(crate::grid::config::Border { |
354 | top: self.borders.top, |
355 | bottom: self.borders.bottom, |
356 | left: self.borders.left, |
357 | right: self.borders.right, |
358 | left_top_corner: self.borders.top_left, |
359 | right_top_corner: self.borders.top_right, |
360 | left_bottom_corner: self.borders.bottom_left, |
361 | right_bottom_corner: self.borders.bottom_right, |
362 | }) |
363 | } |
364 | |
365 | /// Returns an general borders configuration of the style. |
366 | pub fn get_borders(&self) -> Borders<char> { |
367 | self.borders |
368 | } |
369 | } |
370 | |
371 | impl From<Borders<char>> for RawStyle { |
372 | fn from(borders: Borders<char>) -> Self { |
373 | Self { |
374 | borders, |
375 | horizontals: HashMap::new(), |
376 | verticals: HashMap::new(), |
377 | colors: Borders::default(), |
378 | } |
379 | } |
380 | } |
381 | |
382 | impl<R, D> TableOption<R, D, ColoredConfig> for RawStyle |
383 | where |
384 | R: Records, |
385 | { |
386 | fn change(self, records: &mut R, cfg: &mut ColoredConfig, dimension: &mut D) { |
387 | (&self).change(records, cfg, dimension) |
388 | } |
389 | } |
390 | |
391 | impl<R, D> TableOption<R, D, ColoredConfig> for &RawStyle { |
392 | fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { |
393 | cfg.clear_theme(); |
394 | |
395 | cfg.set_borders(self.borders); |
396 | |
397 | for (&row: usize, line: &Line) in &self.horizontals { |
398 | cfg.insert_horizontal_line(line:row, val:config::HorizontalLine::from(*line)); |
399 | } |
400 | |
401 | for (&col: usize, line: &Line) in &self.verticals { |
402 | cfg.insert_vertical_line(line:col, val:config::VerticalLine::from(*line)); |
403 | } |
404 | |
405 | if !self.colors.is_empty() { |
406 | cfg.set_borders_color(self.colors.clone()); |
407 | } |
408 | } |
409 | } |
410 | |
411 | impl<T, B, L, R, H, V, HLines, VLines> From<Style<T, B, L, R, H, V, HLines, VLines>> for RawStyle |
412 | where |
413 | HLines: IntoIterator<Item = HorizontalLine> + Clone, |
414 | VLines: IntoIterator<Item = VerticalLine> + Clone, |
415 | { |
416 | fn from(style: Style<T, B, L, R, H, V, HLines, VLines>) -> Self { |
417 | let horizontals: HashMap = styleMap …> |
418 | .get_horizontals() |
419 | .clone() |
420 | .into_iter() |
421 | .map(|hr| (hr.index, hr.line)) |
422 | .collect(); |
423 | |
424 | let verticals: HashMap = styleMap …> |
425 | .get_verticals() |
426 | .clone() |
427 | .into_iter() |
428 | .map(|hr| (hr.index, hr.line)) |
429 | .collect(); |
430 | |
431 | Self { |
432 | borders: *style.get_borders(), |
433 | horizontals, |
434 | verticals, |
435 | colors: Borders::default(), |
436 | } |
437 | } |
438 | } |
439 | |