1 //! This module contains a compile time style builder [`Style`].
3 use core
::marker
::PhantomData
;
6 grid
::config
::{Borders, CompactConfig, CompactMultilineConfig}
,
10 #[cfg(feature = "std")]
11 use crate::grid
::config
::ColoredConfig
;
13 use super::{HorizontalLine, Line, VerticalLine}
;
15 /// Style is represents a theme of a [`Table`].
18 /// corner top left top intersection corner top right
21 /// ╭───┬───┬───┬───┬───┬───┬────┬────┬────╮
22 /// │ i │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
23 /// ├───┼───┼───┼───┼───┼───┼────┼────┼────┤ <- this horizontal line is custom 'horizontals'
24 /// │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ other lines horizontal lines are not set they called 'horizontal'
25 /// │ 1 │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
26 /// │ 2 │ 0 │ 2 │ 4 │ 6 │ 8 │ 10 │ 12 │ 14 │
27 /// ╰───┴───┴───┴───┴───┴───┴────┴────┴────╯
30 /// corner bottom left | bottom intersection corner bottom right
33 /// all this vertical lines are called 'vertical'
38 /// ┌───┬───┬───┬───┬───┐
39 /// │ 0 │ 1 │ 2 │ 3 │ 4 │
40 /// intersection left ->├───X───X───X───X───┤ <- all this horizontal lines are called 'horizontal'
41 /// │ 1 │ 2 │ 3 │ 4 │ 5 │
42 /// ├───X───X───X───X───┤ <- intersection right
43 /// │ 2 │ 3 │ 4 │ 5 │ 6 │
44 /// └───┴───┴───┴───┴───┘
46 /// All 'X' positions are called 'intersection'.
47 /// It's a place where 'vertical' and 'horizontal' lines intersect.
50 /// It tries to limit an controlling a valid state of it.
51 /// For example, it won't allow to call method [`Style::corner_top_left`] unless [`Style::left`] and [`Style::top`] is set.
53 /// You can turn [`Style`] into [`RawStyle`] to have more control using [`Into`] implementation.
57 #[cfg_attr(feature = "std", doc = "```")]
58 #[cfg_attr(not(feature = "std"), doc = "```ignore")]
59 /// use tabled::{Table, settings::Style};
61 /// let style = Style::ascii()
63 /// .intersection(' ');
65 /// let data = vec!["Hello", "2021"];
66 /// let table = Table::new(&data).with(style).to_string();
68 /// println!("{}", table);
71 /// [`Table`]: crate::Table
72 /// [`RawStyle`]: crate::settings::style::RawStyle
73 /// [`Style::corner_top_left`]: Style::corner_top_left
74 /// [`Style::left`]: Style.left
75 /// [`Style::top`]: Style.function.top
76 #[derive(Debug, Clone)]
77 pub struct Style
<T
, B
, L
, R
, H
, V
, HLines
= HLineArray
<0>, VLines
= VLineArray
<0>> {
78 borders
: Borders
<char>,
82 _bottom
: PhantomData
<B
>,
83 _left
: PhantomData
<L
>,
84 _right
: PhantomData
<R
>,
85 _horizontal
: PhantomData
<H
>,
86 _vertical
: PhantomData
<V
>,
89 type HLineArray
<const N
: usize> = [HorizontalLine
; N
];
91 type VLineArray
<const N
: usize> = [VerticalLine
; N
];
93 /// A marker struct which is used in [`Style`].
94 #[derive(Debug, Clone)]
97 impl Style
<(), (), (), (), (), (), (), ()> {
98 /// This style is a style with no styling options on,
101 /// id destribution link
102 /// 0 Fedora https://getfedora.org/
103 /// 2 OpenSUSE https://www.opensuse.org/
104 /// 3 Endeavouros https://endeavouros.com/
107 /// Note: The cells in the example have 1-left and 1-right indent.
109 /// This style can be used as a base style to build a custom one.
112 /// # use tabled::settings::Style;
113 /// let style = Style::empty()
117 /// .intersection_top('*');
119 pub const fn empty() -> Style
<(), (), (), (), (), ()> {
134 /// This style is analog of `empty` but with a vertical space(' ') line.
137 /// id destribution link
138 /// 0 Fedora https://getfedora.org/
139 /// 2 OpenSUSE https://www.opensuse.org/
140 /// 3 Endeavouros https://endeavouros.com/
142 pub const fn blank() -> Style
<(), (), (), (), (), On
> {
157 /// This is a style which relays only on ASCII charset.
159 /// It has horizontal and vertical lines.
162 /// +----+--------------+---------------------------+
163 /// | id | destribution | link |
164 /// +----+--------------+---------------------------+
165 /// | 0 | Fedora | https://getfedora.org/ |
166 /// +----+--------------+---------------------------+
167 /// | 2 | OpenSUSE | https://www.opensuse.org/ |
168 /// +----+--------------+---------------------------+
169 /// | 3 | Endeavouros | https://endeavouros.com/ |
170 /// +----+--------------+---------------------------+
172 pub const fn ascii() -> Style
<On
, On
, On
, On
, On
, On
> {
175 Line
::full('
-'
, '
+'
, '
+'
, '
+'
),
176 Line
::full('
-'
, '
+'
, '
+'
, '
+'
),
177 Line
::full('
-'
, '
+'
, '
+'
, '
+'
),
187 /// `psql` style looks like a table style `PostgreSQL` uses.
189 /// It has only 1 horizontal line which splits header.
190 /// And no left and right vertical lines.
193 /// id | destribution | link
194 /// ----+--------------+---------------------------
195 /// 0 | Fedora | https://getfedora.org/
196 /// 2 | OpenSUSE | https://www.opensuse.org/
197 /// 3 | Endeavouros | https://endeavouros.com/
199 pub const fn psql() -> Style
<(), (), (), (), (), On
, HLineArray
<1>> {
209 [HorizontalLine
::new(1, Line
::empty())
211 .intersection(Some('
+'
))],
216 /// `markdown` style mimics a `Markdown` table style.
219 /// | id | destribution | link |
220 /// |----|--------------|---------------------------|
221 /// | 0 | Fedora | https://getfedora.org/ |
222 /// | 2 | OpenSUSE | https://www.opensuse.org/ |
223 /// | 3 | Endeavouros | https://endeavouros.com/ |
225 pub const fn markdown() -> Style
<(), (), On
, On
, (), On
, HLineArray
<1>> {
235 [HorizontalLine
::new(1, Line
::full('
-'
, '
|'
, '
|'
, '
|'
))],
240 /// This style is analog of [`Style::ascii`] which uses UTF-8 charset.
242 /// It has vertical and horizontal split lines.
245 /// ┌────┬──────────────┬───────────────────────────┐
246 /// │ id │ destribution │ link │
247 /// ├────┼──────────────┼───────────────────────────┤
248 /// │ 0 │ Fedora │ https://getfedora.org/ │
249 /// ├────┼──────────────┼───────────────────────────┤
250 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
251 /// ├────┼──────────────┼───────────────────────────┤
252 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
253 /// └────┴──────────────┴───────────────────────────┘
255 pub const fn modern() -> Style
<On
, On
, On
, On
, On
, On
> {
258 Line
::full('─'
, '┬'
, '┌'
, '┐'
),
259 Line
::full('─'
, '┴'
, '└'
, '┘'
),
260 Line
::full('─'
, '┼'
, '├'
, '┤'
),
270 /// This style looks like a [`Style::modern`] but without horozizontal lines except a header.
272 /// Beware: It uses UTF-8 characters.
275 /// ┌────┬──────────────┬───────────────────────────┐
276 /// │ id │ destribution │ link │
277 /// ├────┼──────────────┼───────────────────────────┤
278 /// │ 0 │ Fedora │ https://getfedora.org/ │
279 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
280 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
281 /// └────┴──────────────┴───────────────────────────┘
283 pub const fn sharp() -> Style
<On
, On
, On
, On
, (), On
, HLineArray
<1>> {
286 Line
::full('─'
, '┬'
, '┌'
, '┐'
),
287 Line
::full('─'
, '┴'
, '└'
, '┘'
),
293 [HorizontalLine
::new(1, Line
::full('─'
, '┼'
, '├'
, '┤'
))],
298 /// This style looks like a [`Style::sharp`] but with rounded corners.
300 /// Beware: It uses UTF-8 characters.
303 /// ╭────┬──────────────┬───────────────────────────╮
304 /// │ id │ destribution │ link │
305 /// ├────┼──────────────┼───────────────────────────┤
306 /// │ 0 │ Fedora │ https://getfedora.org/ │
307 /// │ 2 │ OpenSUSE │ https://www.opensuse.org/ │
308 /// │ 3 │ Endeavouros │ https://endeavouros.com/ │
309 /// ╰────┴──────────────┴───────────────────────────╯
311 pub const fn rounded() -> Style
<On
, On
, On
, On
, (), On
, HLineArray
<1>> {
314 Line
::full('─'
, '┬'
, '╭'
, '╮'
),
315 Line
::full('─'
, '┴'
, '╰'
, '╯'
),
321 [HorizontalLine
::new(1, Line
::full('─'
, '┼'
, '├'
, '┤'
))],
326 /// This style uses a chars which resembles '2 lines'.
328 /// Beware: It uses UTF8 characters.
331 /// ╔════╦══════════════╦═══════════════════════════╗
332 /// ║ id ║ destribution ║ link ║
333 /// ╠════╬══════════════╬═══════════════════════════╣
334 /// ║ 0 ║ Fedora ║ https://getfedora.org/ ║
335 /// ╠════╬══════════════╬═══════════════════════════╣
336 /// ║ 2 ║ OpenSUSE ║ https://www.opensuse.org/ ║
337 /// ╠════╬══════════════╬═══════════════════════════╣
338 /// ║ 3 ║ Endeavouros ║ https://endeavouros.com/ ║
339 /// ╚════╩══════════════╩═══════════════════════════╝
341 pub const fn extended() -> Style
<On
, On
, On
, On
, On
, On
> {
344 Line
::full('═'
, '╦'
, '╔'
, '╗'
),
345 Line
::full('═'
, '╩'
, '╚'
, '╝'
),
346 Line
::full('═'
, '╬'
, '╠'
, '╣'
),
356 /// This is a style uses only '.' and ':' chars.
357 /// It has a vertical and horizontal split lines.
360 /// .................................................
361 /// : id : destribution : link :
362 /// :....:..............:...........................:
363 /// : 0 : Fedora : https://getfedora.org/ :
364 /// :....:..............:...........................:
365 /// : 2 : OpenSUSE : https://www.opensuse.org/ :
366 /// :....:..............:...........................:
367 /// : 3 : Endeavouros : https://endeavouros.com/ :
368 /// :....:..............:...........................:
370 pub const fn dots() -> Style
<On
, On
, On
, On
, On
, On
> {
373 Line
::full('
.'
, '
.'
, '
.'
, '
.'
),
374 Line
::full('
.'
, '
:'
, '
:'
, '
:'
),
375 Line
::full('
.'
, '
:'
, '
:'
, '
:'
),
385 /// This style is one of table views in `ReStructuredText`.
388 /// ==== ============== ===========================
389 /// id destribution link
390 /// ==== ============== ===========================
391 /// 0 Fedora https://getfedora.org/
392 /// 2 OpenSUSE https://www.opensuse.org/
393 /// 3 Endeavouros https://endeavouros.com/
394 /// ==== ============== ===========================
396 pub const fn re_structured_text() -> Style
<On
, On
, (), (), (), On
, HLineArray
<1>> {
399 Line
::new(Some('
='
), Some(' '
), None
, None
),
400 Line
::new(Some('
='
), Some(' '
), None
, None
),
406 [HorizontalLine
::new(
408 Line
::new(Some('
='
), Some(' '
), None
, None
),
414 /// This is a theme analog of [`Style::rounded`], but in using ascii charset and
415 /// with no horizontal lines.
418 /// .-----------------------------------------------.
419 /// | id | destribution | link |
420 /// | 0 | Fedora | https://getfedora.org/ |
421 /// | 2 | OpenSUSE | https://www.opensuse.org/ |
422 /// | 3 | Endeavouros | https://endeavouros.com/ |
423 /// '-----------------------------------------------'
425 pub const fn ascii_rounded() -> Style
<On
, On
, On
, On
, (), On
> {
428 Line
::full('
-'
, '
-'
, '
.'
, '
.'
),
429 Line
::full('
-'
, '
-'
, '
\''
, '
\''
),
441 impl<T
, B
, L
, R
, H
, V
, HLines
, VLines
> Style
<T
, B
, L
, R
, H
, V
, HLines
, VLines
> {
442 /// Frame function returns a frame as a border.
447 /// use tabled::{Table, settings::{Style, Highlight, object::Rows}};
449 /// let data = [["10:52:19", "Hello"], ["10:52:20", "World"]];
450 /// let table = Table::new(data)
451 /// .with(Highlight::new(Rows::first(), Style::modern().get_frame()))
457 /// "┌──────────────────┐\n",
459 /// "└──────────────────┘\n",
460 /// "| 10:52:19 | Hello |\n",
461 /// "+----------+-------+\n",
462 /// "| 10:52:20 | World |\n",
463 /// "+----------+-------+",
467 #[cfg(feature = "std")]
468 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
469 pub const fn get_frame(&self) -> super::Border
{
470 let mut border
= super::Border
::filled(' '
);
472 if let Some(c
) = self.borders
.top
{
473 border
= border
.top(c
);
476 if let Some(c
) = self.borders
.bottom
{
477 border
= border
.bottom(c
);
480 if let Some(c
) = self.borders
.left
{
481 border
= border
.left(c
);
484 if let Some(c
) = self.borders
.right
{
485 border
= border
.right(c
);
488 if let Some(c
) = self.borders
.top_left
{
489 border
= border
.corner_top_left(c
);
492 if let Some(c
) = self.borders
.bottom_left
{
493 border
= border
.corner_bottom_left(c
);
496 if let Some(c
) = self.borders
.top_right
{
497 border
= border
.corner_top_right(c
);
500 if let Some(c
) = self.borders
.bottom_right
{
501 border
= border
.corner_bottom_right(c
);
507 /// Get a [`Style`]'s default horizontal line.
509 /// It doesn't return an overloaded line via [`Style::horizontals`].
513 #[cfg_attr(feature = "std", doc = "```")]
514 #[cfg_attr(not(feature = "std"), doc = "```ignore")]
515 /// use tabled::{settings::style::{Style, HorizontalLine, Line}, Table};
517 /// let table = Table::new((0..3).map(|i| ("Hello", "World", i)))
518 /// .with(Style::ascii().remove_horizontal().horizontals([HorizontalLine::new(1, Style::modern().get_horizontal())]))
524 /// "+-------+-------+-----+\n",
525 /// "| &str | &str | i32 |\n",
526 /// "├───────┼───────┼─────┤\n",
527 /// "| Hello | World | 0 |\n",
528 /// "| Hello | World | 1 |\n",
529 /// "| Hello | World | 2 |\n",
530 /// "+-------+-------+-----+",
534 pub const fn get_horizontal(&self) -> Line
{
536 self.borders
.horizontal
,
537 self.borders
.intersection
,
538 self.borders
.left_intersection
,
539 self.borders
.right_intersection
,
543 /// Get a [`Style`]'s default horizontal line.
545 /// It doesn't return an overloaded line via [`Style::verticals`].
549 #[cfg_attr(feature = "std", doc = "```")]
550 #[cfg_attr(not(feature = "std"), doc = "```ignore")]
551 /// use tabled::{settings::style::{Style, VerticalLine, Line}, Table};
553 /// let table = Table::new((0..3).map(|i| ("Hello", "World", i)))
554 /// .with(Style::ascii().remove_horizontal().verticals([VerticalLine::new(1, Style::modern().get_vertical())]))
560 /// "+-------┬-------+-----+\n",
561 /// "| &str │ &str | i32 |\n",
562 /// "| Hello │ World | 0 |\n",
563 /// "| Hello │ World | 1 |\n",
564 /// "| Hello │ World | 2 |\n",
565 /// "+-------┴-------+-----+",
569 pub const fn get_vertical(&self) -> Line
{
571 self.borders
.vertical
,
572 self.borders
.intersection
,
573 self.borders
.top_intersection
,
574 self.borders
.bottom_intersection
,
578 /// Sets a top border.
580 /// Any corners and intersections which were set will be overridden.
581 pub fn top(mut self, c
: char) -> Style
<On
, B
, L
, R
, H
, V
, HLines
, VLines
>
583 for<'a
> &'a
mut VLines
: IntoIterator
<Item
= &'a
mut VerticalLine
>,
585 self.borders
.top
= Some(c
);
587 if self.borders
.has_left() {
588 self.borders
.top_left
= Some(c
);
591 if self.borders
.has_right() {
592 self.borders
.top_right
= Some(c
);
595 if self.borders
.has_vertical() {
596 self.borders
.top_intersection
= Some(c
);
599 for vl
in &mut self.verticals
{
600 vl
.line
.connector1
= Some(c
);
603 Style
::new(self.borders
, self.horizontals
, self.verticals
)
606 /// Sets a bottom border.
608 /// Any corners and intersections which were set will be overridden.
609 pub fn bottom(mut self, c
: char) -> Style
<T
, On
, L
, R
, H
, V
, HLines
, VLines
>
611 for<'a
> &'a
mut VLines
: IntoIterator
<Item
= &'a
mut VerticalLine
>,
613 self.borders
.bottom
= Some(c
);
615 if self.borders
.has_left() {
616 self.borders
.bottom_left
= Some(c
);
619 if self.borders
.has_right() {
620 self.borders
.bottom_right
= Some(c
);
623 if self.borders
.has_vertical() {
624 self.borders
.bottom_intersection
= Some(c
);
627 for vl
in &mut self.verticals
{
628 vl
.line
.connector2
= Some(c
);
631 Style
::new(self.borders
, self.horizontals
, self.verticals
)
634 /// Sets a left border.
636 /// Any corners and intersections which were set will be overridden.
637 pub fn left(mut self, c
: char) -> Style
<T
, B
, On
, R
, H
, V
, HLines
, VLines
>
639 for<'a
> &'a
mut HLines
: IntoIterator
<Item
= &'a
mut HorizontalLine
>,
641 self.borders
.left
= Some(c
);
643 if self.borders
.has_top() {
644 self.borders
.top_left
= Some(c
);
647 if self.borders
.has_bottom() {
648 self.borders
.bottom_left
= Some(c
);
651 if self.borders
.has_horizontal() {
652 self.borders
.left_intersection
= Some(c
);
655 for hl
in &mut self.horizontals
{
656 hl
.line
.connector1
= Some(c
);
659 Style
::new(self.borders
, self.horizontals
, self.verticals
)
662 /// Sets a right border.
664 /// Any corners and intersections which were set will be overridden.
665 pub fn right(mut self, c
: char) -> Style
<T
, B
, L
, On
, H
, V
, HLines
, VLines
>
667 for<'a
> &'a
mut HLines
: IntoIterator
<Item
= &'a
mut HorizontalLine
>,
669 self.borders
.right
= Some(c
);
671 if self.borders
.has_top() {
672 self.borders
.top_right
= Some(c
);
675 if self.borders
.has_bottom() {
676 self.borders
.bottom_right
= Some(c
);
679 if self.borders
.has_horizontal() {
680 self.borders
.right_intersection
= Some(c
);
683 for hl
in &mut self.horizontals
{
684 hl
.line
.connector2
= Some(c
);
687 Style
::new(self.borders
, self.horizontals
, self.verticals
)
690 /// Sets a horizontal split line.
692 /// Any corners and intersections which were set will be overridden.
693 pub fn horizontal(mut self, c
: char) -> Style
<T
, B
, L
, R
, On
, V
, HLines
, VLines
>
695 for<'a
> &'a
mut VLines
: IntoIterator
<Item
= &'a
mut VerticalLine
>,
697 self.borders
.horizontal
= Some(c
);
699 if self.borders
.has_vertical() {
700 self.borders
.intersection
= Some(c
);
703 if self.borders
.has_left() {
704 self.borders
.left_intersection
= Some(c
);
707 if self.borders
.has_right() {
708 self.borders
.right_intersection
= Some(c
);
711 for vl
in &mut self.verticals
{
712 vl
.line
.intersection
= Some(c
);
715 Style
::new(self.borders
, self.horizontals
, self.verticals
)
718 /// Sets a vertical split line.
720 /// Any corners and intersections which were set will be overridden.
721 pub fn vertical(mut self, c
: char) -> Style
<T
, B
, L
, R
, H
, On
, HLines
, VLines
>
723 for<'a
> &'a
mut HLines
: IntoIterator
<Item
= &'a
mut HorizontalLine
>,
725 self.borders
.vertical
= Some(c
);
727 if self.borders
.has_horizontal() {
728 self.borders
.intersection
= Some(c
);
731 if self.borders
.has_top() {
732 self.borders
.top_intersection
= Some(c
);
735 if self.borders
.has_bottom() {
736 self.borders
.bottom_intersection
= Some(c
);
739 for hl
in &mut self.horizontals
{
740 hl
.line
.intersection
= Some(c
);
743 Style
::new(self.borders
, self.horizontals
, self.verticals
)
746 /// Set border horizontal lines.
750 #[cfg_attr(feature = "derive", doc = "```")]
751 #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
752 /// use tabled::{settings::style::{Style, HorizontalLine, Line}, Table};
754 /// let table = Table::new((0..3).map(|i| ("Hello", i)))
755 /// .with(Style::rounded().horizontals((1..4).map(|i| HorizontalLine::new(i, Line::filled('#')))))
761 /// "╭───────┬─────╮\n",
762 /// "│ &str │ i32 │\n",
763 /// "###############\n",
764 /// "│ Hello │ 0 │\n",
765 /// "###############\n",
766 /// "│ Hello │ 1 │\n",
767 /// "###############\n",
768 /// "│ Hello │ 2 │\n",
769 /// "╰───────┴─────╯",
773 pub fn horizontals
<NewLines
>(self, lines
: NewLines
) -> Style
<T
, B
, L
, R
, H
, V
, NewLines
, VLines
>
775 NewLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
777 Style
::new(self.borders
, lines
, self.verticals
)
780 /// Set border vertical lines.
784 #[cfg_attr(feature = "derive", doc = "```")]
785 #[cfg_attr(not(feature = "derive"), doc = "```ignore")]
786 /// use tabled::{Table, settings::style::{Style, VerticalLine, Line}};
788 /// let table = Table::new((0..3).map(|i| ("Hello", i)))
789 /// .with(Style::rounded().verticals((0..3).map(|i| VerticalLine::new(i, Line::filled('#')))))
795 /// "#───────#─────#\n",
796 /// "# &str # i32 #\n",
797 /// "├───────┼─────┤\n",
798 /// "# Hello # 0 #\n",
799 /// "# Hello # 1 #\n",
800 /// "# Hello # 2 #\n",
801 /// "#───────#─────#",
805 pub fn verticals
<NewLines
>(self, lines
: NewLines
) -> Style
<T
, B
, L
, R
, H
, V
, HLines
, NewLines
>
807 NewLines
: IntoIterator
<Item
= VerticalLine
> + Clone
,
809 Style
::new(self.borders
, self.horizontals
, lines
)
812 /// Removes all horizontal lines set by [`Style::horizontals`]
813 pub fn remove_horizontals(self) -> Style
<T
, B
, L
, R
, H
, V
, HLineArray
<0>, VLines
> {
814 Style
::new(self.borders
, [], self.verticals
)
817 /// Removes all verticals lines set by [`Style::verticals`]
818 pub fn remove_verticals(self) -> Style
<T
, B
, L
, R
, H
, V
, HLines
, VLineArray
<0>> {
819 Style
::new(self.borders
, self.horizontals
, [])
823 impl<B
, R
, H
, V
, HLines
, VLines
> Style
<On
, B
, On
, R
, H
, V
, HLines
, VLines
> {
824 /// Sets a top left corner.
825 pub fn corner_top_left(mut self, c
: char) -> Self {
826 self.borders
.top_left
= Some(c
);
828 Style
::new(self.borders
, self.horizontals
, self.verticals
)
832 impl<B
, L
, H
, V
, HLines
, VLines
> Style
<On
, B
, L
, On
, H
, V
, HLines
, VLines
> {
833 /// Sets a top right corner.
834 pub fn corner_top_right(mut self, c
: char) -> Self {
835 self.borders
.top_right
= Some(c
);
837 Style
::new(self.borders
, self.horizontals
, self.verticals
)
841 impl<T
, L
, H
, V
, HLines
, VLines
> Style
<T
, On
, L
, On
, H
, V
, HLines
, VLines
> {
842 /// Sets a bottom right corner.
843 pub fn corner_bottom_right(mut self, c
: char) -> Self {
844 self.borders
.bottom_right
= Some(c
);
846 Style
::new(self.borders
, self.horizontals
, self.verticals
)
850 impl<T
, R
, H
, V
, HLines
, VLines
> Style
<T
, On
, On
, R
, H
, V
, HLines
, VLines
> {
851 /// Sets a bottom left corner.
852 pub fn corner_bottom_left(mut self, c
: char) -> Self {
853 self.borders
.bottom_left
= Some(c
);
855 Style
::new(self.borders
, self.horizontals
, self.verticals
)
859 impl<T
, B
, R
, V
, HLines
, VLines
> Style
<T
, B
, On
, R
, On
, V
, HLines
, VLines
> {
860 /// Sets a left intersection char.
861 pub fn intersection_left(mut self, c
: char) -> Self {
862 self.borders
.left_intersection
= Some(c
);
864 Style
::new(self.borders
, self.horizontals
, self.verticals
)
868 impl<T
, B
, L
, V
, HLines
, VLines
> Style
<T
, B
, L
, On
, On
, V
, HLines
, VLines
> {
869 /// Sets a right intersection char.
870 pub fn intersection_right(mut self, c
: char) -> Self {
871 self.borders
.right_intersection
= Some(c
);
873 Style
::new(self.borders
, self.horizontals
, self.verticals
)
877 impl<B
, L
, R
, H
, HLines
, VLines
> Style
<On
, B
, L
, R
, H
, On
, HLines
, VLines
> {
878 /// Sets a top intersection char.
879 pub fn intersection_top(mut self, c
: char) -> Self {
880 self.borders
.top_intersection
= Some(c
);
882 Style
::new(self.borders
, self.horizontals
, self.verticals
)
886 impl<T
, L
, R
, H
, HLines
, VLines
> Style
<T
, On
, L
, R
, H
, On
, HLines
, VLines
> {
887 /// Sets a bottom intersection char.
888 pub fn intersection_bottom(mut self, c
: char) -> Self {
889 self.borders
.bottom_intersection
= Some(c
);
891 Style
::new(self.borders
, self.horizontals
, self.verticals
)
895 impl<T
, B
, L
, R
, HLines
, VLines
> Style
<T
, B
, L
, R
, On
, On
, HLines
, VLines
> {
896 /// Sets an inner intersection char.
897 /// A char between horizontal and vertical split lines.
898 pub fn intersection(mut self, c
: char) -> Self {
899 self.borders
.intersection
= Some(c
);
901 Style
::new(self.borders
, self.horizontals
, self.verticals
)
905 impl<B
, L
, R
, H
, V
, HLines
, VLines
> Style
<On
, B
, L
, R
, H
, V
, HLines
, VLines
> {
906 /// Removes top border.
909 ) -> Style
<(), B
, L
, R
, H
, V
, HLines
, VerticalLineIter
<VLines
::IntoIter
>>
911 VLines
: IntoIterator
<Item
= VerticalLine
> + Clone
,
913 self.borders
.top
= None
;
914 self.borders
.top_intersection
= None
;
915 self.borders
.top_left
= None
;
916 self.borders
.top_right
= None
;
918 let iter
= VerticalLineIter
::new(self.verticals
.into_iter(), false, true, false);
919 Style
::new(self.borders
, self.horizontals
, iter
)
923 impl<T
, L
, R
, H
, V
, HLines
, VLines
> Style
<T
, On
, L
, R
, H
, V
, HLines
, VLines
> {
924 /// Removes bottom border.
925 pub fn remove_bottom(
927 ) -> Style
<T
, (), L
, R
, H
, V
, HLines
, VerticalLineIter
<VLines
::IntoIter
>>
929 VLines
: IntoIterator
<Item
= VerticalLine
> + Clone
,
931 self.borders
.bottom
= None
;
932 self.borders
.bottom_intersection
= None
;
933 self.borders
.bottom_left
= None
;
934 self.borders
.bottom_right
= None
;
936 let iter
= VerticalLineIter
::new(self.verticals
.into_iter(), false, false, true);
937 Style
::new(self.borders
, self.horizontals
, iter
)
941 impl<T
, B
, R
, H
, V
, HLines
, VLines
> Style
<T
, B
, On
, R
, H
, V
, HLines
, VLines
> {
942 /// Removes left border.
945 ) -> Style
<T
, B
, (), R
, H
, V
, HorizontalLineIter
<HLines
::IntoIter
>, VLines
>
947 HLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
949 self.borders
.left
= None
;
950 self.borders
.left_intersection
= None
;
951 self.borders
.top_left
= None
;
952 self.borders
.bottom_left
= None
;
954 let iter
= HorizontalLineIter
::new(self.horizontals
.into_iter(), false, true, false);
955 Style
::new(self.borders
, iter
, self.verticals
)
959 impl<T
, B
, L
, H
, V
, HLines
, VLines
> Style
<T
, B
, L
, On
, H
, V
, HLines
, VLines
> {
960 /// Removes right border.
963 ) -> Style
<T
, B
, L
, (), H
, V
, HorizontalLineIter
<HLines
::IntoIter
>, VLines
>
965 HLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
967 self.borders
.right
= None
;
968 self.borders
.right_intersection
= None
;
969 self.borders
.top_right
= None
;
970 self.borders
.bottom_right
= None
;
972 let iter
= HorizontalLineIter
::new(self.horizontals
.into_iter(), false, false, true);
973 Style
::new(self.borders
, iter
, self.verticals
)
977 impl<T
, B
, L
, R
, V
, HLines
, VLines
> Style
<T
, B
, L
, R
, On
, V
, HLines
, VLines
> {
978 /// Removes horizontal split lines.
980 /// Not including custom split lines.
981 pub fn remove_horizontal(
983 ) -> Style
<T
, B
, L
, R
, (), V
, HLines
, VerticalLineIter
<VLines
::IntoIter
>>
985 VLines
: IntoIterator
<Item
= VerticalLine
> + Clone
,
987 self.borders
.horizontal
= None
;
988 self.borders
.left_intersection
= None
;
989 self.borders
.right_intersection
= None
;
990 self.borders
.intersection
= None
;
992 let iter
= VerticalLineIter
::new(self.verticals
.into_iter(), true, false, false);
993 Style
::new(self.borders
, self.horizontals
, iter
)
997 impl<T
, B
, L
, R
, H
, HLines
, VLines
> Style
<T
, B
, L
, R
, H
, On
, HLines
, VLines
> {
998 /// Removes vertical split lines.
999 pub fn remove_vertical(
1001 ) -> Style
<T
, B
, L
, R
, H
, (), HorizontalLineIter
<HLines
::IntoIter
>, VLines
>
1003 HLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
1005 self.borders
.vertical
= None
;
1006 self.borders
.top_intersection
= None
;
1007 self.borders
.bottom_intersection
= None
;
1008 self.borders
.intersection
= None
;
1010 let iter
= HorizontalLineIter
::new(self.horizontals
.into_iter(), true, false, false);
1011 Style
::new(self.borders
, iter
, self.verticals
)
1015 impl<T
, B
, L
, R
, H
, V
, HLines
, VLines
> Style
<T
, B
, L
, R
, H
, V
, HLines
, VLines
> {
1016 const fn new(borders
: Borders
<char>, horizontals
: HLines
, verticals
: VLines
) -> Self {
1022 _bottom
: PhantomData
,
1024 _right
: PhantomData
,
1025 _horizontal
: PhantomData
,
1026 _vertical
: PhantomData
,
1030 /// Return borders of a table.
1031 pub const fn get_borders(&self) -> &Borders
<char> {
1035 /// Return custom horizontals which were set.
1036 pub const fn get_horizontals(&self) -> &HLines
{
1040 /// Return custom verticals which were set.
1041 pub const fn get_verticals(&self) -> &VLines
{
1046 #[cfg(feature = "std")]
1047 impl<T
, B
, L
, R
, H
, V
, HLines
, VLines
, I
, D
> TableOption
<I
, D
, ColoredConfig
>
1048 for Style
<T
, B
, L
, R
, H
, V
, HLines
, VLines
>
1050 HLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
1051 VLines
: IntoIterator
<Item
= VerticalLine
> + Clone
,
1053 fn change(self, records
: &mut I
, cfg
: &mut ColoredConfig
, dimension
: &mut D
) {
1056 cfg
.set_borders(self.borders
);
1058 for hl
in self.horizontals
{
1059 hl
.change(records
, cfg
, dimension
);
1062 for vl
in self.verticals
{
1063 vl
.change(records
, cfg
, dimension
);
1068 impl<T
, B
, L
, R
, H
, V
, HLines
, VLines
, I
, D
> TableOption
<I
, D
, CompactConfig
>
1069 for Style
<T
, B
, L
, R
, H
, V
, HLines
, VLines
>
1071 HLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
1073 fn change(self, records
: &mut I
, cfg
: &mut CompactConfig
, dimension
: &mut D
) {
1074 *cfg
= cfg
.set_borders(self.borders
);
1076 let first_line
= self.horizontals
.into_iter().next();
1077 if let Some(line
) = first_line
{
1078 line
.change(records
, cfg
, dimension
);
1083 impl<T
, B
, L
, R
, H
, V
, HLines
, VLines
, I
, D
> TableOption
<I
, D
, CompactMultilineConfig
>
1084 for Style
<T
, B
, L
, R
, H
, V
, HLines
, VLines
>
1086 HLines
: IntoIterator
<Item
= HorizontalLine
> + Clone
,
1088 fn change(self, records
: &mut I
, cfg
: &mut CompactMultilineConfig
, dimension
: &mut D
) {
1089 self.change(records
, cfg
.as_mut(), dimension
)
1093 /// An iterator which limits [`Line`] influence on iterations over lines for in [`Style`].
1094 #[derive(Debug, Clone)]
1095 pub struct HorizontalLineIter
<I
> {
1102 impl<I
> HorizontalLineIter
<I
> {
1103 fn new(iter
: I
, intersection
: bool
, left
: bool
, right
: bool
) -> Self {
1113 impl<I
> Iterator
for HorizontalLineIter
<I
>
1115 I
: Iterator
<Item
= HorizontalLine
>,
1117 type Item
= HorizontalLine
;
1119 fn next(&mut self) -> Option
<Self::Item
> {
1120 let mut hl
= self.iter
.next()?
;
1122 if self.intersection
{
1123 hl
.line
.intersection
= None
;
1127 hl
.line
.connector1
= None
;
1131 hl
.line
.connector2
= None
;
1138 /// An iterator which limits [`Line`] influence on iterations over lines for in [`Style`].
1139 #[derive(Debug, Clone)]
1140 pub struct VerticalLineIter
<I
> {
1147 impl<I
> VerticalLineIter
<I
> {
1148 fn new(iter
: I
, intersection
: bool
, top
: bool
, bottom
: bool
) -> Self {
1158 impl<I
> Iterator
for VerticalLineIter
<I
>
1160 I
: Iterator
<Item
= VerticalLine
>,
1162 type Item
= VerticalLine
;
1164 fn next(&mut self) -> Option
<Self::Item
> {
1165 let mut hl
= self.iter
.next()?
;
1167 if self.intersection
{
1168 hl
.line
.intersection
= None
;
1172 hl
.line
.connector1
= None
;
1176 hl
.line
.connector2
= None
;
1183 const fn create_borders(
1188 right
: Option
<char>,
1189 vertical
: Option
<char>,
1190 ) -> Borders
<char> {
1193 bottom
: bottom
.main
,
1194 top_left
: top
.connector1
,
1195 top_right
: top
.connector2
,
1196 bottom_left
: bottom
.connector1
,
1197 bottom_right
: bottom
.connector2
,
1198 top_intersection
: top
.intersection
,
1199 bottom_intersection
: bottom
.intersection
,
1200 left_intersection
: horizontal
.connector1
,
1201 right_intersection
: horizontal
.connector2
,
1202 horizontal
: horizontal
.main
,
1203 intersection
: horizontal
.intersection
,