1 | use 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 | |
15 | use super::util::get_table_height; |
16 | |
17 | /// A modification of a table to decrease the table height. |
18 | #[derive (Debug)] |
19 | pub struct TableHeightLimit<W = usize, P = PriorityNone> { |
20 | height: W, |
21 | priority: P, |
22 | } |
23 | |
24 | impl<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 | |
48 | impl<R, W, P> TableOption<R, CompleteDimensionVecRecords<'static>, ColoredConfig> |
49 | for TableHeightLimit<W, P> |
50 | where |
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 | |
96 | fn decrease_list<P>(list: &mut [usize], total: usize, mut value: usize, mut peaker: P) |
97 | where |
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 | |
112 | fn 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 | |