1use crate::{
2 grid::{
3 config::ColoredConfig,
4 dimension::CompleteDimensionVecRecords,
5 records::{ExactRecords, IntoRecords, PeekableRecords, Records, RecordsMut},
6 util::string::{count_lines, get_lines},
7 },
8 settings::{
9 measurement::Measurement,
10 peaker::{Peaker, PriorityNone},
11 Height, TableOption,
12 },
13};
14
15use super::util::get_table_height;
16
17/// A modification of a table to decrease the table height.
18#[derive(Debug)]
19pub struct TableHeightLimit<W = usize, P = PriorityNone> {
20 height: W,
21 priority: P,
22}
23
24impl<W> TableHeightLimit<W, PriorityNone> {
25 /// Creates a new object.
26 pub fn new(height: W) -> Self
27 where
28 W: Measurement<Height>,
29 {
30 Self {
31 height,
32 priority: PriorityNone::default(),
33 }
34 }
35
36 /// Sets a different priority logic.
37 pub fn priority<P>(self) -> TableHeightLimit<W, P>
38 where
39 P: Peaker,
40 {
41 TableHeightLimit {
42 priority: P::create(),
43 height: self.height,
44 }
45 }
46}
47
48impl<R, W, P> TableOption<R, ColoredConfig, CompleteDimensionVecRecords<'_>>
49 for TableHeightLimit<W, P>
50where
51 W: Measurement<Height>,
52 P: Peaker + Clone,
53 R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
54 for<'a> &'a R: Records,
55 for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
56{
57 fn change(
58 self,
59 records: &mut R,
60 cfg: &mut ColoredConfig,
61 dims: &mut CompleteDimensionVecRecords<'_>,
62 ) {
63 let count_rows = records.count_rows();
64 let count_cols = records.count_columns();
65
66 if count_rows == 0 || count_cols == 0 {
67 return;
68 }
69
70 let height = self.height.measure(&*records, cfg);
71 let (total, mut heights) = get_table_height(&*records, cfg);
72 if total <= height {
73 return;
74 }
75
76 decrease_list(&mut heights, total, height, self.priority);
77
78 for (row, &height) in heights.iter().enumerate() {
79 for col in 0..count_cols {
80 let text = records.get_text((row, col));
81 let count_lines = count_lines(text);
82
83 if count_lines <= height {
84 continue;
85 }
86
87 let text = limit_lines(text, height);
88
89 records.set((row, col), text);
90 }
91 }
92
93 dims.set_heights(heights);
94 }
95}
96
97fn decrease_list<P>(list: &mut [usize], total: usize, mut value: usize, mut peaker: P)
98where
99 P: Peaker,
100{
101 while value != total {
102 let p: Option = peaker.peak(&[], widths:list);
103 let row: usize = match p {
104 Some(row: usize) => row,
105 None => break,
106 };
107
108 list[row] -= 1;
109 value += 1;
110 }
111}
112
113fn limit_lines(s: &str, n: usize) -> String {
114 let mut text: String = String::new();
115 for (i: usize, line: Cow<'_, str>) in get_lines(text:s).take(n).enumerate() {
116 if i > 0 {
117 text.push(ch:'\n');
118 }
119
120 text.push_str(&line);
121 }
122
123 text
124}
125