tabled/features/width/
mod.rs

1//! This module contains object which can be used to limit a cell to a given width:
2//!
3//! - [`Truncate`] cuts a cell content to limit width.
4//! - [`Wrap`] split the content via new lines in order to fit max width.
5//! - [`Justify`] sets columns width to the same value.
6//!
7//! To set a a table width, a combination of [`Width::truncate`] or [`Width::wrap`] and [`Width::increase`] can be used.
8//!
9//! ## Example
10//!
11//! ```
12//! use tabled::{Width, Table};
13//!
14//! let table = Table::new(&["Hello World!"])
15//!     .with(Width::wrap(7))
16//!     .with(Width::increase(7))
17//!     .to_string();
18//!
19//! assert_eq!(
20//!     table,
21//!     concat!(
22//!         "+-----+\n",
23//!         "| &st |\n",
24//!         "| r   |\n",
25//!         "+-----+\n",
26//!         "| Hel |\n",
27//!         "| lo  |\n",
28//!         "| Wor |\n",
29//!         "| ld! |\n",
30//!         "+-----+",
31//!     )
32//! );
33//! ```
34
35mod justify;
36mod min_width;
37mod truncate;
38mod width_list;
39mod wrap;
40
41use crate::measurment::Measurment;
42
43pub use self::{
44    justify::Justify,
45    min_width::MinWidth,
46    truncate::{SuffixLimit, Truncate},
47    width_list::WidthList,
48    wrap::Wrap,
49};
50
51use papergrid::{records::Records, width::WidthEstimator, Estimate, GridConfig};
52
53pub(crate) use wrap::wrap_text;
54
55/// Width allows you to set a min and max width of an object on a [`Table`]
56/// using different strategies.
57///
58/// It also allows you to set a min and max width for a whole table.
59///
60/// You can apply a min and max strategy at the same time with the same value,
61/// the value will be a total table width.
62///
63/// It is an abstract factory.
64///
65/// Beware that borders are not removed when you set a size value to very small.
66/// For example if you set size to 0 the table still be rendered but with all content removed.
67///
68/// Also be aware that it doesn't changes [`Padding`] settings nor it considers them.
69///
70/// The function is color aware if a `color` feature is on.
71///
72/// ## Examples
73///
74/// ### Cell change
75///
76/// ```
77/// use tabled::{object::Segment, Width, Modify, Style, Table};
78///
79/// let data = ["Hello", "World", "!"];
80///
81/// let table = Table::new(&data)
82///     .with(Style::markdown())
83///     .with(Modify::new(Segment::all()).with(Width::truncate(3).suffix("...")));
84/// ```
85///
86/// ### Table change
87///
88/// ```
89/// use tabled::{Width, Table};
90///
91/// let table = Table::new(&["Hello World!"]).with(Width::wrap(5));
92/// ```
93///
94/// ### Total width
95///
96/// ```
97/// use tabled::{Width, Table};
98///
99/// let table = Table::new(&["Hello World!"])
100///     .with(Width::wrap(5))
101///     .with(Width::increase(5));
102/// ```
103///
104/// [`Padding`]: crate::Padding
105/// [`Table`]: crate::Table
106#[derive(Debug)]
107pub struct Width;
108
109impl Width {
110    /// Returns a [`Wrap`] structure.
111    pub fn wrap<W>(width: W) -> Wrap<W>
112    where
113        W: Measurment<Width>,
114    {
115        Wrap::new(width)
116    }
117
118    /// Returns a [`Truncate`] structure.
119    pub fn truncate<W>(width: W) -> Truncate<'static, W>
120    where
121        W: Measurment<Width>,
122    {
123        Truncate::new(width)
124    }
125
126    /// Returns a [`MinWidth`] structure.
127    pub fn increase<W>(width: W) -> MinWidth<W>
128    where
129        W: Measurment<Width>,
130    {
131        MinWidth::new(width)
132    }
133
134    /// Returns a [`Justify`] structure.
135    pub fn justify<W>(width: W) -> Justify<W>
136    where
137        W: Measurment<Width>,
138    {
139        Justify::new(width)
140    }
141
142    /// Create [`WidthList`] to set a table width to a constant list of column widths.
143    ///
144    /// Notice if you provide a list with `.len()` smaller than `Table::count_columns` then it will have no affect.
145    ///
146    /// Also notice that you must provide values bigger than or equal to a real content width, otherwise it may panic.
147    ///
148    /// # Example
149    ///
150    /// ```
151    /// use tabled::{Table, Width};
152    ///
153    /// let data = vec![
154    ///     ("Some\ndata", "here", "and here"),
155    ///     ("Some\ndata on a next", "line", "right here"),
156    /// ];
157    ///
158    /// let table = Table::new(data)
159    ///     .with(Width::list([20, 10, 12]))
160    ///     .to_string();
161    ///
162    /// assert_eq!(
163    ///     table,
164    ///     "+--------------------+----------+------------+\n\
165    ///      | &str               | &str     | &str       |\n\
166    ///      +--------------------+----------+------------+\n\
167    ///      | Some               | here     | and here   |\n\
168    ///      | data               |          |            |\n\
169    ///      +--------------------+----------+------------+\n\
170    ///      | Some               | line     | right here |\n\
171    ///      | data on a next     |          |            |\n\
172    ///      +--------------------+----------+------------+"
173    /// )
174    /// ```
175    pub fn list<I>(rows: I) -> WidthList
176    where
177        I: IntoIterator<Item = usize>,
178    {
179        WidthList::new(rows.into_iter().collect())
180    }
181}
182
183pub(crate) fn get_table_widths<R>(records: R, cfg: &GridConfig) -> Vec<usize>
184where
185    R: Records,
186{
187    let mut evaluator = WidthEstimator::default();
188    evaluator.estimate(records, cfg);
189    evaluator.into()
190}
191
192pub(crate) fn count_borders(
193    cfg: &GridConfig,
194    start: usize,
195    end: usize,
196    count_columns: usize,
197) -> usize {
198    (start..end)
199        .skip(1)
200        .filter(|&i| cfg.has_vertical(i, count_columns))
201        .count()
202}
203
204pub(crate) fn get_table_total_width<W, R>(records: R, cfg: &GridConfig, ctrl: &W) -> usize
205where
206    W: Estimate<R>,
207    R: Records,
208{
209    ctrl.total()
210        + cfg.count_vertical(records.count_columns())
211        + cfg.get_margin().left.size
212        + cfg.get_margin().right.size
213}
214
215pub(crate) fn get_table_widths_with_total<R>(records: R, cfg: &GridConfig) -> (Vec<usize>, usize)
216where
217    R: Records,
218{
219    let mut evaluator = WidthEstimator::default();
220    evaluator.estimate(&records, cfg);
221    let total_width = get_table_total_width(&records, cfg, &evaluator);
222    let widths = evaluator.into();
223    (widths, total_width)
224}