1//! This module contains [`RawStyle`] structure, which is analogues to [`Style`] but not generic,
2//! so sometimes it can be used more conviently.
3
4use std::collections::HashMap;
5
6use crate::{
7 grid::{color::AnsiColor, config, config::Borders, config::ColoredConfig, records::Records},
8 settings::{Color, TableOption},
9};
10
11use 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)]
17pub struct RawStyle {
18 borders: Borders<char>,
19 colors: Borders<AnsiColor<'static>>,
20 horizontals: HashMap<usize, Line>,
21 verticals: HashMap<usize, Line>,
22}
23
24impl 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
371impl 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
382impl<R, D> TableOption<R, D, ColoredConfig> for RawStyle
383where
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
391impl<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
411impl<T, B, L, R, H, V, HLines, VLines> From<Style<T, B, L, R, H, V, HLines, VLines>> for RawStyle
412where
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