1//! This module contains a compile time style builder [`Style`].
2
3use core::marker::PhantomData;
4
5use crate::{
6 grid::config::{Border as GridBorder, Borders, CompactConfig, CompactMultilineConfig},
7 settings::{
8 style::{HorizontalLine, VerticalLine},
9 Border, TableOption,
10 },
11};
12
13#[cfg(feature = "std")]
14use crate::grid::config::ColoredConfig;
15
16/// Style is represents a theme of a [`Table`].
17///
18/// ```text
19/// corner top left top intersection corner top right
20/// . | .
21/// . V .
22/// ╭───┬───┬───┬───┬───┬───┬────┬────┬────╮
23/// │ i │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
24/// ├───┼───┼───┼───┼───┼───┼────┼────┼────┤ <- this horizontal line is custom 'horizontals'
25/// │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ other lines horizontal lines are not set they called 'horizontal'
26/// │ 1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
27/// │ 2 │ 0 │ 2 │ 4 │ 6 │ 8 │ 10 │ 12 │ 14 │
28/// ╰───┴───┴───┴───┴───┴───┴────┴────┴────╯
29/// . ^ ^ .
30/// . | | .
31/// corner bottom left | bottom intersection corner bottom right
32/// |
33/// |
34/// all this vertical lines are called 'vertical'
35/// ```
36///
37///
38/// ```text
39/// ┌───┬───┬───┬───┬───┐
40/// │ 0 │ 1 │ 2 │ 3 │ 4 │
41/// intersection left ->├───X───X───X───X───┤ <- all this horizontal lines are called 'horizontal'
42/// │ 1 │ 2 │ 3 │ 4 │ 5 │
43/// ├───X───X───X───X───┤ <- intersection right
44/// │ 2 │ 3 │ 4 │ 5 │ 6 │
45/// └───┴───┴───┴───┴───┘
46///
47/// All 'X' positions are called 'intersection'.
48/// It's a place where 'vertical' and 'horizontal' lines intersect.
49/// ```
50///
51/// It tries to limit an controlling a valid state of it.
52/// For example, it won't allow to call method [`Style::corner_top_left`] unless [`Style::left`] and [`Style::top`] is set.
53///
54/// You can turn [`Style`] into [`Theme`] to have a precise control using [`Into`] implementation.
55///
56/// # Example
57///
58#[cfg_attr(feature = "std", doc = "```")]
59#[cfg_attr(not(feature = "std"), doc = "```ignore")]
60/// use tabled::{Table, settings::style::Style};
61///
62/// let data = vec!["Hello", "2021"];
63/// let mut table = Table::new(&data);
64///
65/// let style = Style::ascii().bottom('*').intersection(' ');
66/// table.with(style);
67///
68/// println!("{}", table);
69/// ```
70///
71/// [`Table`]: crate::Table
72/// [`Theme`]: crate::settings::themes::Theme
73/// [`Style::corner_top_left`]: Style::corner_top_left
74/// [`Style::left`]: Style.left
75/// [`Style::top`]: Style.function.top
76#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct Style<T, B, L, R, H, V, const HSIZE: usize, const VSIZE: usize> {
78 borders: Borders<char>,
79 horizontals: HArray<HSIZE>,
80 verticals: VArray<VSIZE>,
81 _top: PhantomData<T>,
82 _bottom: PhantomData<B>,
83 _left: PhantomData<L>,
84 _right: PhantomData<R>,
85 _horizontal: PhantomData<H>,
86 _vertical: PhantomData<V>,
87}
88
89type HLine = crate::grid::config::HorizontalLine<char>;
90type VLine = crate::grid::config::VerticalLine<char>;
91
92type HArray<const N: usize> = [(usize, HLine); N];
93type VArray<const N: usize> = [(usize, VLine); N];
94
95/// A marker struct which is used in [`Style`].
96#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Default, Hash)]
97pub struct On;
98
99impl Style<(), (), (), (), (), (), 0, 0> {
100 /// This style is a style with no styling options on,
101 ///
102 /// ```text
103 /// id destribution link
104 /// 0 Fedora https://getfedora.org/
105 /// 2 OpenSUSE https://www.opensuse.org/
106 /// 3 Endeavouros https://endeavouros.com/
107 /// ```
108 ///
109 /// Note: The cells in the example have 1-left and 1-right indent.
110 ///
111 /// This style can be used as a base style to build a custom one.
112 ///
113 /// ```rust,no_run
114 /// # use tabled::settings::style::Style;
115 /// let style = Style::empty()
116 /// .top('*')
117 /// .bottom('*')
118 /// .vertical('#')
119 /// .intersection_top('*');
120 /// ```
121 pub const fn empty() -> Style<(), (), (), (), (), (), 0, 0> {
122 Style::new(Borders::empty(), [], [])
123 }
124
125 /// This style is analog of `empty` but with a vertical space(' ') line.
126 ///
127 /// ```text
128 /// id destribution link
129 /// 0 Fedora https://getfedora.org/
130 /// 2 OpenSUSE https://www.opensuse.org/
131 /// 3 Endeavouros https://endeavouros.com/
132 /// ```
133 pub const fn blank() -> Style<(), (), (), (), (), On, 0, 0> {
134 Style::new(
135 create_borders(
136 HLine::empty(),
137 HLine::empty(),
138 HLine::empty(),
139 None,
140 None,
141 Some(' '),
142 ),
143 [],
144 [],
145 )
146 }
147
148 /// This is a style which relays only on ASCII charset.
149 ///
150 /// It has horizontal and vertical lines.
151 ///
152 /// ```text
153 /// +----+--------------+---------------------------+
154 /// | id | destribution | link |
155 /// +----+--------------+---------------------------+
156 /// | 0 | Fedora | https://getfedora.org/ |
157 /// +----+--------------+---------------------------+
158 /// | 2 | OpenSUSE | https://www.opensuse.org/ |
159 /// +----+--------------+---------------------------+
160 /// | 3 | Endeavouros | https://endeavouros.com/ |
161 /// +----+--------------+---------------------------+
162 /// ```
163 pub const fn ascii() -> Style<On, On, On, On, On, On, 0, 0> {
164 Style::new(
165 create_borders(
166 HLine::full('-', '+', '+', '+'),
167 HLine::full('-', '+', '+', '+'),
168 HLine::full('-', '+', '+', '+'),
169 Some('|'),
170 Some('|'),
171 Some('|'),
172 ),
173 [],
174 [],
175 )
176 }
177
178 /// `psql` style looks like a table style `PostgreSQL` uses.
179 ///
180 /// It has only 1 horizontal line which splits header.
181 /// And no left and right vertical lines.
182 ///
183 /// ```text
184 /// id | destribution | link
185 /// ----+--------------+---------------------------
186 /// 0 | Fedora | https://getfedora.org/
187 /// 2 | OpenSUSE | https://www.opensuse.org/
188 /// 3 | Endeavouros | https://endeavouros.com/
189 /// ```
190 pub const fn psql() -> Style<(), (), (), (), (), On, 1, 0> {
191 Style::new(
192 create_borders(
193 HLine::empty(),
194 HLine::empty(),
195 HLine::empty(),
196 None,
197 None,
198 Some('|'),
199 ),
200 [(1, HLine::new(Some('-'), Some('+'), None, None))],
201 [],
202 )
203 }
204
205 /// `markdown` style mimics a `Markdown` table style.
206 ///
207 /// ```text
208 /// | id | destribution | link |
209 /// |----|--------------|---------------------------|
210 /// | 0 | Fedora | https://getfedora.org/ |
211 /// | 2 | OpenSUSE | https://www.opensuse.org/ |
212 /// | 3 | Endeavouros | https://endeavouros.com/ |
213 /// ```
214 pub const fn markdown() -> Style<(), (), On, On, (), On, 1, 0> {
215 Style::new(
216 create_borders(
217 HLine::empty(),
218 HLine::empty(),
219 HLine::empty(),
220 Some('|'),
221 Some('|'),
222 Some('|'),
223 ),
224 [(1, HLine::full('-', '|', '|', '|'))],
225 [],
226 )
227 }
228
229 /// This style is analog of [`Style::ascii`] which uses UTF-8 charset.
230 ///
231 /// It has vertical and horizontal split lines.
232 ///
233 /// ```text
234 /// ┌────┬──────────────┬───────────────────────────┐
235 /// │ id │ destribution │ link │
236 /// ├────┼──────────────┼───────────────────────────┤
237 /// │ 0 │ Fedora │ https://getfedora.org/ │
238 /// ├────┼──────────────┼───────────────────────────┤
239 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
240 /// ├────┼──────────────┼───────────────────────────┤
241 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
242 /// └────┴──────────────┴───────────────────────────┘
243 /// ```
244 pub const fn modern() -> Style<On, On, On, On, On, On, 0, 0> {
245 Style::new(
246 create_borders(
247 HLine::full('─', '┬', '┌', '┐'),
248 HLine::full('─', '┴', '└', '┘'),
249 HLine::full('─', '┼', '├', '┤'),
250 Some('│'),
251 Some('│'),
252 Some('│'),
253 ),
254 [],
255 [],
256 )
257 }
258
259 /// This style looks like a [`Style::modern`] but without horozizontal lines except a header.
260 ///
261 /// Beware: It uses UTF-8 characters.
262 ///
263 /// ```text
264 /// ┌────┬──────────────┬───────────────────────────┐
265 /// │ id │ destribution │ link │
266 /// ├────┼──────────────┼───────────────────────────┤
267 /// │ 0 │ Fedora │ https://getfedora.org/ │
268 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
269 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
270 /// └────┴──────────────┴───────────────────────────┘
271 /// ```
272 pub const fn sharp() -> Style<On, On, On, On, (), On, 1, 0> {
273 Style::new(
274 create_borders(
275 HLine::full('─', '┬', '┌', '┐'),
276 HLine::full('─', '┴', '└', '┘'),
277 HLine::empty(),
278 Some('│'),
279 Some('│'),
280 Some('│'),
281 ),
282 [(1, HLine::full('─', '┼', '├', '┤'))],
283 [],
284 )
285 }
286
287 /// This style looks like a [`Style::sharp`] but with rounded corners.
288 ///
289 /// Beware: It uses UTF-8 characters.
290 ///
291 /// ```text
292 /// ╭────┬──────────────┬───────────────────────────╮
293 /// │ id │ destribution │ link │
294 /// ├────┼──────────────┼───────────────────────────┤
295 /// │ 0 │ Fedora │ https://getfedora.org/ │
296 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
297 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
298 /// ╰────┴──────────────┴───────────────────────────╯
299 /// ```
300 pub const fn rounded() -> Style<On, On, On, On, (), On, 1, 0> {
301 Style::new(
302 create_borders(
303 HLine::full('─', '┬', '╭', '╮'),
304 HLine::full('─', '┴', '╰', '╯'),
305 HLine::empty(),
306 Some('│'),
307 Some('│'),
308 Some('│'),
309 ),
310 [(1, HLine::full('─', '┼', '├', '┤'))],
311 [],
312 )
313 }
314
315 /// This style looks like a [`Style::rounded`] but with horizontals lines.
316 ///
317 /// Beware: It uses UTF-8 characters.
318 ///
319 /// ```text
320 /// ╭────┬──────────────┬───────────────────────────╮
321 /// │ id │ destribution │ link │
322 /// ├────┼──────────────┼───────────────────────────┤
323 /// │ 0 │ Fedora │ https://getfedora.org/ │
324 /// ├────┼──────────────┼───────────────────────────┤
325 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
326 /// ├────┼──────────────┼───────────────────────────┤
327 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
328 /// ╰────┴──────────────┴───────────────────────────╯
329 /// ```
330 pub const fn modern_rounded() -> Style<On, On, On, On, On, On, 0, 0> {
331 Style::new(
332 create_borders(
333 HLine::full('─', '┬', '╭', '╮'),
334 HLine::full('─', '┴', '╰', '╯'),
335 HLine::full('─', '┼', '├', '┤'),
336 Some('│'),
337 Some('│'),
338 Some('│'),
339 ),
340 [],
341 [],
342 )
343 }
344
345 /// This style uses a chars which resembles '2 lines'.
346 ///
347 /// Beware: It uses UTF8 characters.
348 ///
349 /// ```text
350 /// ╔════╦══════════════╦═══════════════════════════╗
351 /// ║ id ║ destribution ║ link ║
352 /// ╠════╬══════════════╬═══════════════════════════╣
353 /// ║ 0 ║ Fedora ║ https://getfedora.org/ ║
354 /// ╠════╬══════════════╬═══════════════════════════╣
355 /// ║ 2 ║ OpenSUSE ║ https://www.opensuse.org/ ║
356 /// ╠════╬══════════════╬═══════════════════════════╣
357 /// ║ 3 ║ Endeavouros ║ https://endeavouros.com/ ║
358 /// ╚════╩══════════════╩═══════════════════════════╝
359 /// ```
360 pub const fn extended() -> Style<On, On, On, On, On, On, 0, 0> {
361 Style::new(
362 create_borders(
363 HLine::full('═', '╦', '╔', '╗'),
364 HLine::full('═', '╩', '╚', '╝'),
365 HLine::full('═', '╬', '╠', '╣'),
366 Some('║'),
367 Some('║'),
368 Some('║'),
369 ),
370 [],
371 [],
372 )
373 }
374
375 /// This is a style uses only '.' and ':' chars.
376 /// It has a vertical and horizontal split lines.
377 ///
378 /// ```text
379 /// .................................................
380 /// : id : destribution : link :
381 /// :....:..............:...........................:
382 /// : 0 : Fedora : https://getfedora.org/ :
383 /// :....:..............:...........................:
384 /// : 2 : OpenSUSE : https://www.opensuse.org/ :
385 /// :....:..............:...........................:
386 /// : 3 : Endeavouros : https://endeavouros.com/ :
387 /// :....:..............:...........................:
388 /// ```
389 pub const fn dots() -> Style<On, On, On, On, On, On, 0, 0> {
390 Style::new(
391 create_borders(
392 HLine::full('.', '.', '.', '.'),
393 HLine::full('.', ':', ':', ':'),
394 HLine::full('.', ':', ':', ':'),
395 Some(':'),
396 Some(':'),
397 Some(':'),
398 ),
399 [],
400 [],
401 )
402 }
403
404 /// This style is one of table views in `ReStructuredText`.
405 ///
406 /// ```text
407 /// ==== ============== ===========================
408 /// id destribution link
409 /// ==== ============== ===========================
410 /// 0 Fedora https://getfedora.org/
411 /// 2 OpenSUSE https://www.opensuse.org/
412 /// 3 Endeavouros https://endeavouros.com/
413 /// ==== ============== ===========================
414 /// ```
415 pub const fn re_structured_text() -> Style<On, On, (), (), (), On, 1, 0> {
416 Style::new(
417 create_borders(
418 HLine::new(Some('='), Some(' '), None, None),
419 HLine::new(Some('='), Some(' '), None, None),
420 HLine::empty(),
421 None,
422 None,
423 Some(' '),
424 ),
425 [(1, HLine::new(Some('='), Some(' '), None, None))],
426 [],
427 )
428 }
429
430 /// This is a theme analog of [`Style::rounded`], but in using ascii charset and
431 /// with no horizontal lines.
432 ///
433 /// ```text
434 /// .-----------------------------------------------.
435 /// | id | destribution | link |
436 /// | 0 | Fedora | https://getfedora.org/ |
437 /// | 2 | OpenSUSE | https://www.opensuse.org/ |
438 /// | 3 | Endeavouros | https://endeavouros.com/ |
439 /// '-----------------------------------------------'
440 /// ```
441 pub const fn ascii_rounded() -> Style<On, On, On, On, (), On, 0, 0> {
442 Style::new(
443 create_borders(
444 HLine::full('-', '-', '.', '.'),
445 HLine::full('-', '-', '\'', '\''),
446 HLine::empty(),
447 Some('|'),
448 Some('|'),
449 Some('|'),
450 ),
451 [],
452 [],
453 )
454 }
455}
456
457impl<T, B, L, R, H, V, const HSIZE: usize, const VSIZE: usize>
458 Style<T, B, L, R, H, V, HSIZE, VSIZE>
459{
460 pub(crate) const fn new(
461 borders: Borders<char>,
462 horizontals: HArray<HSIZE>,
463 verticals: VArray<VSIZE>,
464 ) -> Self {
465 Self {
466 borders,
467 horizontals,
468 verticals,
469 _top: PhantomData,
470 _bottom: PhantomData,
471 _left: PhantomData,
472 _right: PhantomData,
473 _horizontal: PhantomData,
474 _vertical: PhantomData,
475 }
476 }
477
478 pub(crate) const fn get_borders(&self) -> Borders<char> {
479 self.borders
480 }
481
482 #[cfg(feature = "std")]
483 pub(crate) const fn get_horizontals(&self) -> [(usize, HLine); HSIZE] {
484 self.horizontals
485 }
486}
487
488impl<T, B, L, R, H, V, const HN: usize, const VN: usize> Style<T, B, L, R, H, V, HN, VN> {
489 /// Set border horizontal lines.
490 ///
491 /// # Example
492 ///
493 #[cfg_attr(feature = "derive", doc = "```")]
494 #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
495 /// use tabled::{settings::style::{Style, HorizontalLine}, Table};
496 ///
497 /// let data = (0..3).map(|i| ("Hello", i));
498 /// let mut table = Table::new(data);
499 ///
500 /// let style = Style::rounded().horizontals([
501 /// (1, HorizontalLine::filled('#')),
502 /// (2, HorizontalLine::filled('&')),
503 /// (3, HorizontalLine::filled('@')),
504 /// ]);
505 ///
506 /// table.with(style);
507 ///
508 /// assert_eq!(
509 /// table.to_string(),
510 /// concat!(
511 /// "╭───────┬─────╮\n",
512 /// "│ &str │ i32 │\n",
513 /// "###############\n",
514 /// "│ Hello │ 0 │\n",
515 /// "&&&&&&&&&&&&&&&\n",
516 /// "│ Hello │ 1 │\n",
517 /// "@@@@@@@@@@@@@@@\n",
518 /// "│ Hello │ 2 │\n",
519 /// "╰───────┴─────╯",
520 /// )
521 /// )
522 /// ```
523 pub const fn horizontals<const SIZE: usize>(
524 self,
525 list: [(usize, HorizontalLine<L, R, V>); SIZE],
526 ) -> Style<T, B, L, R, H, V, SIZE, VN> {
527 let list = harr_convert(list);
528 Style::new(self.borders, list, self.verticals)
529 }
530
531 /// Set border vertical lines.
532 ///
533 /// # Example
534 ///
535 #[cfg_attr(feature = "derive", doc = "```")]
536 #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
537 /// use tabled::{settings::style::{Style, VerticalLine}, Table};
538 ///
539 /// let data = (0..3).map(|i| ("Hello", "World", i));
540 /// let mut table = Table::new(data);
541 ///
542 /// let style = Style::rounded().verticals([
543 /// (1, VerticalLine::new('#').top(':').bottom('.')),
544 /// (2, VerticalLine::new('&').top(':').bottom('.')),
545 /// ]);
546 /// let table = table.with(style).to_string();
547 ///
548 /// assert_eq!(
549 /// table,
550 /// concat!(
551 /// "╭───────:───────:─────╮\n",
552 /// "│ &str # &str & i32 │\n",
553 /// "├───────┼───────┼─────┤\n",
554 /// "│ Hello # World & 0 │\n",
555 /// "│ Hello # World & 1 │\n",
556 /// "│ Hello # World & 2 │\n",
557 /// "╰───────.───────.─────╯",
558 /// )
559 /// )
560 /// ```
561 pub const fn verticals<const SIZE: usize>(
562 self,
563 list: [(usize, VerticalLine<T, B, H>); SIZE],
564 ) -> Style<T, B, L, R, H, V, HN, SIZE> {
565 let list = varr_convert(list);
566 Style::new(self.borders, self.horizontals, list)
567 }
568
569 /// Removes all horizontal lines set by [`Style::horizontals`]
570 pub const fn remove_horizontals(self) -> Style<T, B, L, R, H, V, 0, VN> {
571 Style::new(self.borders, [], self.verticals)
572 }
573
574 /// Removes all verticals lines set by [`Style::verticals`]
575 pub const fn remove_verticals(self) -> Style<T, B, L, R, H, V, HN, 0> {
576 Style::new(self.borders, self.horizontals, [])
577 }
578
579 /// Sets a top border.
580 ///
581 /// Any corners and intersections which were set will be overridden.
582 pub const fn top(mut self, c: char) -> Style<On, B, L, R, H, V, HN, VN>
583 where
584 T: Copy,
585 B: Copy,
586 H: Copy,
587 {
588 self.borders.top = Some(c);
589
590 if self.borders.has_left() {
591 self.borders.top_left = Some(c);
592 }
593
594 if self.borders.has_right() {
595 self.borders.top_right = Some(c);
596 }
597
598 if self.borders.has_vertical() {
599 self.borders.top_intersection = Some(c);
600 }
601
602 let verticals = varr_set(self.verticals, VLine::new(None, None, Some(c), None));
603
604 Style::new(self.borders, self.horizontals, verticals)
605 }
606
607 /// Sets a bottom border.
608 ///
609 /// Any corners and intersections which were set will be overridden.
610 pub const fn bottom(mut self, c: char) -> Style<T, On, L, R, H, V, HN, VN>
611 where
612 T: Copy,
613 B: Copy,
614 H: Copy,
615 {
616 self.borders.bottom = Some(c);
617
618 if self.borders.has_left() {
619 self.borders.bottom_left = Some(c);
620 }
621
622 if self.borders.has_right() {
623 self.borders.bottom_right = Some(c);
624 }
625
626 if self.borders.has_vertical() {
627 self.borders.bottom_intersection = Some(c);
628 }
629
630 let verticals = varr_set(self.verticals, VLine::new(None, None, None, Some(c)));
631
632 Style::new(self.borders, self.horizontals, verticals)
633 }
634
635 /// Sets a left border.
636 ///
637 /// Any corners and intersections which were set will be overridden.
638 pub const fn left(mut self, c: char) -> Style<T, B, On, R, H, V, HN, VN>
639 where
640 L: Copy,
641 R: Copy,
642 V: Copy,
643 {
644 self.borders.left = Some(c);
645
646 if self.borders.has_top() {
647 self.borders.top_left = Some(c);
648 }
649
650 if self.borders.has_bottom() {
651 self.borders.bottom_left = Some(c);
652 }
653
654 if self.borders.has_horizontal() {
655 self.borders.left_intersection = Some(c);
656 }
657
658 let horizontals = harr_set(self.horizontals, HLine::new(None, None, Some(c), None));
659
660 Style::new(self.borders, horizontals, self.verticals)
661 }
662
663 /// Sets a right border.
664 ///
665 /// Any corners and intersections which were set will be overridden.
666 pub const fn right(mut self, c: char) -> Style<T, B, L, On, H, V, HN, VN>
667 where
668 L: Copy,
669 R: Copy,
670 V: Copy,
671 {
672 self.borders.right = Some(c);
673
674 if self.borders.has_top() {
675 self.borders.top_right = Some(c);
676 }
677
678 if self.borders.has_bottom() {
679 self.borders.bottom_right = Some(c);
680 }
681
682 if self.borders.has_horizontal() {
683 self.borders.right_intersection = Some(c);
684 }
685
686 let horizontals = harr_set(self.horizontals, HLine::new(None, None, None, Some(c)));
687
688 Style::new(self.borders, horizontals, self.verticals)
689 }
690
691 /// Sets a horizontal split line.
692 ///
693 /// Any corners and intersections which were set will be overridden.
694 pub const fn horizontal(mut self, c: char) -> Style<T, B, L, R, On, V, HN, VN>
695 where
696 T: Copy,
697 B: Copy,
698 H: Copy,
699 {
700 self.borders.horizontal = Some(c);
701
702 if self.borders.has_vertical() {
703 self.borders.intersection = Some(c);
704 }
705
706 if self.borders.has_left() {
707 self.borders.left_intersection = Some(c);
708 }
709
710 if self.borders.has_right() {
711 self.borders.right_intersection = Some(c);
712 }
713
714 let verticals = varr_set(self.verticals, VLine::new(None, Some(c), None, None));
715
716 Style::new(self.borders, self.horizontals, verticals)
717 }
718
719 /// Sets a vertical split line.
720 ///
721 /// Any corners and intersections which were set will be overridden.
722 pub const fn vertical(mut self, c: char) -> Style<T, B, L, R, H, On, HN, VN>
723 where
724 L: Copy,
725 R: Copy,
726 V: Copy,
727 {
728 self.borders.vertical = Some(c);
729
730 if self.borders.has_horizontal() {
731 self.borders.intersection = Some(c);
732 }
733
734 if self.borders.has_top() {
735 self.borders.top_intersection = Some(c);
736 }
737
738 if self.borders.has_bottom() {
739 self.borders.bottom_intersection = Some(c);
740 }
741
742 let horizontals = harr_set(self.horizontals, HLine::new(None, Some(c), None, None));
743
744 Style::new(self.borders, horizontals, self.verticals)
745 }
746
747 /// Set a vertical line.
748 /// An equvalent of calling vertical+top_intersection+bottom_intersection+intersion.
749 ///
750 /// Notice, that it will clear everything that is outdated, meaning
751 /// If your style has a top border line and but the given vertical line has not got it then it will be removed.
752 pub const fn line_vertical<Top, Bottom, Intersection>(
753 mut self,
754 line: VerticalLine<Top, Bottom, Intersection>,
755 ) -> Style<Top, Bottom, L, R, Intersection, On, HN, VN>
756 where
757 L: Copy,
758 R: Copy,
759 Top: Copy,
760 Bottom: Copy,
761 Intersection: Copy,
762 {
763 let line = line.into_inner();
764
765 self.borders.vertical = line.main;
766 self.borders.intersection = line.intersection;
767 self.borders.top_intersection = line.top;
768 self.borders.bottom_intersection = line.bottom;
769
770 if line.intersection.is_none() {
771 self.borders.horizontal = None;
772 self.borders.left_intersection = None;
773 self.borders.right_intersection = None;
774 self.borders.intersection = None;
775 } else {
776 if self.borders.has_left() && self.borders.left_intersection.is_none() {
777 self.borders.left_intersection = Some(' ');
778 }
779
780 if self.borders.has_right() && self.borders.right_intersection.is_none() {
781 self.borders.right_intersection = Some(' ');
782 }
783
784 if self.borders.horizontal.is_none() {
785 self.borders.horizontal = Some(' ');
786 }
787 }
788
789 if line.top.is_none() {
790 self.borders.top = None;
791 self.borders.top_left = None;
792 self.borders.top_right = None;
793 self.borders.top_intersection = None;
794 }
795
796 if line.bottom.is_none() {
797 self.borders.bottom = None;
798 self.borders.bottom_left = None;
799 self.borders.bottom_right = None;
800 self.borders.bottom_intersection = None;
801 }
802
803 let horizontals = harr_set(
804 self.horizontals,
805 HLine::new(None, line.intersection, None, None),
806 );
807 let verticals = varr_set(
808 self.verticals,
809 VLine::new(None, line.intersection, line.top, line.bottom),
810 );
811
812 Style::new(self.borders, horizontals, verticals)
813 }
814
815 /// Set a horizontal line.
816 /// An equvalent of calling horizontal+left_intersection+right_intersection+intersion.
817 ///
818 /// Notice, that it will clear everything that is outdated, meaning
819 /// If your style has a left border line and but the given vertical line has not got it then it will be removed.
820 pub const fn line_horizontal<Left, Right, Intersection>(
821 mut self,
822 line: HorizontalLine<Left, Right, Intersection>,
823 ) -> Style<T, B, Left, Right, On, Intersection, HN, VN>
824 where
825 L: Copy,
826 R: Copy,
827 Left: Copy,
828 Right: Copy,
829 Intersection: Copy,
830 {
831 let line = line.into_inner();
832
833 self.borders.horizontal = line.main;
834 self.borders.intersection = line.intersection;
835 self.borders.left_intersection = line.left;
836 self.borders.right_intersection = line.right;
837
838 if line.intersection.is_none() {
839 self.borders.vertical = None;
840 self.borders.top_intersection = None;
841 self.borders.bottom_intersection = None;
842 self.borders.intersection = None;
843 } else {
844 if self.borders.has_top() && self.borders.top_intersection.is_none() {
845 self.borders.top_intersection = Some(' ');
846 }
847
848 if self.borders.has_bottom() && self.borders.bottom_intersection.is_none() {
849 self.borders.bottom_intersection = Some(' ');
850 }
851
852 if self.borders.vertical.is_none() {
853 self.borders.vertical = Some(' ');
854 }
855 }
856
857 if line.left.is_none() {
858 self.borders.left = None;
859 self.borders.top_left = None;
860 self.borders.bottom_left = None;
861 self.borders.left_intersection = None;
862 }
863
864 if line.right.is_none() {
865 self.borders.right = None;
866 self.borders.top_right = None;
867 self.borders.bottom_right = None;
868 self.borders.right_intersection = None;
869 }
870
871 let horizontals = harr_set(
872 self.horizontals,
873 HLine::new(None, line.intersection, line.left, line.right),
874 );
875 let verticals = varr_set(
876 self.verticals,
877 VLine::new(None, line.intersection, None, None),
878 );
879
880 Style::new(self.borders, horizontals, verticals)
881 }
882
883 /// Set a horizontal line.
884 /// An equvalent of calling top+cornet_top_right+cornet_top_left+top_intersection.
885 ///
886 /// Notice, that it will clear everything that is outdated, meaning
887 /// If your style has a left border line and but the given vertical line has not got it then it will be removed.
888 pub const fn line_top<Left, Right, Intersection>(
889 mut self,
890 line: HorizontalLine<Left, Right, Intersection>,
891 ) -> Style<On, B, Left, Right, H, Intersection, HN, VN>
892 where
893 L: Copy,
894 R: Copy,
895 Left: Copy,
896 Right: Copy,
897 Intersection: Copy,
898 {
899 let line = line.into_inner();
900
901 self.borders.top = line.main;
902 self.borders.top_intersection = line.intersection;
903 self.borders.top_left = line.left;
904 self.borders.top_right = line.right;
905
906 if line.intersection.is_none() {
907 self.borders.vertical = None;
908 self.borders.top_intersection = None;
909 self.borders.bottom_intersection = None;
910 self.borders.intersection = None;
911 } else {
912 if self.borders.has_top() && self.borders.top_intersection.is_none() {
913 self.borders.top_intersection = Some(' ');
914 }
915
916 if self.borders.has_bottom() && self.borders.bottom_intersection.is_none() {
917 self.borders.bottom_intersection = Some(' ');
918 }
919
920 if self.borders.vertical.is_none() {
921 self.borders.vertical = Some(' ');
922 }
923 }
924
925 if line.left.is_none() {
926 self.borders.left = None;
927 self.borders.top_left = None;
928 self.borders.bottom_left = None;
929 self.borders.left_intersection = None;
930 }
931
932 if line.right.is_none() {
933 self.borders.right = None;
934 self.borders.top_right = None;
935 self.borders.bottom_right = None;
936 self.borders.right_intersection = None;
937 }
938
939 let horizontals = harr_set(
940 self.horizontals,
941 HLine::new(None, line.intersection, line.left, line.right),
942 );
943 let verticals = varr_set(
944 self.verticals,
945 VLine::new(None, line.intersection, None, None),
946 );
947
948 Style::new(self.borders, horizontals, verticals)
949 }
950
951 /// Set a horizontal line.
952 /// An equvalent of calling bottom+cornet_bottom_right+cornet_bottom_left+bottom_intersection.
953 ///
954 /// Notice, that it will clear everything that is outdated, meaning
955 /// If your style has a left border line and but the given vertical line has not got it then it will be removed.
956 pub const fn line_bottom<Left, Right, Intersection>(
957 mut self,
958 line: HorizontalLine<Left, Right, Intersection>,
959 ) -> Style<T, On, Left, Right, H, Intersection, HN, VN>
960 where
961 L: Copy,
962 R: Copy,
963 Left: Copy,
964 Right: Copy,
965 Intersection: Copy,
966 {
967 let line = line.into_inner();
968
969 self.borders.bottom = line.main;
970 self.borders.bottom_intersection = line.intersection;
971 self.borders.bottom_left = line.left;
972 self.borders.bottom_right = line.right;
973
974 if line.intersection.is_none() {
975 self.borders.vertical = None;
976 self.borders.top_intersection = None;
977 self.borders.bottom_intersection = None;
978 self.borders.intersection = None;
979 } else {
980 if self.borders.has_top() && self.borders.top_intersection.is_none() {
981 self.borders.top_intersection = Some(' ');
982 }
983
984 if self.borders.has_bottom() && self.borders.bottom_intersection.is_none() {
985 self.borders.bottom_intersection = Some(' ');
986 }
987
988 if self.borders.vertical.is_none() {
989 self.borders.vertical = Some(' ');
990 }
991 }
992
993 if line.left.is_none() {
994 self.borders.left = None;
995 self.borders.top_left = None;
996 self.borders.bottom_left = None;
997 self.borders.left_intersection = None;
998 }
999
1000 if line.right.is_none() {
1001 self.borders.right = None;
1002 self.borders.top_right = None;
1003 self.borders.bottom_right = None;
1004 self.borders.right_intersection = None;
1005 }
1006
1007 let horizontals = harr_set(
1008 self.horizontals,
1009 HLine::new(None, line.intersection, line.left, line.right),
1010 );
1011 let verticals = varr_set(
1012 self.verticals,
1013 VLine::new(None, line.intersection, None, None),
1014 );
1015
1016 Style::new(self.borders, horizontals, verticals)
1017 }
1018
1019 /// Set a vertical line.
1020 /// An equvalent of calling left+corner_top_left+corner_bottom_left+left_intersection.
1021 ///
1022 /// Notice, that it will clear everything that is outdated, meaning
1023 /// If your style has a top border line and but the given vertical line has not got it then it will be removed.
1024 pub const fn line_left<Top, Bottom, Intersection>(
1025 mut self,
1026 line: VerticalLine<Top, Bottom, Intersection>,
1027 ) -> Style<Top, Bottom, On, R, Intersection, V, HN, VN>
1028 where
1029 L: Copy,
1030 R: Copy,
1031 Top: Copy,
1032 Bottom: Copy,
1033 Intersection: Copy,
1034 {
1035 let line = line.into_inner();
1036
1037 self.borders.left = line.main;
1038 self.borders.left_intersection = line.intersection;
1039 self.borders.top_left = line.top;
1040 self.borders.bottom_left = line.bottom;
1041
1042 if line.intersection.is_none() {
1043 self.borders.horizontal = None;
1044 self.borders.left_intersection = None;
1045 self.borders.right_intersection = None;
1046 self.borders.intersection = None;
1047 } else {
1048 if self.borders.has_left() && self.borders.left_intersection.is_none() {
1049 self.borders.left_intersection = Some(' ');
1050 }
1051
1052 if self.borders.has_right() && self.borders.right_intersection.is_none() {
1053 self.borders.right_intersection = Some(' ');
1054 }
1055
1056 if self.borders.horizontal.is_none() {
1057 self.borders.horizontal = Some(' ');
1058 }
1059 }
1060
1061 if line.top.is_none() {
1062 self.borders.top = None;
1063 self.borders.top_left = None;
1064 self.borders.top_right = None;
1065 self.borders.top_intersection = None;
1066 }
1067
1068 if line.bottom.is_none() {
1069 self.borders.bottom = None;
1070 self.borders.bottom_left = None;
1071 self.borders.bottom_right = None;
1072 self.borders.bottom_intersection = None;
1073 }
1074
1075 let horizontals = harr_set(
1076 self.horizontals,
1077 HLine::new(None, line.intersection, None, None),
1078 );
1079 let verticals = varr_set(
1080 self.verticals,
1081 VLine::new(None, line.intersection, line.top, line.bottom),
1082 );
1083
1084 Style::new(self.borders, horizontals, verticals)
1085 }
1086
1087 /// Set a vertical line.
1088 /// An equvalent of calling right+corner_top_right+corner_bottom_right+right_intersection.
1089 ///
1090 /// Notice, that it will clear everything that is outdated, meaning
1091 /// If your style has a top border line and but the given vertical line has not got it then it will be removed.
1092 pub const fn line_right<Top, Bottom, Intersection>(
1093 mut self,
1094 line: VerticalLine<Top, Bottom, Intersection>,
1095 ) -> Style<Top, Bottom, L, On, Intersection, V, HN, VN>
1096 where
1097 L: Copy,
1098 R: Copy,
1099 Top: Copy,
1100 Bottom: Copy,
1101 Intersection: Copy,
1102 {
1103 let line = line.into_inner();
1104
1105 self.borders.right = line.main;
1106 self.borders.right_intersection = line.intersection;
1107 self.borders.top_right = line.top;
1108 self.borders.bottom_right = line.bottom;
1109
1110 if line.intersection.is_none() {
1111 self.borders.horizontal = None;
1112 self.borders.left_intersection = None;
1113 self.borders.right_intersection = None;
1114 self.borders.intersection = None;
1115 } else {
1116 if self.borders.has_left() && self.borders.left_intersection.is_none() {
1117 self.borders.left_intersection = Some(' ');
1118 }
1119
1120 if self.borders.has_right() && self.borders.right_intersection.is_none() {
1121 self.borders.right_intersection = Some(' ');
1122 }
1123
1124 if self.borders.horizontal.is_none() {
1125 self.borders.horizontal = Some(' ');
1126 }
1127 }
1128
1129 if line.top.is_none() {
1130 self.borders.top = None;
1131 self.borders.top_left = None;
1132 self.borders.top_right = None;
1133 self.borders.top_intersection = None;
1134 }
1135
1136 if line.bottom.is_none() {
1137 self.borders.bottom = None;
1138 self.borders.bottom_left = None;
1139 self.borders.bottom_right = None;
1140 self.borders.bottom_intersection = None;
1141 }
1142
1143 let horizontals = harr_set(
1144 self.horizontals,
1145 HLine::new(None, line.intersection, None, None),
1146 );
1147 let verticals = varr_set(
1148 self.verticals,
1149 VLine::new(None, line.intersection, line.top, line.bottom),
1150 );
1151
1152 Style::new(self.borders, horizontals, verticals)
1153 }
1154
1155 /// Set a frame for a style.
1156 ///
1157 /// It makes assumptions that a full frame will be set, but it may not be.
1158 ///
1159 /// # Example
1160 ///
1161 /// ```
1162 /// use tabled::{Table, settings::style::{Style, Border}};
1163 ///
1164 /// let data = [["10:52:19", "Hello"], ["10:52:20", "World"]];
1165 /// let table = Table::new(data)
1166 /// .with(Style::ascii().frame(Border::inherit(Style::modern())))
1167 /// .to_string();
1168 ///
1169 /// assert_eq!(
1170 /// table,
1171 /// concat!(
1172 /// "┌──────────+───────┐\n",
1173 /// "│ 0 | 1 │\n",
1174 /// "+----------+-------+\n",
1175 /// "│ 10:52:19 | Hello │\n",
1176 /// "+----------+-------+\n",
1177 /// "│ 10:52:20 | World │\n",
1178 /// "└──────────+───────┘",
1179 /// )
1180 /// );
1181 /// ```
1182 pub const fn frame<Top, Bottom, Left, Right>(
1183 mut self,
1184 border: Border<Top, Bottom, Left, Right>,
1185 ) -> Style<Top, Bottom, Left, Right, H, V, HN, VN>
1186 where
1187 T: Copy,
1188 B: Copy,
1189 L: Copy,
1190 R: Copy,
1191 H: Copy,
1192 V: Copy,
1193 Left: Copy,
1194 Right: Copy,
1195 Top: Copy,
1196 Bottom: Copy,
1197 {
1198 let border = border.into_inner();
1199 let border = correct_border(border);
1200
1201 let horizontals = harr_set(
1202 self.horizontals,
1203 HLine::new(None, None, border.left, border.right),
1204 );
1205 let verticals = varr_set(
1206 self.verticals,
1207 VLine::new(None, None, border.top, border.bottom),
1208 );
1209
1210 self.borders.top = border.top;
1211 self.borders.bottom = border.bottom;
1212 self.borders.left = border.left;
1213 self.borders.top_left = border.left_top_corner;
1214 self.borders.bottom_left = border.left_bottom_corner;
1215 self.borders.right = border.right;
1216 self.borders.top_right = border.right_top_corner;
1217 self.borders.bottom_right = border.right_bottom_corner;
1218
1219 Style::new(self.borders, horizontals, verticals)
1220 }
1221}
1222
1223impl<B, R, H, V, const HN: usize, const VN: usize> Style<On, B, On, R, H, V, HN, VN> {
1224 /// Sets a top left corner.
1225 pub const fn corner_top_left(mut self, c: char) -> Self {
1226 self.borders.top_left = Some(c);
1227
1228 Style::new(self.borders, self.horizontals, self.verticals)
1229 }
1230}
1231
1232impl<B, L, H, V, const HN: usize, const VN: usize> Style<On, B, L, On, H, V, HN, VN> {
1233 /// Sets a top right corner.
1234 pub const fn corner_top_right(mut self, c: char) -> Self {
1235 self.borders.top_right = Some(c);
1236
1237 Style::new(self.borders, self.horizontals, self.verticals)
1238 }
1239}
1240
1241impl<T, L, H, V, const HN: usize, const VN: usize> Style<T, On, L, On, H, V, HN, VN> {
1242 /// Sets a bottom right corner.
1243 pub const fn corner_bottom_right(mut self, c: char) -> Self {
1244 self.borders.bottom_right = Some(c);
1245
1246 Style::new(self.borders, self.horizontals, self.verticals)
1247 }
1248}
1249
1250impl<T, R, H, V, const HN: usize, const VN: usize> Style<T, On, On, R, H, V, HN, VN> {
1251 /// Sets a bottom left corner.
1252 pub const fn corner_bottom_left(mut self, c: char) -> Self {
1253 self.borders.bottom_left = Some(c);
1254
1255 Style::new(self.borders, self.horizontals, self.verticals)
1256 }
1257}
1258
1259impl<T, B, R, V, const HN: usize, const VN: usize> Style<T, B, On, R, On, V, HN, VN> {
1260 /// Sets a left intersection char.
1261 pub const fn intersection_left(mut self, c: char) -> Self {
1262 self.borders.left_intersection = Some(c);
1263
1264 Style::new(self.borders, self.horizontals, self.verticals)
1265 }
1266}
1267
1268impl<T, B, L, V, const HN: usize, const VN: usize> Style<T, B, L, On, On, V, HN, VN> {
1269 /// Sets a right intersection char.
1270 pub const fn intersection_right(mut self, c: char) -> Self {
1271 self.borders.right_intersection = Some(c);
1272
1273 Style::new(self.borders, self.horizontals, self.verticals)
1274 }
1275}
1276
1277impl<B, L, R, H, const HN: usize, const VN: usize> Style<On, B, L, R, H, On, HN, VN> {
1278 /// Sets a top intersection char.
1279 pub const fn intersection_top(mut self, c: char) -> Self {
1280 self.borders.top_intersection = Some(c);
1281
1282 Style::new(self.borders, self.horizontals, self.verticals)
1283 }
1284}
1285
1286impl<T, L, R, H, const HN: usize, const VN: usize> Style<T, On, L, R, H, On, HN, VN> {
1287 /// Sets a bottom intersection char.
1288 pub const fn intersection_bottom(mut self, c: char) -> Self {
1289 self.borders.bottom_intersection = Some(c);
1290
1291 Style::new(self.borders, self.horizontals, self.verticals)
1292 }
1293}
1294
1295impl<T, B, L, R, const HN: usize, const VN: usize> Style<T, B, L, R, On, On, HN, VN> {
1296 /// Sets an inner intersection char.
1297 /// A char between horizontal and vertical split lines.
1298 pub const fn intersection(mut self, c: char) -> Self
1299 where
1300 T: Copy,
1301 B: Copy,
1302 R: Copy,
1303 L: Copy,
1304 {
1305 self.borders.intersection = Some(c);
1306
1307 let horizontals: [(usize, HorizontalLine); HN] = harr_set(self.horizontals, set:HLine::new(main:None, intersection:Some(c), left:None, right:None));
1308 let verticals: [(usize, VerticalLine); VN] = varr_set(self.verticals, set:VLine::new(main:None, intersection:Some(c), top:None, bottom:None));
1309
1310 Style::new(self.borders, horizontals, verticals)
1311 }
1312}
1313
1314impl<B, L, R, H, V, const HN: usize, const VN: usize> Style<On, B, L, R, H, V, HN, VN> {
1315 /// Removes top border.
1316 pub const fn remove_top(mut self) -> Style<(), B, L, R, H, V, HN, VN>
1317 where
1318 B: Copy,
1319 H: Copy,
1320 {
1321 self.borders.top = None;
1322 self.borders.top_intersection = None;
1323 self.borders.top_left = None;
1324 self.borders.top_right = None;
1325
1326 let verticals: [(usize, VerticalLine); VN] = varr_unset(self.verticals, set:VLine::new(main:None, intersection:None, top:Some(' '), bottom:None));
1327
1328 Style::new(self.borders, self.horizontals, verticals)
1329 }
1330}
1331
1332impl<T, L, R, H, V, const HN: usize, const VN: usize> Style<T, On, L, R, H, V, HN, VN> {
1333 /// Removes bottom border.
1334 pub const fn remove_bottom(mut self) -> Style<T, (), L, R, H, V, HN, VN>
1335 where
1336 T: Copy,
1337 H: Copy,
1338 {
1339 self.borders.bottom = None;
1340 self.borders.bottom_intersection = None;
1341 self.borders.bottom_left = None;
1342 self.borders.bottom_right = None;
1343
1344 let verticals: [(usize, VerticalLine); VN] = varr_unset(self.verticals, set:VLine::new(main:None, intersection:None, top:None, bottom:Some(' ')));
1345
1346 Style::new(self.borders, self.horizontals, verticals)
1347 }
1348}
1349
1350impl<T, B, R, H, V, const HN: usize, const VN: usize> Style<T, B, On, R, H, V, HN, VN> {
1351 /// Removes left border.
1352 pub const fn remove_left(mut self) -> Style<T, B, (), R, H, V, HN, VN>
1353 where
1354 R: Copy,
1355 V: Copy,
1356 {
1357 self.borders.left = None;
1358 self.borders.left_intersection = None;
1359 self.borders.top_left = None;
1360 self.borders.bottom_left = None;
1361
1362 let horizontals: [(usize, HorizontalLine); HN] = harr_unset(self.horizontals, set:HLine::new(main:None, intersection:None, left:Some(' '), right:None));
1363
1364 Style::new(self.borders, horizontals, self.verticals)
1365 }
1366}
1367
1368impl<T, B, L, H, V, const HN: usize, const VN: usize> Style<T, B, L, On, H, V, HN, VN> {
1369 /// Removes right border.
1370 pub const fn remove_right(mut self) -> Style<T, B, L, (), H, V, HN, VN>
1371 where
1372 L: Copy,
1373 V: Copy,
1374 {
1375 self.borders.right = None;
1376 self.borders.right_intersection = None;
1377 self.borders.top_right = None;
1378 self.borders.bottom_right = None;
1379
1380 let horizontals: [(usize, HorizontalLine); HN] = harr_unset(self.horizontals, set:HLine::new(main:None, intersection:None, left:None, right:Some(' ')));
1381
1382 Style::new(self.borders, horizontals, self.verticals)
1383 }
1384}
1385
1386impl<T, B, L, R, V, const HN: usize, const VN: usize> Style<T, B, L, R, On, V, HN, VN> {
1387 /// Removes horizontal split lines.
1388 ///
1389 /// Not including custom split lines.
1390 pub const fn remove_horizontal(mut self) -> Style<T, B, L, R, (), V, HN, VN>
1391 where
1392 T: Copy,
1393 B: Copy,
1394 V: Copy,
1395 {
1396 self.borders.horizontal = None;
1397 self.borders.left_intersection = None;
1398 self.borders.right_intersection = None;
1399 self.borders.intersection = None;
1400
1401 // let lines = linearr_unset(lines, Line::new(None, Some(' '), None, None));
1402 let verticals: [(usize, VerticalLine); VN] = self.verticals;
1403
1404 Style::new(self.borders, self.horizontals, verticals)
1405 }
1406}
1407
1408impl<T, B, L, R, H, const HN: usize, const VN: usize> Style<T, B, L, R, H, On, HN, VN> {
1409 /// Removes vertical split lines.
1410 pub const fn remove_vertical(mut self) -> Style<T, B, L, R, H, (), HN, VN>
1411 where
1412 R: Copy,
1413 L: Copy,
1414 {
1415 self.borders.vertical = None;
1416 self.borders.top_intersection = None;
1417 self.borders.bottom_intersection = None;
1418 self.borders.intersection = None;
1419
1420 // let lines = linearr_unset(lines, Line::new(None, Some(' '), None, None));
1421 let horizontals: [(usize, HorizontalLine); HN] = self.horizontals;
1422
1423 Style::new(self.borders, horizontals, self.verticals)
1424 }
1425}
1426
1427impl<H, V, const HN: usize, const VN: usize> Style<On, On, On, On, H, V, HN, VN> {
1428 /// Removes frame.
1429 pub const fn remove_frame(self) -> Style<(), (), (), (), H, V, HN, VN>
1430 where
1431 V: Copy,
1432 H: Copy,
1433 {
1434 self.remove_bottom()
1435 .remove_top()
1436 .remove_left()
1437 .remove_right()
1438 }
1439}
1440
1441#[cfg(feature = "std")]
1442impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
1443 TableOption<Data, ColoredConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
1444{
1445 fn change(self, _: &mut Data, cfg: &mut ColoredConfig, _: &mut Dims) {
1446 cfg_clear_borders(cfg);
1447 cfg_set_custom_lines(cfg, &self.horizontals, &self.verticals);
1448 cfg.set_borders(self.borders);
1449 }
1450}
1451
1452impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
1453 TableOption<Data, CompactConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
1454{
1455 fn change(self, _: &mut Data, cfg: &mut CompactConfig, _: &mut Dims) {
1456 *cfg = cfg.set_borders(self.borders);
1457 }
1458}
1459
1460impl<T, B, L, R, H, V, Data, Dims, const HSIZE: usize, const VSIZE: usize>
1461 TableOption<Data, CompactMultilineConfig, Dims> for Style<T, B, L, R, H, V, HSIZE, VSIZE>
1462{
1463 fn change(self, _: &mut Data, cfg: &mut CompactMultilineConfig, _: &mut Dims) {
1464 cfg.set_borders(self.borders);
1465 }
1466}
1467
1468impl<T, B, L, R, H, V, const HSIZE: usize, const VSIZE: usize>
1469 From<Style<T, B, L, R, H, V, HSIZE, VSIZE>> for Borders<char>
1470{
1471 fn from(value: Style<T, B, L, R, H, V, HSIZE, VSIZE>) -> Self {
1472 value.borders
1473 }
1474}
1475
1476const fn correct_border(mut border: GridBorder<char>) -> GridBorder<char> {
1477 if border.has_top() && border.top.is_none() {
1478 border.top = Some(' ');
1479 }
1480
1481 if border.has_bottom() && border.bottom.is_none() {
1482 border.bottom = Some(' ');
1483 }
1484
1485 if border.has_left() && border.left.is_none() {
1486 border.left = Some(' ');
1487 }
1488
1489 if border.has_right() && border.right.is_none() {
1490 border.right = Some(' ');
1491 }
1492
1493 if border.has_top() && border.has_left() && border.left_top_corner.is_none() {
1494 border.left_top_corner = Some(' ');
1495 }
1496
1497 if border.has_top() && border.has_right() && border.right_top_corner.is_none() {
1498 border.right_top_corner = Some(' ');
1499 }
1500
1501 if border.has_bottom() && border.has_left() && border.left_top_corner.is_none() {
1502 border.left_bottom_corner = Some(' ');
1503 }
1504
1505 if border.has_bottom() && border.has_right() && border.right_bottom_corner.is_none() {
1506 border.right_bottom_corner = Some(' ');
1507 }
1508
1509 border
1510}
1511
1512const fn varr_convert<T, B, I, const N: usize>(
1513 lines: [(usize, VerticalLine<T, B, I>); N],
1514) -> VArray<N> {
1515 let mut buf: [(usize, VerticalLine); N] = [(0, VLine::empty()); N];
1516 let mut i: usize = 0;
1517 while i < N {
1518 let (index: &usize, line: &VerticalLine) = &lines[i];
1519 let index: usize = *index;
1520 let line: VerticalLine = line.into_inner();
1521
1522 buf[i].0 = index;
1523 buf[i].1 = line;
1524
1525 i += 1;
1526 }
1527
1528 buf
1529}
1530
1531const fn harr_convert<L, R, I, const N: usize>(
1532 lines: [(usize, HorizontalLine<L, R, I>); N],
1533) -> HArray<N> {
1534 let mut buf: [(usize, HorizontalLine); N] = [(0, HLine::empty()); N];
1535 let mut i: usize = 0;
1536 while i < N {
1537 let (index: &usize, line: &HorizontalLine) = &lines[i];
1538 let index: usize = *index;
1539 let line: HorizontalLine = line.into_inner();
1540
1541 buf[i].0 = index;
1542 buf[i].1 = line;
1543
1544 i += 1;
1545 }
1546
1547 buf
1548}
1549
1550const fn harr_set<const N: usize>(lines: HArray<N>, set: HLine) -> HArray<N> {
1551 let mut buf = [(0, HLine::empty()); N];
1552 let mut i = 0;
1553 while i < N {
1554 let (index, mut line) = lines[i];
1555
1556 if set.left.is_some() {
1557 line.left = set.left;
1558 }
1559
1560 if set.right.is_some() {
1561 line.right = set.right;
1562 }
1563
1564 if set.intersection.is_some() {
1565 line.intersection = set.intersection;
1566 }
1567
1568 if set.main.is_some() {
1569 line.main = set.main;
1570 }
1571
1572 buf[i].0 = index;
1573 buf[i].1 = line;
1574
1575 i += 1;
1576 }
1577
1578 buf
1579}
1580
1581const fn harr_unset<const N: usize>(lines: HArray<N>, set: HLine) -> HArray<N> {
1582 let mut buf = [(0, HLine::empty()); N];
1583 let mut i = 0;
1584 while i < N {
1585 let (index, mut line) = lines[i];
1586
1587 if set.left.is_some() {
1588 line.left = None;
1589 }
1590
1591 if set.right.is_some() {
1592 line.right = None;
1593 }
1594
1595 if set.intersection.is_some() {
1596 line.intersection = None;
1597 }
1598
1599 if set.main.is_some() {
1600 line.main = None;
1601 }
1602
1603 buf[i].0 = index;
1604 buf[i].1 = line;
1605
1606 i += 1;
1607 }
1608
1609 buf
1610}
1611
1612const fn varr_set<const N: usize>(lines: VArray<N>, set: VLine) -> VArray<N> {
1613 let mut buf = [(0, VLine::empty()); N];
1614 let mut i = 0;
1615 while i < N {
1616 let (index, mut line) = lines[i];
1617
1618 if set.top.is_some() {
1619 line.top = set.top;
1620 }
1621
1622 if set.bottom.is_some() {
1623 line.bottom = set.bottom;
1624 }
1625
1626 if set.intersection.is_some() {
1627 line.intersection = set.intersection;
1628 }
1629
1630 if set.main.is_some() {
1631 line.main = set.main;
1632 }
1633
1634 buf[i].0 = index;
1635 buf[i].1 = line;
1636
1637 i += 1;
1638 }
1639
1640 buf
1641}
1642
1643const fn varr_unset<const N: usize>(lines: VArray<N>, set: VLine) -> VArray<N> {
1644 let mut buf = [(0, VLine::empty()); N];
1645 let mut i = 0;
1646 while i < N {
1647 let (index, mut line) = lines[i];
1648
1649 if set.top.is_some() {
1650 line.top = None;
1651 }
1652
1653 if set.bottom.is_some() {
1654 line.bottom = None;
1655 }
1656
1657 if set.intersection.is_some() {
1658 line.intersection = None;
1659 }
1660
1661 if set.main.is_some() {
1662 line.main = None;
1663 }
1664
1665 buf[i].0 = index;
1666 buf[i].1 = line;
1667
1668 i += 1;
1669 }
1670
1671 buf
1672}
1673
1674const fn create_borders(
1675 top: HLine,
1676 bottom: HLine,
1677 horizontal: HLine,
1678 left: Option<char>,
1679 right: Option<char>,
1680 vertical: Option<char>,
1681) -> Borders<char> {
1682 Borders {
1683 top: top.main,
1684 top_left: top.left,
1685 top_right: top.right,
1686 top_intersection: top.intersection,
1687 bottom: bottom.main,
1688 bottom_left: bottom.left,
1689 bottom_right: bottom.right,
1690 bottom_intersection: bottom.intersection,
1691 left_intersection: horizontal.left,
1692 right_intersection: horizontal.right,
1693 horizontal: horizontal.main,
1694 intersection: horizontal.intersection,
1695 left,
1696 right,
1697 vertical,
1698 }
1699}
1700
1701#[cfg(feature = "std")]
1702fn cfg_set_custom_lines(
1703 cfg: &mut ColoredConfig,
1704 hlines: &[(usize, HLine)],
1705 vlines: &[(usize, VLine)],
1706) {
1707 for &(row: usize, line: HorizontalLine) in hlines {
1708 cfg.insert_horizontal_line(line:row, val:line);
1709 }
1710
1711 for &(col: usize, line: VerticalLine) in vlines {
1712 cfg.insert_vertical_line(line:col, val:line);
1713 }
1714}
1715
1716#[cfg(feature = "std")]
1717fn cfg_clear_borders(cfg: &mut ColoredConfig) {
1718 cfg.remove_borders();
1719 cfg.remove_vertical_chars();
1720 cfg.remove_horizontal_chars();
1721 cfg.remove_borders_colors();
1722 cfg.remove_color_line_horizontal();
1723 cfg.remove_color_line_vertical();
1724}
1725