tabled/settings/height/
cell_height_limit.rs

1use crate::{
2    grid::{
3        config::{ColoredConfig, Entity, Position},
4        dimension::CompleteDimension,
5        records::{ExactRecords, IntoRecords, PeekableRecords, Records, RecordsMut},
6        util::string::{count_lines, get_lines},
7    },
8    settings::{measurement::Measurement, peaker::Peaker, CellOption, Height, TableOption},
9};
10
11use super::table_height_limit::TableHeightLimit;
12
13/// A modification for cell/table to increase its height.
14///
15/// If used for a [`Table`] [`PriorityNone`] is used.
16///
17/// [`PriorityNone`]: crate::settings::peaker::PriorityNone
18/// [`Table`]: crate::Table
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
20pub struct CellHeightLimit<W = usize> {
21    height: W,
22}
23
24impl<W> CellHeightLimit<W> {
25    /// Constructs a new object.
26    pub fn new(height: W) -> Self
27    where
28        W: Measurement<Height>,
29    {
30        Self { height }
31    }
32
33    /// Set's a priority by which the limit logic will be applied.
34    pub fn priority<P>(self, priority: P) -> TableHeightLimit<W, P>
35    where
36        P: Peaker,
37        W: Measurement<Height>,
38    {
39        TableHeightLimit::new(self.height).priority(priority)
40    }
41}
42
43impl<W, R> CellOption<R, ColoredConfig> for CellHeightLimit<W>
44where
45    W: Measurement<Height>,
46    R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
47    for<'a> &'a R: Records,
48    for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
49{
50    fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
51        let height = self.height.measure(&*records, cfg);
52
53        let count_rows = records.count_rows();
54        let count_columns = records.count_columns();
55        let max_pos = Position::new(count_rows, count_columns);
56
57        for pos in entity.iter(count_rows, count_columns) {
58            if !max_pos.has_coverage(pos) {
59                continue;
60            }
61
62            let text = records.get_text(pos);
63            let count_lines = count_lines(text);
64
65            if count_lines <= height {
66                continue;
67            }
68
69            let content = limit_lines(text, height);
70            records.set(pos, content);
71        }
72    }
73}
74
75impl<R, W> TableOption<R, ColoredConfig, CompleteDimension> for CellHeightLimit<W>
76where
77    W: Measurement<Height>,
78    R: Records + ExactRecords + PeekableRecords + RecordsMut<String>,
79    for<'a> &'a R: Records,
80    for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
81{
82    fn change(self, records: &mut R, cfg: &mut ColoredConfig, dims: &mut CompleteDimension) {
83        let height = self.height.measure(&*records, cfg);
84        TableHeightLimit::new(height).change(records, cfg, dims)
85    }
86
87    fn hint_change(&self) -> Option<Entity> {
88        TableHeightLimit::new(0).hint_change()
89    }
90}
91
92fn limit_lines(s: &str, n: usize) -> String {
93    let mut text = String::new();
94    for (i, line) in get_lines(s).take(n).enumerate() {
95        if i > 0 {
96            text.push('\n');
97        }
98
99        text.push_str(&line);
100    }
101
102    text
103}