comfy_table/utils/arrangement/
mod.rs

1use std::collections::BTreeMap;
2
3use super::ColumnDisplayInfo;
4use crate::style::ContentArrangement;
5use crate::table::Table;
6
7pub mod constraint;
8mod disabled;
9mod dynamic;
10pub mod helper;
11
12type DisplayInfos = BTreeMap<usize, ColumnDisplayInfo>;
13
14/// Determine the width of each column depending on the content of the given table.
15/// The results uses Option<usize>, since users can choose to hide columns.
16pub fn arrange_content(table: &Table) -> Vec<ColumnDisplayInfo> {
17    let table_width = table.width().map(usize::from);
18    let mut infos = BTreeMap::new();
19
20    let max_content_widths = table.column_max_content_widths();
21
22    // Check if we can already resolve some constraints.
23    // This step also populates the ColumnDisplayInfo structs.
24    let visible_columns = helper::count_visible_columns(&table.columns);
25    for column in table.columns.iter() {
26        if column.constraint.is_some() {
27            constraint::evaluate(
28                table,
29                visible_columns,
30                &mut infos,
31                column,
32                max_content_widths[column.index],
33            );
34        }
35    }
36    #[cfg(feature = "debug")]
37    println!("After initial constraints: {infos:#?}");
38
39    // Fallback to `ContentArrangement::Disabled`, if we don't have any information
40    // on how wide the table should be.
41    let table_width = if let Some(table_width) = table_width {
42        table_width
43    } else {
44        disabled::arrange(table, &mut infos, visible_columns, &max_content_widths);
45        return infos.into_values().collect();
46    };
47
48    match &table.arrangement {
49        ContentArrangement::Disabled => {
50            disabled::arrange(table, &mut infos, visible_columns, &max_content_widths)
51        }
52        ContentArrangement::Dynamic | ContentArrangement::DynamicFullWidth => {
53            dynamic::arrange(table, &mut infos, table_width, &max_content_widths);
54        }
55    }
56
57    infos.into_values().collect()
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_disabled_arrangement() {
66        let mut table = Table::new();
67        table.set_header(vec!["head", "head", "head"]);
68        table.add_row(vec!["__", "fivef", "sixsix"]);
69
70        let display_infos = arrange_content(&table);
71
72        // The width should be the width of the rows + padding
73        let widths: Vec<u16> = display_infos.iter().map(ColumnDisplayInfo::width).collect();
74        assert_eq!(widths, vec![6, 7, 8]);
75    }
76
77    #[test]
78    fn test_discover_columns() {
79        let mut table = Table::new();
80        table.add_row(vec!["one", "two"]);
81
82        // Get the first row and add a new cell, which would create a new column.
83        let row = table.row_mut(0).unwrap();
84        row.add_cell("three".into());
85
86        // The table cannot know about the new cell yet, which is why we expect two columns.
87        assert_eq!(table.columns.len(), 2);
88
89        // After scanning for new columns however, it should show up.
90        table.discover_columns();
91        assert_eq!(table.columns.len(), 3);
92    }
93}