aopt_help/
wrapper.rs

1use crate::style::{Align, Style};
2use std::borrow::Cow;
3use textwrap::{core::display_width, wrap};
4
5#[derive(Debug, Default)]
6pub struct Wrapped<'a> {
7    cows: Vec<Cow<'a, str>>,
8
9    style: Style,
10}
11
12impl<'a> Wrapped<'a> {
13    pub fn new(cows: Vec<Cow<'a, str>>, style: Style) -> Self {
14        Self { cows, style }
15    }
16
17    pub fn get_style(&self) -> &Style {
18        &self.style
19    }
20
21    pub fn set_wrap_width(&mut self, width: usize) {
22        self.style.wrap_width = width;
23    }
24
25    pub fn get_wrap_width(&self) -> usize {
26        self.style.wrap_width
27    }
28
29    pub fn get_line(&self, line: usize) -> String {
30        let padding_str = String::from(self.style.padding_char);
31
32        if line < self.cows.len() {
33            let mut ret = " ".repeat(self.style.indent);
34            let real_width = display_width(self.cows[line].as_ref());
35            let padding_width = self.get_wrap_width() - real_width;
36
37            ret += self.cows[line].as_ref();
38            match self.style.align {
39                Align::Left => {
40                    ret += &padding_str.repeat(padding_width);
41                }
42                Align::Right => {
43                    ret = padding_str.repeat(padding_width) + &ret;
44                }
45            }
46            ret
47        } else {
48            format!(
49                "{}{}",
50                " ".repeat(self.style.indent),
51                padding_str.repeat(self.get_wrap_width())
52            )
53        }
54    }
55
56    pub fn len(&self) -> usize {
57        self.cows.len()
58    }
59
60    pub fn is_empty(&self) -> bool {
61        self.len() == 0
62    }
63}
64
65#[derive(Debug)]
66pub struct Wrapper<'a, 'b> {
67    data: &'a [Vec<Cow<'b, str>>],
68
69    output: Vec<Vec<Wrapped<'b>>>,
70}
71
72impl<'a, 'b> Wrapper<'a, 'b>
73where
74    'a: 'b,
75{
76    pub fn new(data: &'a [Vec<Cow<'b, str>>]) -> Self {
77        Self {
78            data,
79            output: vec![],
80        }
81    }
82
83    pub fn wrap(&mut self, max_width: usize) {
84        let data_len = self.data.iter().map(|v| v.len()).max().unwrap_or(0);
85        let mut default_style = vec![Style::default(); data_len];
86
87        for line in self.data.iter() {
88            for (style_mut, col) in default_style.iter_mut().zip(line.iter()) {
89                let width = display_width(col);
90
91                if style_mut.wrap_width < width {
92                    style_mut.wrap_width = if max_width != 0 && width > max_width {
93                        max_width
94                    } else {
95                        width
96                    };
97                }
98            }
99        }
100
101        for line in self.data.iter() {
102            let mut wrapped = vec![];
103
104            for (col, style) in line.iter().zip(default_style.iter()) {
105                wrapped.push(Wrapped::new(wrap(col, style.wrap_width), style.clone()));
106            }
107
108            self.output.push(wrapped);
109        }
110    }
111
112    /// Modify wrap_width if wrap_width is 0
113    pub fn wrap_with(&mut self, styles: &[Style], max_width: usize) {
114        let mut styles = styles.to_owned();
115        let status: Vec<bool> = styles.iter().map(|v| v.wrap_width == 0).collect();
116
117        for (line, status) in self.data.iter().zip(status.iter()) {
118            if *status {
119                for (style_mut, col) in styles.iter_mut().zip(line.iter()) {
120                    let width = display_width(col);
121
122                    if style_mut.wrap_width < width {
123                        style_mut.wrap_width = if max_width != 0 && width > max_width {
124                            max_width
125                        } else {
126                            width
127                        };
128                    }
129                }
130            }
131        }
132
133        for line in self.data.iter() {
134            let mut wrapped = vec![];
135
136            for (col, style) in line.iter().zip(styles.iter()) {
137                wrapped.push(Wrapped::new(wrap(col, style.wrap_width), style.clone()));
138            }
139            self.output.push(wrapped);
140        }
141    }
142
143    pub fn get_output(&self) -> &Vec<Vec<Wrapped<'b>>> {
144        &self.output
145    }
146
147    pub fn len(&self) -> usize {
148        self.output.len()
149    }
150
151    pub fn is_empty(&self) -> bool {
152        self.len() == 0
153    }
154}