Skip to content

Commit

Permalink
Merge pull request #15 from Nukesor/hidden_columns
Browse files Browse the repository at this point in the history
Add a constraint to hide columns
  • Loading branch information
Nukesor authored Nov 8, 2020
2 parents e2ba49b + ae71af0 commit 441ffee
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 32 deletions.
2 changes: 2 additions & 0 deletions src/style/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/// They allow some control over the dynamic content arrangement process.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ColumnConstraint {
/// This will completely hide a column as if it doesn't exist.
Hidden,
/// Force the column to be as long as it's content.
/// Use with caution! This can easily break your table, if the column's content is overly long.
ContentWidth,
Expand Down
39 changes: 36 additions & 3 deletions src/utils/arrangement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ impl ColumnDisplayInfo {
self.content_width + self.padding.0 + self.padding.1
}

pub fn is_hidden(&self) -> bool {
if let Some(constraint) = self.constraint {
return constraint == ColumnConstraint::Hidden;
}

false
}

/// Return the remaining value after subtracting the padding width.
fn without_padding(&self, width: u16) -> u16 {
let padding = self.padding_width();
Expand Down Expand Up @@ -158,6 +166,9 @@ fn evaluate_constraint(
info.constraint = Some(MaxWidth(max_width));
}
}
Hidden => {
info.constraint = Some(ColumnConstraint::Hidden);
}
}
}

