1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! The module contains [`TruncateContent`] records iterator.

use crate::{
    grid::dimension::Dimension, grid::records::into_records::either_string::EitherString,
    grid::records::IntoRecords, grid::util::string::string_width_multiline,
    settings::width::Truncate,
};

/// A records iterator which truncates all cells to a given width.
#[derive(Debug)]
pub struct TruncateContent<I, D> {
    records: I,
    dimension: D,
}

impl TruncateContent<(), ()> {
    /// Creates new [`TruncateContent`] object.
    pub fn new<I, D>(records: I, dimension: D) -> TruncateContent<I, D> {
        TruncateContent { records, dimension }
    }
}

impl<I, D> IntoRecords for TruncateContent<I, D>
where
    I: IntoRecords,
    I::Cell: AsRef<str>,
    D: Clone + Dimension,
{
    type Cell = EitherString<I::Cell>;
    type IterColumns = TruncateContentColumnsIter<<I::IterColumns as IntoIterator>::IntoIter, D>;
    type IterRows = TruncateContentIter<<I::IterRows as IntoIterator>::IntoIter, D>;

    fn iter_rows(self) -> Self::IterRows {
        TruncateContentIter {
            iter: self.records.iter_rows().into_iter(),
            dimension: self.dimension.clone(),
        }
    }
}

/// A row iterator for [`TruncateContent`].
#[derive(Debug)]
pub struct TruncateContentIter<I, D> {
    iter: I,
    dimension: D,
}

impl<I, D> Iterator for TruncateContentIter<I, D>
where
    I: Iterator,
    I::Item: IntoIterator,
    D: Clone,
{
    type Item = TruncateContentColumnsIter<<I::Item as IntoIterator>::IntoIter, D>;

    fn next(&mut self) -> Option<Self::Item> {
        let iter = self.iter.next()?;
        let iter = TruncateContentColumnsIter {
            iter: iter.into_iter(),
            iter_column: 0,
            dimension: self.dimension.clone(),
        };

        Some(iter)
    }
}

/// A column iterator for [`TruncateContent`].
#[derive(Debug)]
pub struct TruncateContentColumnsIter<I, D> {
    iter: I,
    dimension: D,
    iter_column: usize,
}

impl<I, D> Iterator for TruncateContentColumnsIter<I, D>
where
    I: Iterator,
    I::Item: AsRef<str>,
    D: Dimension,
{
    type Item = EitherString<I::Item>;

    fn next(&mut self) -> Option<Self::Item> {
        let text = self.iter.next()?;
        let text_ref = text.as_ref();

        let width = self.dimension.get_width(self.iter_column);
        self.iter_column += 1;

        let text_width = string_width_multiline(text_ref);
        let is_small = text_width <= width;
        if is_small {
            Some(EitherString::Some(text))
        } else {
            let text = Truncate::truncate_text(text_ref, width);
            let text = text.into_owned();
            Some(EitherString::Owned(text))
        }
    }
}