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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::style::{Alignment, Style};
use std::borrow::Cow;
use textwrap::{core::display_width, wrap};

#[derive(Debug, Default)]
pub struct Wrapped<'a> {
    cows: Vec<Cow<'a, str>>,

    style: Style,
}

impl<'a> Wrapped<'a> {
    pub fn new(cows: Vec<Cow<'a, str>>, style: Style) -> Self {
        Self { cows, style }
    }

    pub fn get_style(&self) -> &Style {
        &self.style
    }

    pub fn set_wrap_width(&mut self, width: usize) {
        self.style.wrap_width = width;
    }

    pub fn get_wrap_width(&self) -> usize {
        self.style.wrap_width
    }

    pub fn get_line(&self, line: usize) -> String {
        let padding_str = String::from(self.style.padding_char);

        if line < self.cows.len() {
            let mut ret = " ".repeat(self.style.indent);
            let real_width = display_width(self.cows[line].as_ref());
            let padding_width = self.get_wrap_width() - real_width;

            ret += self.cows[line].as_ref();
            match self.style.align {
                Alignment::Left => {
                    ret += &padding_str.repeat(padding_width);
                }
                Alignment::Right => {
                    ret = padding_str.repeat(padding_width) + &ret;
                }
            }
            ret
        } else {
            format!(
                "{}{}",
                " ".repeat(self.style.indent),
                padding_str.repeat(self.get_wrap_width())
            )
        }
    }

    pub fn len(&self) -> usize {
        self.cows.len()
    }
}

#[derive(Debug)]
pub struct Wrapper<'a, 'b> {
    data: &'a Vec<Vec<&'b str>>,

    output: Vec<Vec<Wrapped<'b>>>,
}

impl<'a, 'b> Wrapper<'a, 'b> {
    pub fn new(data: &'a Vec<Vec<&'b str>>) -> Self {
        Self {
            data,
            output: vec![],
        }
    }

    pub fn wrap(&mut self) {
        let data_len = self.data.iter().map(|v| v.len()).max().unwrap_or(0);
        let mut default_style = vec![Style::default(); data_len];

        for line in self.data.iter() {
            for (style_mut, col) in default_style.iter_mut().zip(line.iter()) {
                let width = display_width(col);
                if style_mut.wrap_width < width {
                    style_mut.wrap_width = width;
                }
            }
        }

        for line in self.data.iter() {
            let mut wrapped = vec![];

            for (col, style) in line.iter().zip(default_style.iter()) {
                wrapped.push(Wrapped::new(wrap(col, style.wrap_width), style.clone()));
            }

            self.output.push(wrapped);
        }
    }

    pub fn wrap_with(&mut self, styles: Vec<Style>) {
        for line in self.data.iter() {
            let mut wrapped = vec![];

            for (col, style) in line.iter().zip(styles.iter()) {
                wrapped.push(Wrapped::new(wrap(col, style.wrap_width), style.clone()));
            }
            self.output.push(wrapped);
        }
    }

    pub fn get_output(&self) -> &Vec<Vec<Wrapped<'b>>> {
        &self.output
    }

    pub fn len(&self) -> usize {
        self.output.len()
    }
}