1 | use 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 | |
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, ColoredConfig, CompleteDimensionVecRecords<'_>> |
49 | for TableHeightLimit<W, P> |
50 | where |
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 | |
97 | fn decrease_list<P>(list: &mut [usize], total: usize, mut value: usize, mut peaker: P) |
98 | where |
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 | |
113 | fn 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 | |