tabled/features/
merge.rs

1//! The module contains a set of methods to merge cells together via [`Span`]s.
2//!
3//! [`Span`]: crate::Span
4
5use crate::{papergrid::records::Records, Table, TableOption};
6
7/// Merge to combine duplicates together, using [`Span`].
8///
9/// [`Span`]: crate::Span
10#[derive(Debug)]
11pub struct Merge;
12
13impl Merge {
14    /// Vertical merge.
15    pub fn vertical() -> MergeDuplicatesVertical {
16        MergeDuplicatesVertical
17    }
18
19    /// Horizontal merge.
20    pub fn horizontal() -> MergeDuplicatesHorizontal {
21        MergeDuplicatesHorizontal
22    }
23}
24
25/// A modificator for [`Table`] which looks up for duplicates in columns and
26/// in case of duplicate merges the cells together using [`Span`].
27///
28/// [`Table`]: crate::Table
29/// [`Span`]: crate::Span
30#[derive(Debug)]
31pub struct MergeDuplicatesVertical;
32
33impl<R> TableOption<R> for MergeDuplicatesVertical
34where
35    R: Records,
36{
37    fn change(&mut self, table: &mut Table<R>) {
38        if table.is_empty() {
39            return;
40        }
41
42        for column in 0..table.get_records().count_columns() {
43            let mut repeat_length = 0;
44            let mut repeat_value = String::new();
45            let mut repeat_is_set = false;
46            let mut last_is_row_span = false;
47            for row in (0..table.get_records().count_rows()).rev() {
48                if last_is_row_span {
49                    last_is_row_span = false;
50                    continue;
51                }
52
53                // we need to mitigate messing existing spans
54                let is_cell_visible = table
55                    .get_config()
56                    .is_cell_visible((row, column), table.shape());
57
58                let is_row_span_cell = table
59                    .get_config()
60                    .get_column_span((row, column), table.shape())
61                    .is_some();
62
63                if !repeat_is_set {
64                    if !is_cell_visible {
65                        continue;
66                    }
67
68                    if is_row_span_cell {
69                        continue;
70                    }
71
72                    repeat_length = 1;
73                    repeat_value = table.get_records().get_text((row, column)).to_owned();
74                    repeat_is_set = true;
75                    continue;
76                }
77
78                if is_row_span_cell {
79                    repeat_is_set = false;
80                    last_is_row_span = true;
81                    continue;
82                }
83
84                if !is_cell_visible {
85                    repeat_is_set = false;
86                    continue;
87                }
88
89                let text = table.get_records().get_text((row, column));
90                let is_duplicate = text == repeat_value;
91
92                if is_duplicate {
93                    repeat_length += 1;
94                    continue;
95                }
96
97                if repeat_length > 1 {
98                    table
99                        .get_config_mut()
100                        .set_row_span((row + 1, column), repeat_length);
101                }
102
103                repeat_length = 1;
104                repeat_value = table.get_records().get_text((row, column)).to_owned();
105            }
106
107            if repeat_length > 1 {
108                table
109                    .get_config_mut()
110                    .set_row_span((0, column), repeat_length);
111            }
112        }
113
114        table.destroy_width_cache();
115        table.destroy_height_cache();
116    }
117}
118
119/// A modificator for [`Table`] which looks up for duplicates in rows and
120/// in case of duplicate merges the cells together using [`Span`].
121///
122/// [`Table`]: crate::Table
123/// [`Span`]: crate::Span
124#[derive(Debug)]
125pub struct MergeDuplicatesHorizontal;
126
127impl<R> TableOption<R> for MergeDuplicatesHorizontal
128where
129    R: Records,
130{
131    fn change(&mut self, table: &mut Table<R>) {
132        if table.is_empty() {
133            return;
134        }
135
136        for row in 0..table.get_records().count_rows() {
137            let mut repeat_length = 0;
138            let mut repeat_value = String::new();
139            let mut repeat_is_set = false;
140            let mut last_is_col_span = false;
141            for column in (0..table.get_records().count_columns()).rev() {
142                if last_is_col_span {
143                    last_is_col_span = false;
144                    continue;
145                }
146
147                // we need to mitigate messing existing spans
148                let is_cell_visible = table
149                    .get_config()
150                    .is_cell_visible((row, column), table.shape());
151
152                let is_col_span_cell = table
153                    .get_config()
154                    .get_row_span((row, column), table.shape())
155                    .is_some();
156
157                if !repeat_is_set {
158                    if !is_cell_visible {
159                        continue;
160                    }
161
162                    if is_col_span_cell {
163                        continue;
164                    }
165
166                    repeat_length = 1;
167                    repeat_value = table.get_records().get_text((row, column)).to_owned();
168                    repeat_is_set = true;
169                    continue;
170                }
171
172                if is_col_span_cell {
173                    repeat_is_set = false;
174                    last_is_col_span = true;
175                    continue;
176                }
177
178                if !is_cell_visible {
179                    repeat_is_set = false;
180                    continue;
181                }
182
183                let text = table.get_records().get_text((row, column));
184                let is_duplicate = text == repeat_value;
185
186                if is_duplicate {
187                    repeat_length += 1;
188                    continue;
189                }
190
191                if repeat_length > 1 {
192                    table
193                        .get_config_mut()
194                        .set_column_span((row, column + 1), repeat_length);
195                }
196
197                repeat_length = 1;
198                repeat_value = table.get_records().get_text((row, column)).to_owned();
199            }
200
201            if repeat_length > 1 {
202                table
203                    .get_config_mut()
204                    .set_column_span((row, 0), repeat_length);
205            }
206        }
207
208        table.destroy_width_cache();
209        table.destroy_height_cache();
210    }
211}