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 --- .../src/settings/formatting/alignment_strategy.rs | 172 +++++++++++++++++++++ vendor/tabled/src/settings/formatting/charset.rs | 108 +++++++++++++ .../src/settings/formatting/justification.rs | 127 +++++++++++++++ vendor/tabled/src/settings/formatting/mod.rs | 20 +++ vendor/tabled/src/settings/formatting/tab_size.rs | 62 ++++++++ .../src/settings/formatting/trim_strategy.rs | 118 ++++++++++++++ 6 files changed, 607 insertions(+) create mode 100644 vendor/tabled/src/settings/formatting/alignment_strategy.rs create mode 100644 vendor/tabled/src/settings/formatting/charset.rs create mode 100644 vendor/tabled/src/settings/formatting/justification.rs create mode 100644 vendor/tabled/src/settings/formatting/mod.rs create mode 100644 vendor/tabled/src/settings/formatting/tab_size.rs create mode 100644 vendor/tabled/src/settings/formatting/trim_strategy.rs (limited to 'vendor/tabled/src/settings/formatting') diff --git a/vendor/tabled/src/settings/formatting/alignment_strategy.rs b/vendor/tabled/src/settings/formatting/alignment_strategy.rs new file mode 100644 index 000000000..c95facc5c --- /dev/null +++ b/vendor/tabled/src/settings/formatting/alignment_strategy.rs @@ -0,0 +1,172 @@ +use crate::{ + grid::config::{ColoredConfig, CompactMultilineConfig, Entity}, + settings::{CellOption, TableOption}, +}; + +/// `AlignmentStrategy` is a responsible for a flow how we apply an alignment. +/// It mostly matters for multiline strings. +/// +/// # Examples +/// +/// ``` +/// use tabled::{ +/// Table, +/// settings::{ +/// Style, Modify, Alignment, object::Segment, +/// formatting::{AlignmentStrategy, TrimStrategy} +/// } +/// }; +/// +/// // sample_from: https://opensource.adobe.com/Spry/samples/data_region/JSONDataSetSample.html +/// let json = r#" +/// { +/// "id": "0001", +/// "type": "donut", +/// "name": "Cake", +/// "ppu": 0.55, +/// "batters": { +/// "batter": [ +/// { "id": "1001", "type": "Regular" }, +/// { "id": "1002", "type": "Chocolate" }, +/// ] +/// }, +/// "topping": [ +/// { "id": "5001", "type": "None" }, +/// { "id": "5006", "type": "Chocolate with Sprinkles" }, +/// { "id": "5003", "type": "Chocolate" }, +/// { "id": "5004", "type": "Maple" } +/// ] +/// }"#; +/// +/// let mut table = Table::new(&[json]); +/// table +/// .with(Style::modern()) +/// .with(Modify::new(Segment::all()).with(Alignment::right())) +/// .with(Modify::new(Segment::all()).with(TrimStrategy::None)); +/// +/// println!("{}", table); +/// +/// assert_eq!( +/// format!("\n{}", table), +/// r#" +/// ┌───────────────────────────────────────────────────────────────┐ +/// │ &str │ +/// ├───────────────────────────────────────────────────────────────┤ +/// │ │ +/// │ { │ +/// │ "id": "0001", │ +/// │ "type": "donut", │ +/// │ "name": "Cake", │ +/// │ "ppu": 0.55, │ +/// │ "batters": { │ +/// │ "batter": [ │ +/// │ { "id": "1001", "type": "Regular" }, │ +/// │ { "id": "1002", "type": "Chocolate" }, │ +/// │ ] │ +/// │ }, │ +/// │ "topping": [ │ +/// │ { "id": "5001", "type": "None" }, │ +/// │ { "id": "5006", "type": "Chocolate with Sprinkles" }, │ +/// │ { "id": "5003", "type": "Chocolate" }, │ +/// │ { "id": "5004", "type": "Maple" } │ +/// │ ] │ +/// │ } │ +/// └───────────────────────────────────────────────────────────────┘"#); +/// +/// table +/// .with(Modify::new(Segment::all()).with(AlignmentStrategy::PerCell)) +/// .with(Modify::new(Segment::all()).with(TrimStrategy::Horizontal)); +/// +/// assert_eq!( +/// format!("\n{}", table), +/// r#" +/// ┌───────────────────────────────────────────────────────────────┐ +/// │ &str │ +/// ├───────────────────────────────────────────────────────────────┤ +/// │ │ +/// │ { │ +/// │ "id": "0001", │ +/// │ "type": "donut", │ +/// │ "name": "Cake", │ +/// │ "ppu": 0.55, │ +/// │ "batters": { │ +/// │ "batter": [ │ +/// │ { "id": "1001", "type": "Regular" }, │ +/// │ { "id": "1002", "type": "Chocolate" }, │ +/// │ ] │ +/// │ }, │ +/// │ "topping": [ │ +/// │ { "id": "5001", "type": "None" }, │ +/// │ { "id": "5006", "type": "Chocolate with Sprinkles" }, │ +/// │ { "id": "5003", "type": "Chocolate" }, │ +/// │ { "id": "5004", "type": "Maple" } │ +/// │ ] │ +/// │ } │ +/// └───────────────────────────────────────────────────────────────┘"#); +/// +/// table.with(Modify::new(Segment::all()).with(AlignmentStrategy::PerLine)); +/// +/// assert_eq!( +/// format!("\n{}", table), +/// r#" +/// ┌───────────────────────────────────────────────────────────────┐ +/// │ &str │ +/// ├───────────────────────────────────────────────────────────────┤ +/// │ │ +/// │ { │ +/// │ "id": "0001", │ +/// │ "type": "donut", │ +/// │ "name": "Cake", │ +/// │ "ppu": 0.55, │ +/// │ "batters": { │ +/// │ "batter": [ │ +/// │ { "id": "1001", "type": "Regular" }, │ +/// │ { "id": "1002", "type": "Chocolate" }, │ +/// │ ] │ +/// │ }, │ +/// │ "topping": [ │ +/// │ { "id": "5001", "type": "None" }, │ +/// │ { "id": "5006", "type": "Chocolate with Sprinkles" }, │ +/// │ { "id": "5003", "type": "Chocolate" }, │ +/// │ { "id": "5004", "type": "Maple" } │ +/// │ ] │ +/// │ } │ +/// └───────────────────────────────────────────────────────────────┘"#); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum AlignmentStrategy { + /// Apply alignment for cell content as a whole. + PerCell, + /// Apply alignment for each line of a cell content as a whole. + PerLine, +} + +impl CellOption for AlignmentStrategy { + fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + let mut formatting = *cfg.get_formatting(entity); + match &self { + AlignmentStrategy::PerCell => formatting.allow_lines_alignment = false, + AlignmentStrategy::PerLine => formatting.allow_lines_alignment = true, + } + + cfg.set_formatting(entity, formatting); + } +} + +impl TableOption for AlignmentStrategy { + fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { + >::change(self, records, cfg, Entity::Global) + } +} + +impl TableOption for AlignmentStrategy { + fn change(self, _: &mut R, cfg: &mut CompactMultilineConfig, _: &mut D) { + let mut f = cfg.get_formatting(); + match &self { + AlignmentStrategy::PerCell => f.allow_lines_alignment = false, + AlignmentStrategy::PerLine => f.allow_lines_alignment = true, + } + + *cfg = cfg.set_formatting(f); + } +} diff --git a/vendor/tabled/src/settings/formatting/charset.rs b/vendor/tabled/src/settings/formatting/charset.rs new file mode 100644 index 000000000..c58effcd8 --- /dev/null +++ b/vendor/tabled/src/settings/formatting/charset.rs @@ -0,0 +1,108 @@ +use papergrid::{ + config::Entity, + records::{ExactRecords, PeekableRecords}, +}; + +use crate::{ + grid::records::{Records, RecordsMut}, + settings::{CellOption, TableOption}, +}; + +/// A structure to handle special chars. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Charset; + +impl Charset { + /// Returns [`CleanCharset`] which removes all `\t` and `\r` occurences. + /// + /// Notice that tab is just removed rather then being replaced with spaces. + /// You might be better call [`TabSize`] first if you not expect such behavior. + /// + /// # Example + /// + /// ``` + /// use tabled::{Table, settings::formatting::Charset}; + /// + /// let text = "Some\ttext\t\twith \\tabs"; + /// + /// let mut table = Table::new([text]); + /// table.with(Charset::clean()); + /// + /// assert_eq!( + /// table.to_string(), + /// "+--------------------+\n\ + /// | &str |\n\ + /// +--------------------+\n\ + /// | Sometextwith \\tabs |\n\ + /// +--------------------+" + /// ) + /// ``` + /// + /// [`TabSize`]: crate::settings::formatting::TabSize + pub fn clean() -> CleanCharset { + CleanCharset + } +} + +/// [`CleanCharset`] removes all `\t` and `\r` occurences. +/// +/// # Example +/// +/// ``` +/// use tabled::{Table, settings::formatting::Charset}; +/// +/// let text = "Some text which was created on windows \r\n yes they use this \\r\\n"; +/// +/// let mut builder = Table::builder([text]); +/// builder.set_header(["win. text"]); +/// +/// let mut table = builder.build(); +/// table.with(Charset::clean()); +/// +/// assert_eq!( +/// table.to_string(), +/// "+-----------------------------------------+\n\ +/// | win. text |\n\ +/// +-----------------------------------------+\n\ +/// | Some text which was created on windows |\n\ +/// | yes they use this \\r\\n |\n\ +/// +-----------------------------------------+" +/// ) +/// ``` +#[derive(Debug, Default, Clone)] +pub struct CleanCharset; + +impl TableOption for CleanCharset +where + for<'a> &'a R: Records, + R: RecordsMut, +{ + fn change(self, records: &mut R, _: &mut C, _: &mut D) { + let mut list = vec![]; + for (row, cells) in records.iter_rows().into_iter().enumerate() { + for (col, text) in cells.into_iter().enumerate() { + let text = text.as_ref().replace(['\t', '\r'], ""); + list.push(((row, col), text)); + } + } + + for (pos, text) in list { + records.set(pos, text); + } + } +} + +impl CellOption for CleanCharset +where + R: Records + ExactRecords + PeekableRecords + RecordsMut, +{ + fn change(self, records: &mut R, _: &mut C, entity: Entity) { + let count_rows = records.count_rows(); + let count_cols = records.count_columns(); + for pos in entity.iter(count_rows, count_cols) { + let text = records.get_text(pos); + let text = text.replace(['\t', '\r'], ""); + records.set(pos, text); + } + } +} diff --git a/vendor/tabled/src/settings/formatting/justification.rs b/vendor/tabled/src/settings/formatting/justification.rs new file mode 100644 index 000000000..a427eb95e --- /dev/null +++ b/vendor/tabled/src/settings/formatting/justification.rs @@ -0,0 +1,127 @@ +use crate::{ + grid::{ + color::AnsiColor, + config::{ColoredConfig, Entity}, + }, + settings::{CellOption, Color, TableOption}, +}; + +/// Set a justification character and a color. +/// +/// Default value is `' '` (``) with no color. +/// +/// # Examples +/// +/// Setting a justification character. +/// +/// ``` +/// use tabled::{ +/// Table, +/// settings::formatting::Justification, +/// }; +/// +/// let mut table = Table::new(&[("Hello", ""), ("", "World")]); +/// table.with(Justification::new('#')); +/// +/// assert_eq!( +/// table.to_string(), +/// "+-------+-------+\n\ +/// | &str# | &str# |\n\ +/// +-------+-------+\n\ +/// | Hello | ##### |\n\ +/// +-------+-------+\n\ +/// | ##### | World |\n\ +/// +-------+-------+" +/// ); +/// ``` +/// +/// Setting a justification color. +/// +/// ``` +/// use tabled::{ +/// Table, +/// settings::{formatting::Justification, Color}, +/// }; +/// +/// let mut table = Table::new(&[("Hello", ""), ("", "World")]); +/// table.with(Justification::default().color(Color::BG_BRIGHT_RED)); +/// +/// assert_eq!( +/// table.to_string(), +/// "+-------+-------+\n\ +/// | &str\u{1b}[101m \u{1b}[49m | &str\u{1b}[101m \u{1b}[49m |\n\ +/// +-------+-------+\n\ +/// | Hello | \u{1b}[101m \u{1b}[49m |\n\ +/// +-------+-------+\n\ +/// | \u{1b}[101m \u{1b}[49m | World |\n\ +/// +-------+-------+" +/// ); +/// ``` +/// +/// Use different justification for different columns. +/// +/// ``` +/// use tabled::{ +/// Table, +/// settings::{Modify, object::Columns, formatting::Justification}, +/// }; +/// +/// let mut table = Table::new(&[("Hello", ""), ("", "World")]); +/// table.with(Modify::new(Columns::single(0)).with(Justification::new('#'))); +/// table.with(Modify::new(Columns::single(1)).with(Justification::new('@'))); +/// +/// assert_eq!( +/// table.to_string(), +/// "+-------+-------+\n\ +/// | &str# | &str@ |\n\ +/// +-------+-------+\n\ +/// | Hello | @@@@@ |\n\ +/// +-------+-------+\n\ +/// | ##### | World |\n\ +/// +-------+-------+" +/// ); +/// ``` +/// +#[derive(Debug, Default, Clone)] +pub struct Justification { + c: Option, + color: Option>, +} + +impl Justification { + /// Creates new [`Justification`] object. + pub fn new(c: char) -> Self { + Self { + c: Some(c), + color: None, + } + } + + /// Sets a color for a justification. + pub fn color(self, color: Color) -> Self { + Self { + c: self.c, + color: Some(color.into()), + } + } +} + +impl TableOption for Justification { + fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { + let c = self.c.unwrap_or(' '); + let color = self.color; + + cfg.set_justification(Entity::Global, c); + cfg.set_justification_color(Entity::Global, color); + } +} + +impl CellOption for Justification { + fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + let c = self.c.unwrap_or(' '); + let color = self.color; + + cfg.set_justification(entity, c); + cfg.set_justification_color(entity, color); + } +} diff --git a/vendor/tabled/src/settings/formatting/mod.rs b/vendor/tabled/src/settings/formatting/mod.rs new file mode 100644 index 000000000..e3a56092f --- /dev/null +++ b/vendor/tabled/src/settings/formatting/mod.rs @@ -0,0 +1,20 @@ +//! This module contains settings for render strategy of papergrid. +//! +//! - [`TrimStrategy`] and [`AlignmentStrategy`] allows to set [`Alignment`] settings. +//! - [`TabSize`] sets a default tab size. +//! - [`Charset`] responsible for special char treatment. +//! - [`Justification`] responsible for justification space of content. +//! +//! [`Alignment`]: crate::settings::Alignment + +mod alignment_strategy; +mod charset; +mod justification; +mod tab_size; +mod trim_strategy; + +pub use alignment_strategy::AlignmentStrategy; +pub use charset::{Charset, CleanCharset}; +pub use justification::Justification; +pub use tab_size::TabSize; +pub use trim_strategy::TrimStrategy; diff --git a/vendor/tabled/src/settings/formatting/tab_size.rs b/vendor/tabled/src/settings/formatting/tab_size.rs new file mode 100644 index 000000000..677d0d613 --- /dev/null +++ b/vendor/tabled/src/settings/formatting/tab_size.rs @@ -0,0 +1,62 @@ +use crate::{ + grid::records::{Records, RecordsMut}, + settings::TableOption, +}; + +/// Set a tab size. +/// +/// The size is used in order to calculate width correctly. +/// +/// Default value is 4 (basically 1 '\t' equals 4 spaces). +/// +/// IMPORTANT: The tab character might be not present in output, +/// it might be replaced by spaces. +/// +/// # Example +/// +/// ``` +/// use tabled::{Table, settings::formatting::TabSize}; +/// +/// let text = "Some\ttext\t\twith \\tabs"; +/// +/// let mut table = Table::new([text]); +/// table.with(TabSize::new(4)); +/// +/// assert_eq!( +/// table.to_string(), +/// "+--------------------------------+\n\ +/// | &str |\n\ +/// +--------------------------------+\n\ +/// | Some text with \\tabs |\n\ +/// +--------------------------------+" +/// ) +/// ``` +#[derive(Debug, Default, Clone)] +pub struct TabSize(usize); + +impl TabSize { + /// Creates new [`TabSize`] object. + pub fn new(size: usize) -> Self { + Self(size) + } +} + +impl TableOption for TabSize +where + for<'a> &'a R: Records, + R: RecordsMut, +{ + fn change(self, records: &mut R, _: &mut C, _: &mut D) { + let mut list = vec![]; + for (row, cells) in records.iter_rows().into_iter().enumerate() { + for (col, text) in cells.into_iter().enumerate() { + let text = text.as_ref().replace('\t', &" ".repeat(self.0)); + list.push(((row, col), text)); + } + } + + for (pos, text) in list { + records.set(pos, text); + } + } +} diff --git a/vendor/tabled/src/settings/formatting/trim_strategy.rs b/vendor/tabled/src/settings/formatting/trim_strategy.rs new file mode 100644 index 000000000..64ec7e10a --- /dev/null +++ b/vendor/tabled/src/settings/formatting/trim_strategy.rs @@ -0,0 +1,118 @@ +use crate::{ + grid::config::ColoredConfig, + grid::config::Entity, + settings::{CellOption, TableOption}, +}; + +/// `TrimStrategy` determines if it's allowed to use empty space while doing [`Alignment`]. +/// +/// # Examples +/// +/// ``` +/// use tabled::{ +/// Table, +/// settings::{ +/// Style, Modify, Alignment, object::Segment, +/// formatting::{TrimStrategy, AlignmentStrategy} +/// } +/// }; +/// +/// let mut table = Table::new(&[" Hello World"]); +/// table +/// .with(Style::modern()) +/// .with( +/// Modify::new(Segment::all()) +/// .with(Alignment::left()) +/// .with(TrimStrategy::Horizontal) +/// ); +/// +/// // Note that nothing was changed exactly. +/// +/// assert_eq!( +/// table.to_string(), +/// "┌────────────────┐\n\ +/// │ &str │\n\ +/// ├────────────────┤\n\ +/// │ Hello World │\n\ +/// └────────────────┘" +/// ); +/// +/// // To trim lines you would need also set [`AlignmentStrategy`]. +/// table.with(Modify::new(Segment::all()).with(AlignmentStrategy::PerLine)); +/// +/// assert_eq!( +/// table.to_string(), +/// "┌────────────────┐\n\ +/// │ &str │\n\ +/// ├────────────────┤\n\ +/// │ Hello World │\n\ +/// └────────────────┘" +/// ); +/// +/// let mut table = Table::new(&[" \n\n\n Hello World"]); +/// table +/// .with(Style::modern()) +/// .with( +/// Modify::new(Segment::all()) +/// .with(Alignment::center()) +/// .with(Alignment::top()) +/// .with(TrimStrategy::Vertical) +/// ); +/// +/// assert_eq!( +/// table.to_string(), +/// "┌─────────────────┐\n\ +/// │ &str │\n\ +/// ├─────────────────┤\n\ +/// │ Hello World │\n\ +/// │ │\n\ +/// │ │\n\ +/// │ │\n\ +/// └─────────────────┘" +/// ); +/// ``` +/// +/// [`Alignment`]: crate::settings::Alignment +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum TrimStrategy { + /// Allow vertical trim. + Vertical, + /// Allow horizontal trim. + Horizontal, + /// Allow horizontal and vertical trim. + Both, + /// Doesn't allow any trim. + None, +} + +impl CellOption for TrimStrategy { + fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) { + let mut formatting = *cfg.get_formatting(entity); + + // todo: could be changed to be a struct an enum like consts in `impl` block. + match self { + TrimStrategy::Vertical => { + formatting.vertical_trim = true; + } + TrimStrategy::Horizontal => { + formatting.horizontal_trim = true; + } + TrimStrategy::Both => { + formatting.vertical_trim = true; + formatting.horizontal_trim = true; + } + TrimStrategy::None => { + formatting.vertical_trim = false; + formatting.horizontal_trim = false; + } + } + + cfg.set_formatting(entity, formatting); + } +} + +impl TableOption for TrimStrategy { + fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) { + >::change(self, records, cfg, Entity::Global) + } +} -- cgit v1.2.3