tabled/settings/height/
table_height_limit.rs1use crate::{
2 grid::{
3 config::{ColoredConfig, Entity},
4 dimension::CompleteDimension,
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#[derive(Debug)]
19pub struct TableHeightLimit<W = usize, P = PriorityNone> {
20 height: W,
21 priority: P,
22}
23
24impl<W> TableHeightLimit<W, PriorityNone> {
25 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 pub fn priority<P>(self, priority: P) -> TableHeightLimit<W, P>
38 where
39 P: Peaker,
40 {
41 TableHeightLimit {
42 priority,
43 height: self.height,
44 }
45 }
46}
47
48impl<R, W, P> TableOption<R, ColoredConfig, CompleteDimension> for TableHeightLimit<W, P>
49where
50 W: Measurement<Height>,
51 P: Peaker + Clone,
52 R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
53 for<'a> &'a R: Records,
54 for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
55{
56 fn change(self, records: &mut R, cfg: &mut ColoredConfig, dims: &mut CompleteDimension) {
57 let count_rows = records.count_rows();
58 let count_cols = records.count_columns();
59
60 if count_rows == 0 || count_cols == 0 {
61 return;
62 }
63
64 let height = self.height.measure(&*records, cfg);
65 let (total, mut heights) = get_table_height(&*records, cfg);
66 if total <= height {
67 return;
68 }
69
70 decrease_list(&mut heights, total, height, self.priority);
71
72 for (row, &height) in heights.iter().enumerate() {
73 for col in 0..count_cols {
74 let text = records.get_text((row, col).into());
75 let count_lines = count_lines(text);
76
77 if count_lines <= height {
78 continue;
79 }
80
81 let text = limit_lines(text, height);
82
83 records.set((row, col).into(), text);
84 }
85 }
86
87 dims.set_heights(heights);
88 }
89
90 fn hint_change(&self) -> Option<Entity> {
91 None
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 = peaker.peak(&[], list);
103 let row = match p {
104 Some(row) => 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::new();
115 for (i, line) in get_lines(s).take(n).enumerate() {
116 if i > 0 {
117 text.push('\n');
118 }
119
120 text.push_str(&line);
121 }
122
123 text
124}