Expand Down Expand Up @@ -198,6 +209,7 @@ fn disabled_arrangement(infos: &mut Vec<ColumnDisplayInfo>) {
fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_width: u16) {
// Convert to i32 to handle negative values in case we work with a very small terminal
let mut remaining_width = table_width as i32;
let column_count = count_visible_columns(infos);

// Remove space occupied by borders from remaining_width
if should_draw_left_border(table) {
Expand All @@ -207,7 +219,7 @@ fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_
remaining_width -= 1;
}
if should_draw_vertical_lines(table) {
remaining_width -= infos.len() as i32 - 1;
remaining_width -= column_count as i32 - 1;
}

// All columns that have have been checked.
Expand All @@ -227,7 +239,7 @@ fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_
let mut found_smaller = true;
while found_smaller {
found_smaller = false;
let remaining_columns = infos.len() - checked.len();
let remaining_columns = column_count - checked.len();

// There are no columns left to check. Proceed to the next step
if remaining_columns == 0 {
Expand All @@ -241,6 +253,11 @@ fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_
}

for (id, info) in infos.iter_mut().enumerate() {
// Ignore hidden columns
if info.is_hidden() {
continue;
}

// We already checked this column, skip it
if checked.contains(&id) {
continue;
Expand Down Expand Up @@ -276,7 +293,7 @@ fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_
}

// Step 5. Equally distribute the remaining_width to all remaining columns
let remaining_columns = infos.len() - checked.len();
let remaining_columns = column_count - checked.len();
// We already managed to fix all.
if remaining_columns == 0 {
return;
Expand All @@ -296,10 +313,16 @@ fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_
let mut excess = remaining_width - (average_space * remaining_columns as u16);

for (id, info) in infos.iter_mut().enumerate() {
// Ignore hidden columns
if info.is_hidden() {
continue;
}

// We already checked this column, skip it
if checked.contains(&id) {
continue;
}

// Distribute the excess until nothing is left
let mut width = if excess > 0 {
excess -= 1;
Expand All @@ -315,6 +338,16 @@ fn dynamic_arrangement(table: &Table, infos: &mut Vec<ColumnDisplayInfo>, table_
}
}

fn count_visible_columns(infos: &[ColumnDisplayInfo]) -> usize {
let mut count = 0;
for info in infos {
if !info.is_hidden() {
count += 1;
}
}
count
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
55 changes: 34 additions & 21 deletions src/utils/borders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub(crate) fn draw_borders(
fn draw_top_border(table: &Table, display_info: &[ColumnDisplayInfo]) -> String {
let left_corner = table.style_or_default(TableComponent::TopLeftCorner);
let top_border = table.style_or_default(TableComponent::TopBorder);
let border_intersection = table.style_or_default(TableComponent::TopBorderIntersections);
let intersection = table.style_or_default(TableComponent::TopBorderIntersections);
let right_corner = table.style_or_default(TableComponent::TopRightCorner);

let mut line = String::new();
Expand All @@ -33,13 +33,17 @@ fn draw_top_border(table: &Table, display_info: &[ColumnDisplayInfo]) -> String
line += &left_corner;
}

// Add the top border lines depending on column width
// Also add the border intersections, if we haven't arrived at the last element yet
let mut iter = display_info.iter().peekable();
while let Some(info) = iter.next() {
line += &top_border.repeat(info.width() as usize);
if iter.peek().is_some() {
line += &border_intersection;
// Build the top border line depending on the columns' width.
// Also add the border intersections.
let mut first = true;
for info in display_info.iter() {
// Only add something, if the column isn't hidden
if !info.is_hidden() {
if !first {
line += &intersection;
}
line += &top_border.repeat(info.width() as usize);
first = false;
}
}

Expand Down Expand Up @@ -112,6 +116,7 @@ fn draw_horizontal_lines(
display_info: &[ColumnDisplayInfo],
header: bool,
) -> String {
// Styling depends on whether we're currently on the header line or not.
let (left_intersection, horizontal_lines, middle_intersection, right_intersection) = if header {
(
table.style_or_default(TableComponent::LeftHeaderIntersection),
Expand All @@ -134,13 +139,17 @@ fn draw_horizontal_lines(
line += &left_intersection;
}

// Add the bottom border lines depending on column width
// Also add the border intersections, if we haven't arrived at the last element yet
let mut iter = display_info.iter().peekable();
while let Some(info) = iter.next() {
line += &horizontal_lines.repeat(info.width() as usize);
if iter.peek().is_some() {
line += &middle_intersection;
// Append the middle lines depending on the columns' widths.
// Also add the middle intersections.
let mut first = true;
for info in display_info.iter() {
// Only add something, if the column isn't hidden
if !info.is_hidden() {
if !first {
line += &middle_intersection;
}
line += &horizontal_lines.repeat(info.width() as usize);
first = false;
}
}

Expand All @@ -165,12 +174,16 @@ fn draw_bottom_border(table: &Table, display_info: &[ColumnDisplayInfo]) -> Stri
}

// Add the bottom border lines depending on column width
// Also add the border intersections, if we haven't arrived at the last element yet
let mut iter = display_info.iter().peekable();
while let Some(info) = iter.next() {
line += &bottom_border.repeat(info.width() as usize);
if iter.peek().is_some() {
line += &middle_intersection;
// Also add the border intersections.
let mut first = true;
for info in display_info.iter() {
// Only add something, if the column isn't hidden
if !info.is_hidden() {
if !first {
line += &middle_intersection;
}
line += &bottom_border.repeat(info.width() as usize);
first = false;
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/utils/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,19 @@ pub fn format_content(table: &Table, display_info: &[ColumnDisplayInfo]) -> Vec<

pub fn format_row(
row: &Row,
display_info: &[ColumnDisplayInfo],
display_infos: &[ColumnDisplayInfo],
table: &Table,
) -> Vec<Vec<String>> {
// The content of this specific row
let mut temp_row_content = Vec::new();

let mut cell_iter = row.cells.iter();
// Now iterate over all cells and handle them according to their alignment
for info in display_info.iter() {
for info in display_infos.iter() {
if info.is_hidden() {
cell_iter.next();
continue;
}
// Each cell is devided into several lines devided by newline
// Every line that's too long will be split into two/several lines
let mut cell_lines = Vec::new();
Expand Down Expand Up @@ -133,7 +137,10 @@ pub fn format_row(
for index in 0..max_lines {
let mut line = Vec::new();
let mut cell_iter = temp_row_content.iter();
for info in display_info.iter() {
for info in display_infos.iter() {
if info.is_hidden() {
continue;
}
let cell = cell_iter.next().unwrap();
match cell.get(index) {
// The current cell has content for this line. Append it
Expand Down
10 changes: 5 additions & 5 deletions tests/constraints_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use comfy_table::*;
use pretty_assertions::assert_eq;

fn get_max_min_table() -> Table {
fn get_constraint_table() -> Table {
let mut table = Table::new();
table
.set_header(&vec!["smol", "Header2", "Header3"])
Expand All @@ -22,7 +22,7 @@ fn get_max_min_table() -> Table {
#[test]
/// Ensure max-, min- and fixed-width constraints are respected
fn fixed_max_min_constraints() {
let mut table = get_max_min_table();
let mut table = get_constraint_table();

table.set_constraints(vec![
ColumnConstraint::MinWidth(10),
Expand Down Expand Up @@ -99,7 +99,7 @@ fn fixed_max_min_constraints() {
/// Max and Min constraints won't be considered, if they are unnecessary
/// This is true for normal and dynamic arrangement tables.
fn unnecessary_max_min_constraints() {
let mut table = get_max_min_table();
let mut table = get_constraint_table();

table.set_constraints(vec![
ColumnConstraint::MinWidth(1),
Expand Down Expand Up @@ -140,7 +140,7 @@ fn unnecessary_max_min_constraints() {
/// This is allowed, but results in a wider table than acutally aimed for.
/// Anyway we still try to fit everything as good as possible, which of course breaks stuff.
fn constraints_bigger_than_table_width() {
let mut table = get_max_min_table();
let mut table = get_constraint_table();

table
.set_content_arrangement(ContentArrangement::Dynamic)
Expand Down Expand Up @@ -176,7 +176,7 @@ fn constraints_bigger_than_table_width() {
/// Test correct usage of the Percentage constraint.
/// Percentage allows to set a fixed width.
fn percentage() {
let mut table = get_max_min_table();
let mut table = get_constraint_table();

// Set a percentage of 20% for the first column
// Hide the second
Expand Down
Loading

0 comments on commit 441ffee

Please sign in to comment.