From ef24de24a82fe681581cc130f342363c47c0969a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 7 Jun 2024 07:48:48 +0200 Subject: Merging upstream version 1.75.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/tabled/src/settings/span/column.rs | 125 +++++++++++++++++++++++++++++ vendor/tabled/src/settings/span/mod.rs | 68 ++++++++++++++++ vendor/tabled/src/settings/span/row.rs | 126 ++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+) create mode 100644 vendor/tabled/src/settings/span/column.rs create mode 100644 vendor/tabled/src/settings/span/mod.rs create mode 100644 vendor/tabled/src/settings/span/row.rs (limited to 'vendor/tabled/src/settings/span') diff --git a/vendor/tabled/src/settings/span/column.rs b/vendor/tabled/src/settings/span/column.rs new file mode 100644 index 000000000..50af64c23 --- /dev/null +++ b/vendor/tabled/src/settings/span/column.rs @@ -0,0 +1,125 @@ +use crate::{ + grid::{ + config::{ColoredConfig, Entity, Position, SpannedConfig}, + records::{ExactRecords, Records}, + }, + settings::CellOption, +}; + +/// Columns (Vertical) span. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ColumnSpan { + size: usize, +} + +impl ColumnSpan { + /// Creates a new column (vertical) span. + pub fn new(size: usize) -> Self { + Self { size } + } + + /// Creates a new column (vertical) span with a maximux value possible. + pub fn max() -> Self { + Self::new(usize::MAX) + } +} + +impl CellOption for ColumnSpan +where + R: Records + ExactRecords, +{ + fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + let count_rows = records.count_rows(); + let count_cols = records.count_columns(); + + set_col_spans(cfg, self.size, entity, (count_rows, count_cols)); + remove_false_spans(cfg); + } +} + +fn set_col_spans(cfg: &mut SpannedConfig, span: usize, entity: Entity, shape: (usize, usize)) { + for pos in entity.iter(shape.0, shape.1) { + if !is_valid_pos(pos, shape) { + continue; + } + + let mut span = span; + if !is_column_span_valid(pos.1, span, shape.1) { + span = shape.1 - pos.1; + } + + if span_has_intersections(cfg, pos, span) { + continue; + } + + set_span_column(cfg, pos, span); + } +} + +fn set_span_column(cfg: &mut SpannedConfig, pos: (usize, usize), span: usize) { + if span == 0 { + let (row, col) = pos; + if col == 0 { + return; + } + + if let Some(closecol) = closest_visible(cfg, (row, col - 1)) { + let span = col + 1 - closecol; + cfg.set_column_span((row, closecol), span); + } + } + + cfg.set_column_span(pos, span); +} + +fn closest_visible(cfg: &SpannedConfig, mut pos: Position) -> Option { + loop { + if cfg.is_cell_visible(pos) { + return Some(pos.1); + } + + if pos.1 == 0 { + return None; + } + + pos.1 -= 1; + } +} + +fn is_column_span_valid(col: usize, span: usize, count_cols: usize) -> bool { + span + col <= count_cols +} + +fn is_valid_pos((row, col): Position, (count_rows, count_cols): (usize, usize)) -> bool { + row < count_rows && col < count_cols +} + +fn span_has_intersections(cfg: &SpannedConfig, (row, col): Position, span: usize) -> bool { + for col in col..col + span { + if !cfg.is_cell_visible((row, col)) { + return true; + } + } + + false +} + +fn remove_false_spans(cfg: &mut SpannedConfig) { + for (pos, _) in cfg.get_column_spans() { + if cfg.is_cell_visible(pos) { + continue; + } + + cfg.set_row_span(pos, 1); + cfg.set_column_span(pos, 1); + } + + for (pos, _) in cfg.get_row_spans() { + if cfg.is_cell_visible(pos) { + continue; + } + + cfg.set_row_span(pos, 1); + cfg.set_column_span(pos, 1); + } +} diff --git a/vendor/tabled/src/settings/span/mod.rs b/vendor/tabled/src/settings/span/mod.rs new file mode 100644 index 000000000..1139a2b99 --- /dev/null +++ b/vendor/tabled/src/settings/span/mod.rs @@ -0,0 +1,68 @@ +//! This module contains a [`Span`] settings, it helps to +//! make a cell take more space then it generally takes. +//! +//! # Example +//! +//! ``` +//! use tabled::{settings::{Span, Modify}, Table}; +//! +//! let data = [[1, 2, 3], [4, 5, 6]]; +//! +//! let table = Table::new(data) +//! .with(Modify::new((2, 0)).with(Span::column(2))) +//! .with(Modify::new((0, 1)).with(Span::column(2))) +//! .to_string(); +//! +//! assert_eq!( +//! table, +//! concat!( +//! "+---+---+---+\n", +//! "| 0 | 1 |\n", +//! "+---+---+---+\n", +//! "| 1 | 2 | 3 |\n", +//! "+---+---+---+\n", +//! "| 4 | 6 |\n", +//! "+---+---+---+", +//! ) +//! ) +//! ``` + +mod column; +mod row; + +pub use column::ColumnSpan; +pub use row::RowSpan; + +/// Span represent a horizontal/column span setting for any cell on a [`Table`]. +/// +/// It will be ignored if: +/// - cell position is out of scope +/// - size is bigger then the total number of columns. +/// - size is bigger then the total number of rows. +/// +/// ```rust,no_run +/// # use tabled::{Table, settings::{Style, Span, Modify, object::Columns}}; +/// # let data: Vec<&'static str> = Vec::new(); +/// let table = Table::new(&data) +/// .with(Modify::new(Columns::single(0)).with(Span::column(2))); +/// ``` +/// +/// [`Table`]: crate::Table +#[derive(Debug)] +pub struct Span; + +impl Span { + /// New constructs a horizontal/column [`Span`]. + /// + /// If size is bigger then the total number of columns it will be ignored. + pub fn column(size: usize) -> ColumnSpan { + ColumnSpan::new(size) + } + + /// New constructs a vertical/row [`Span`]. + /// + /// If size is bigger then the total number of rows it will be ignored. + pub fn row(size: usize) -> RowSpan { + RowSpan::new(size) + } +} diff --git a/vendor/tabled/src/settings/span/row.rs b/vendor/tabled/src/settings/span/row.rs new file mode 100644 index 000000000..68673f7a2 --- /dev/null +++ b/vendor/tabled/src/settings/span/row.rs @@ -0,0 +1,126 @@ +use crate::{ + grid::{ + config::{ColoredConfig, Entity, Position, SpannedConfig}, + records::{ExactRecords, Records}, + }, + settings::CellOption, +}; + +/// Row (vertical) span. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct RowSpan { + size: usize, +} + +impl RowSpan { + /// Creates a new row (vertical) span. + pub const fn new(size: usize) -> Self { + Self { size } + } + + /// Creates a new row (vertical) span with a maximux value possible. + pub const fn max() -> Self { + Self::new(usize::MAX) + } +} + +impl CellOption for RowSpan +where + R: Records + ExactRecords, +{ + fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + let count_rows = records.count_rows(); + let count_cols = records.count_columns(); + + set_row_spans(cfg, self.size, entity, (count_rows, count_cols)); + remove_false_spans(cfg); + } +} + +fn set_row_spans(cfg: &mut SpannedConfig, span: usize, entity: Entity, shape: (usize, usize)) { + for pos in entity.iter(shape.0, shape.1) { + if !is_valid_pos(pos, shape) { + continue; + } + + let mut span = span; + if !is_row_span_valid(pos.0, span, shape.0) { + span = shape.0 - pos.0; + } + + if span_has_intersections(cfg, pos, span) { + continue; + } + + set_span_row(cfg, pos, span); + } +} + +fn set_span_row(cfg: &mut SpannedConfig, pos: (usize, usize), span: usize) { + if span == 0 { + let (row, col) = pos; + if row == 0 { + return; + } + + if let Some(closerow) = closest_visible_row(cfg, (row - 1, col)) { + let span = row + 1 - closerow; + cfg.set_row_span((closerow, col), span); + } + } + + cfg.set_row_span(pos, span); +} + +fn closest_visible_row(cfg: &SpannedConfig, mut pos: Position) -> Option { + loop { + if cfg.is_cell_visible(pos) { + return Some(pos.0); + } + + if pos.0 == 0 { + // can happen if we have a above horizontal spanned cell + return None; + } + + pos.0 -= 1; + } +} + +fn is_row_span_valid(row: usize, span: usize, count_rows: usize) -> bool { + span + row <= count_rows +} + +fn is_valid_pos((row, col): Position, (count_rows, count_cols): (usize, usize)) -> bool { + row < count_rows && col < count_cols +} + +fn span_has_intersections(cfg: &SpannedConfig, (row, col): Position, span: usize) -> bool { + for row in row..row + span { + if !cfg.is_cell_visible((row, col)) { + return true; + } + } + + false +} + +fn remove_false_spans(cfg: &mut SpannedConfig) { + for (pos, _) in cfg.get_column_spans() { + if cfg.is_cell_visible(pos) { + continue; + } + + cfg.set_row_span(pos, 1); + cfg.set_column_span(pos, 1); + } + + for (pos, _) in cfg.get_row_spans() { + if cfg.is_cell_visible(pos) { + continue; + } + + cfg.set_row_span(pos, 1); + cfg.set_column_span(pos, 1); + } +} -- cgit v1.2.3