comfy_table/
cell.rs

1use crate::style::CellAlignment;
2#[cfg(feature = "tty")]
3use crate::{Attribute, Color};
4
5/// A stylable table cell with content.
6#[derive(Clone, Debug, PartialEq, Eq, Hash)]
7pub struct Cell {
8    /// The content is a list of strings.\
9    /// This is done to make working with newlines more easily.\
10    /// When creating a new [Cell], the given content is split by newline.
11    pub(crate) content: Vec<String>,
12    /// The delimiter which is used to split the text into consistent pieces.\
13    /// The default is ` `.
14    pub(crate) delimiter: Option<char>,
15    pub(crate) alignment: Option<CellAlignment>,
16    #[cfg(feature = "tty")]
17    pub(crate) fg: Option<Color>,
18    #[cfg(feature = "tty")]
19    pub(crate) bg: Option<Color>,
20    #[cfg(feature = "tty")]
21    pub(crate) attributes: Vec<Attribute>,
22}
23
24impl Cell {
25    /// Create a new Cell
26    #[allow(clippy::needless_pass_by_value)]
27    pub fn new<T: ToString>(content: T) -> Self {
28        Self::new_owned(content.to_string())
29    }
30
31    /// Create a new Cell from an owned String
32    pub fn new_owned(content: String) -> Self {
33        #[cfg_attr(not(feature = "custom_styling"), allow(unused_mut))]
34        let mut split_content: Vec<String> = content.split('\n').map(ToString::to_string).collect();
35
36        // Correct ansi codes so style is terminated and resumed around the split
37        #[cfg(feature = "custom_styling")]
38        crate::utils::formatting::content_split::fix_style_in_split_str(&mut split_content);
39
40        Self {
41            content: split_content,
42            delimiter: None,
43            alignment: None,
44            #[cfg(feature = "tty")]
45            fg: None,
46            #[cfg(feature = "tty")]
47            bg: None,
48            #[cfg(feature = "tty")]
49            attributes: Vec::new(),
50        }
51    }
52
53    /// Return a copy of the content contained in this cell.
54    pub fn content(&self) -> String {
55        self.content.join("\n")
56    }
57
58    /// Set the delimiter used to split text for this cell. \
59    /// Normal text uses spaces (` `) as delimiters. This is necessary to help comfy-table
60    /// understand the concept of _words_.
61    #[must_use]
62    pub fn set_delimiter(mut self, delimiter: char) -> Self {
63        self.delimiter = Some(delimiter);
64
65        self
66    }
67
68    /// Set the alignment of content for this cell.
69    ///
70    /// Setting this overwrites alignment settings of the
71    /// [Column](crate::column::Column::set_cell_alignment) for this specific cell.
72    /// ```
73    /// use comfy_table::{Cell, CellAlignment};
74    ///
75    /// let mut cell = Cell::new("Some content").set_alignment(CellAlignment::Center);
76    /// ```
77    #[must_use]
78    pub fn set_alignment(mut self, alignment: CellAlignment) -> Self {
79        self.alignment = Some(alignment);
80
81        self
82    }
83
84    /// Set the foreground text color for this cell.
85    ///
86    /// Look at [Color](crate::Color) for a list of all possible Colors.
87    /// ```
88    /// use comfy_table::{Cell, Color};
89    ///
90    /// let mut cell = Cell::new("Some content").fg(Color::Red);
91    /// ```
92    #[cfg(feature = "tty")]
93    #[must_use]
94    pub fn fg(mut self, color: Color) -> Self {
95        self.fg = Some(color);
96
97        self
98    }
99
100    /// Set the background color for this cell.
101    ///
102    /// Look at [Color](crate::Color) for a list of all possible Colors.
103    /// ```
104    /// use comfy_table::{Cell, Color};
105    ///
106    /// let mut cell = Cell::new("Some content").bg(Color::Red);
107    /// ```
108    #[cfg(feature = "tty")]
109    #[must_use]
110    pub fn bg(mut self, color: Color) -> Self {
111        self.bg = Some(color);
112
113        self
114    }
115
116    /// Add a styling attribute to the content cell.\
117    /// Those can be **bold**, _italic_, blinking and many more.
118    ///
119    /// Look at [Attribute](crate::Attribute) for a list of all possible Colors.
120    /// ```
121    /// use comfy_table::{Attribute, Cell};
122    ///
123    /// let mut cell = Cell::new("Some content").add_attribute(Attribute::Bold);
124    /// ```
125    #[cfg(feature = "tty")]
126    #[must_use]
127    pub fn add_attribute(mut self, attribute: Attribute) -> Self {
128        self.attributes.push(attribute);
129
130        self
131    }
132
133    /// Same as add_attribute, but you can pass a vector of [Attributes](Attribute)
134    #[cfg(feature = "tty")]
135    #[must_use]
136    pub fn add_attributes(mut self, mut attribute: Vec<Attribute>) -> Self {
137        self.attributes.append(&mut attribute);
138
139        self
140    }
141}
142
143/// Convert anything with [ToString] to a new [Cell].
144///
145/// ```
146/// # use comfy_table::Cell;
147/// let cell: Cell = "content".into();
148/// let cell: Cell = 5u32.into();
149/// ```
150impl<T: ToString> From<T> for Cell {
151    fn from(content: T) -> Self {
152        Self::new(content)
153    }
154}
155
156/// A simple wrapper type for a `Vec<Cell>`.
157///
158/// This wrapper is needed to support generic conversions between iterables and `Vec<Cell>`.
159/// Check the trait implementations for more docs.
160pub struct Cells(pub Vec<Cell>);
161
162/// Allow the conversion of a type to a [Cells], which is a simple vector of cells.
163///
164/// By default this is implemented for all Iterators over items implementing [ToString].
165///
166/// ```
167/// use comfy_table::{Cells, Row};
168///
169/// let cells_string: Cells = vec!["One", "Two", "Three"].into();
170/// let cells_integer: Cells = vec![1, 2, 3, 4].into();
171/// ```
172impl<T> From<T> for Cells
173where
174    T: IntoIterator,
175    T::Item: Into<Cell>,
176{
177    fn from(cells: T) -> Self {
178        Self(cells.into_iter().map(Into::into).collect())
179    }
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn test_column_generation() {
188        let content = "This is\nsome multiline\nstring".to_string();
189        let cell = Cell::new(content.clone());
190
191        assert_eq!(cell.content(), content);
192    }
193}