tableau/
cell.rs

1use std::collections::HashSet;
2
3/// The alignment of a cell's content.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum Alignment {
6    /// Align the content to the left.
7    Left,
8    /// Align the content to the center.
9    Center,
10    /// Align the content to the right.
11    Right,
12}
13
14/// A cell in a table row.
15#[derive(Debug, Clone, PartialEq)]
16pub struct Cell {
17    /// The content of the cell.
18    pub content: String,
19    /// The number of columns the cell spans.
20    pub column_span: usize,
21    /// The alignment of the cell's content.
22    pub alignment: Alignment,
23    /// Whether the cell's content should be horizontally padded.
24    pub has_padding: bool,
25}
26
27impl Cell {
28    /// Creates a new cell with the given content.
29    pub fn new(content: impl ToString) -> Self {
30        Cell {
31            content: content.to_string(),
32            column_span: 1,
33            alignment: Alignment::Left,
34            has_padding: true,
35        }
36    }
37
38    /// Sets the number of columns the cell spans.
39    pub fn with_column_span(mut self, column_span: usize) -> Self {
40        self.column_span = column_span;
41        self
42    }
43
44    /// Sets the alignment of the cell's content.
45    pub fn with_alignment(mut self, alignment: Alignment) -> Self {
46        self.alignment = alignment;
47        self
48    }
49
50    /// Disables horizontal padding for the cell.
51    pub fn without_padding(mut self) -> Self {
52        self.has_padding = false;
53        self
54    }
55
56    /// Returns the width of the cell.
57    pub(crate) fn width(&self) -> usize {
58        crate::visible_width(&self.content) + if self.has_padding { 2 } else { 0 }
59    }
60
61    /// Returns the contents of the cell, wrapped to fit in `max_width`.
62    pub(crate) fn wrapped_content(&self, max_width: usize) -> Vec<String> {
63        let hidden: HashSet<usize> = crate::ANSI_REGEX
64            .find_iter(&self.content)
65            .flat_map(|m| m.start()..m.end())
66            .collect();
67        let mut res: Vec<String> = Vec::new();
68        let mut buf = String::new();
69        let mut byte_index = 0;
70        for c in self.content.chars() {
71            if !hidden.contains(&byte_index)
72                && (crate::visible_width(&buf) >= max_width || c == '\n')
73            {
74                res.push(buf);
75                buf = String::new();
76                if c == '\n' {
77                    byte_index += 1;
78                    continue;
79                }
80            }
81            byte_index += c.len_utf8();
82            buf.push(c);
83        }
84        res.push(buf);
85
86        res
87    }
88}