tabled/settings/formatting/
alignment_strategy.rs

1use crate::{
2    grid::config::{ColoredConfig, CompactMultilineConfig, Entity},
3    settings::{CellOption, TableOption},
4};
5
6/// `AlignmentStrategy` is a responsible for a flow how we apply an alignment.
7/// It mostly matters for multiline strings.
8///
9/// # Examples
10///
11/// ```
12/// use tabled::{
13///     Table,
14///     settings::{
15///         Style, Modify, Alignment, object::Segment,
16///         formatting::{AlignmentStrategy, TrimStrategy}
17///     }
18/// };
19///
20/// // sample_from: https://opensource.adobe.com/Spry/samples/data_region/JSONDataSetSample.html
21/// let json = r#"
22/// {
23///     "id": "0001",
24///     "type": "donut",
25///     "name": "Cake",
26///     "ppu": 0.55,
27///     "batters": {
28///         "batter": [
29///             { "id": "1001", "type": "Regular" },
30///             { "id": "1002", "type": "Chocolate" },
31///         ]
32///     },
33///     "topping": [
34///         { "id": "5001", "type": "None" },
35///         { "id": "5006", "type": "Chocolate with Sprinkles" },
36///         { "id": "5003", "type": "Chocolate" },
37///         { "id": "5004", "type": "Maple" }
38///     ]
39/// }"#;
40///
41/// let mut table = Table::new(&[json]);
42/// table
43///     .with(Style::modern())
44///     .with(Modify::new(Segment::all()).with(Alignment::right()))
45///     .with(Modify::new(Segment::all()).with(TrimStrategy::None));
46///
47/// println!("{}", table);
48///
49/// assert_eq!(
50///     format!("\n{}", table),
51///     r#"
52/// ┌───────────────────────────────────────────────────────────────┐
53/// │                                                          &str │
54/// ├───────────────────────────────────────────────────────────────┤
55/// │                                                               │
56/// │ {                                                             │
57/// │     "id": "0001",                                             │
58/// │     "type": "donut",                                          │
59/// │     "name": "Cake",                                           │
60/// │     "ppu": 0.55,                                              │
61/// │     "batters": {                                              │
62/// │         "batter": [                                           │
63/// │             { "id": "1001", "type": "Regular" },              │
64/// │             { "id": "1002", "type": "Chocolate" },            │
65/// │         ]                                                     │
66/// │     },                                                        │
67/// │     "topping": [                                              │
68/// │         { "id": "5001", "type": "None" },                     │
69/// │         { "id": "5006", "type": "Chocolate with Sprinkles" }, │
70/// │         { "id": "5003", "type": "Chocolate" },                │
71/// │         { "id": "5004", "type": "Maple" }                     │
72/// │     ]                                                         │
73/// │ }                                                             │
74/// └───────────────────────────────────────────────────────────────┘"#);
75///
76/// table
77///     .with(Modify::new(Segment::all()).with(AlignmentStrategy::PerCell))
78///     .with(Modify::new(Segment::all()).with(TrimStrategy::Horizontal));
79///
80/// assert_eq!(
81///     format!("\n{}", table),
82///     r#"
83/// ┌───────────────────────────────────────────────────────────────┐
84/// │                                                          &str │
85/// ├───────────────────────────────────────────────────────────────┤
86/// │                                                               │
87/// │         {                                                     │
88/// │         "id": "0001",                                         │
89/// │         "type": "donut",                                      │
90/// │         "name": "Cake",                                       │
91/// │         "ppu": 0.55,                                          │
92/// │         "batters": {                                          │
93/// │         "batter": [                                           │
94/// │         { "id": "1001", "type": "Regular" },                  │
95/// │         { "id": "1002", "type": "Chocolate" },                │
96/// │         ]                                                     │
97/// │         },                                                    │
98/// │         "topping": [                                          │
99/// │         { "id": "5001", "type": "None" },                     │
100/// │         { "id": "5006", "type": "Chocolate with Sprinkles" }, │
101/// │         { "id": "5003", "type": "Chocolate" },                │
102/// │         { "id": "5004", "type": "Maple" }                     │
103/// │         ]                                                     │
104/// │         }                                                     │
105/// └───────────────────────────────────────────────────────────────┘"#);
106///
107/// table.with(Modify::new(Segment::all()).with(AlignmentStrategy::PerLine));
108///
109/// assert_eq!(
110///     format!("\n{}", table),
111///     r#"
112/// ┌───────────────────────────────────────────────────────────────┐
113/// │                                                          &str │
114/// ├───────────────────────────────────────────────────────────────┤
115/// │                                                               │
116/// │                                                             { │
117/// │                                                 "id": "0001", │
118/// │                                              "type": "donut", │
119/// │                                               "name": "Cake", │
120/// │                                                  "ppu": 0.55, │
121/// │                                                  "batters": { │
122/// │                                                   "batter": [ │
123/// │                          { "id": "1001", "type": "Regular" }, │
124/// │                        { "id": "1002", "type": "Chocolate" }, │
125/// │                                                             ] │
126/// │                                                            }, │
127/// │                                                  "topping": [ │
128/// │                             { "id": "5001", "type": "None" }, │
129/// │         { "id": "5006", "type": "Chocolate with Sprinkles" }, │
130/// │                        { "id": "5003", "type": "Chocolate" }, │
131/// │                             { "id": "5004", "type": "Maple" } │
132/// │                                                             ] │
133/// │                                                             } │
134/// └───────────────────────────────────────────────────────────────┘"#);
135/// ```
136#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
137pub enum AlignmentStrategy {
138    /// Apply alignment for cell content as a whole.
139    PerCell,
140    /// Apply alignment for each line of a cell content as a whole.
141    PerLine,
142}
143
144impl<R> CellOption<R, ColoredConfig> for AlignmentStrategy {
145    fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
146        let on = match &self {
147            AlignmentStrategy::PerCell => false,
148            AlignmentStrategy::PerLine => true,
149        };
150
151        cfg.set_line_alignment(entity, on);
152    }
153}
154
155impl<R, D> TableOption<R, ColoredConfig, D> for AlignmentStrategy {
156    fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
157        <Self as CellOption<R, ColoredConfig>>::change(self, records, cfg, Entity::Global)
158    }
159
160    fn hint_change(&self) -> Option<Entity> {
161        None
162    }
163}
164
165impl<R, D> TableOption<R, CompactMultilineConfig, D> for AlignmentStrategy {
166    fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) {
167        let mut f = cfg.get_formatting();
168        match &self {
169            AlignmentStrategy::PerCell => f.allow_lines_alignment = false,
170            AlignmentStrategy::PerLine => f.allow_lines_alignment = true,
171        }
172
173        cfg.set_formatting(f);
174    }
175
176    fn hint_change(&self) -> Option<Entity> {
177        None
178    }
179}