1use crate::{
2 grid::{
3 config::ColoredConfig,
4 dimension::CompleteDimensionVecRecords,
5 records::{ExactRecords, 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, CompleteDimensionVecRecords<'static>, ColoredConfig>
49 for TableHeightLimit<W, P>
50where
51 W: Measurement<Height>,
52 P: Peaker + Clone,
53 R: ExactRecords + PeekableRecords + RecordsMut<String>,
54 for<'a> &'a R: Records,
55{
56 fn change(
57 self,
58 records: &mut R,
59 cfg: &mut ColoredConfig,
60 dims: &mut CompleteDimensionVecRecords<'static>,
61 ) {
62 let count_rows = records.count_rows();
63 let count_cols = (&*records).count_columns();
64
65 if count_rows == 0 || count_cols == 0 {
66 return;
67 }
68
69 let height = self.height.measure(&*records, cfg);
70 let (total, mut heights) = get_table_height(&*records, cfg);
71 if total <= height {
72 return;
73 }
74
75 decrease_list(&mut heights, total, height, self.priority);
76
77 for (row, &height) in heights.iter().enumerate() {
78 for col in 0..count_cols {
79 let text = records.get_text((row, col));
80 let count_lines = count_lines(text);
81
82 if count_lines <= height {
83 continue;
84 }
85
86 let text = limit_lines(text, height);
87
88 records.set((row, col), text);
89 }
90 }
91
92 let _ = dims.set_heights(heights);
93 }
94}
95
96fn decrease_list<P>(list: &mut [usize], total: usize, mut value: usize, mut peaker: P)
97where
98 P: Peaker,
99{
100 while value != total {
101 let p: Option = peaker.peak(&[], widths:list);
102 let row: usize = match p {
103 Some(row: usize) => row,
104 None => break,
105 };
106
107 list[row] -= 1;
108 value += 1;
109 }
110}
111
112fn limit_lines(s: &str, n: usize) -> String {
113 let mut text: String = String::new();
114 for (i: usize, line: Cow<'_, str>) in get_lines(text:s).take(n).enumerate() {
115 if i > 0 {
116 text.push(ch:'\n');
117 }
118
119 text.push_str(&line);
120 }
121
122 text
123}
124