From 4e2e5fd8b110eb79e7428868bfa67d106ea1d334 Mon Sep 17 00:00:00 2001 From: Arne Beer Date: Sun, 28 May 2023 18:31:57 +0200 Subject: [PATCH 1/3] change: Don't re-export crossterm's types by default --- .github/workflows/test.yml | 8 +- CHANGELOG.md | 16 +++ Cargo.toml | 24 ++++- src/cell.rs | 11 +-- src/style/attribute.rs | 129 +++++++++++++++++++++++++ src/style/color.rs | 116 ++++++++++++++++++++++ src/style/mod.rs | 57 ++++++++--- src/utils/formatting/content_format.rs | 8 +- tests/all/property_test.rs | 2 +- 9 files changed, 341 insertions(+), 30 deletions(-) create mode 100644 src/style/attribute.rs create mode 100644 src/style/color.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index faf755f..2a19ca9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -61,11 +61,15 @@ jobs: if: ${{ !matrix.minimal_setup }} - name: cargo test + run: cargo test --target=${{ matrix.target }} --features=integration_test + if: ${{ !matrix.minimal_setup }} + + - name: cargo test without default features run: cargo test --target=${{ matrix.target }} --tests --no-default-features if: ${{ !matrix.minimal_setup }} - - name: cargo test - run: cargo test --target=${{ matrix.target }} --features=integration_test + - name: cargo test with crossterm re-export + run: cargo test --target=${{ matrix.target }} --features=integration_test,reexport_crossterm if: ${{ !matrix.minimal_setup }} - name: cargo test with custom_styling diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f7f75..40ad564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [7.0.0] - 2023-06-06 + +### Breaking + +- The `Color` and `Attribute` enum are no longer re-exported from crossterm by default. + Previously, when updating comfy-table, crossterm needed to be upgraded as well, since the compile would otherwise fail due to type incompatibilies. + + To fix this, these enums are now mirrored and internally mapped to their crossterm equivalents, which allows us to safely bump crossterm whenever a new version is released. + This change will only affect you if your projects explicitly use crossterm and comfy-table at the same time **and** feed crossterm's native types into comfy-table. + + This change allows us to bump the crossterm dependency in the future, without having to release a major version. + +### Added + +- `reexport_crossterm` feature flag to enable old crossterm re-export. + ## [6.2.0] - 2023-05-26 ### Added diff --git a/Cargo.toml b/Cargo.toml index 387338c..28c9540 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,11 +38,31 @@ required-features = ["custom_styling"] [features] default = ["tty"] +# This flag enables support for terminals: +# - Automatic detection whether we're in a terminal environment +# Only used when no explicit `Table::set_width` is provided. +# - Support for ANSI Escape Code styling for terminals. tty = ["crossterm"] +# This flag enables support for custom styling of text inside of cells: +# - Text formatting still works, even if you roll your own ANSI escape sequences. +# - Rainbow text +# - Makes comfy-table 30-50% slower custom_styling = ["console"] -# This flag is for library debugging only! +# With this flag, comfy_table re-exposes crossterm's "Attribute" and "Color" enum. +# By default, a mirrored type is exposed, which internally maps to the crossterm type. +# +# This feature is very convenient if you use both comfy_table and crossterm in your code +# and want to use crossterm's types for everything interchangeably. +# +# **BUT** if you enable this feature, you opt-in for breaking changes on minor/patch versions. +# Meaning, you have to update crossterm whenever you update comfy_table and vice versa, since +# they now use the same types. +reexport_crossterm = ["tty"] +# This flag is for comfy-table development debugging! +# You usually don't need this as a user of the library. debug = [] -# This feature is used to expose internal functionality for integration testing. +# This feature is used to for integration testing of comfy_table. +# It exposes normally unexposed internal functionality for easier testing. integration_test = [] [dependencies] diff --git a/src/cell.rs b/src/cell.rs index ac2b494..1d0304a 100644 --- a/src/cell.rs +++ b/src/cell.rs @@ -1,5 +1,5 @@ #[cfg(feature = "tty")] -use crossterm::style::{Attribute, Color}; +use crate::{Attribute, Color}; use crate::style::CellAlignment; @@ -82,8 +82,7 @@ impl Cell { /// Set the foreground text color for this cell. /// - /// comfy-table uses [Crossterm Colors](crossterm::style::Color). - /// Look at their documentation for all possible Colors. + /// Look at [Color](crate::Color) for a list of all possible Colors. /// ``` /// use comfy_table::Color; /// use comfy_table::Cell; @@ -101,8 +100,7 @@ impl Cell { /// Set the background color for this cell. /// - /// comfy-table uses [Crossterm Colors](crossterm::style::Color). - /// Look at their documentation for all possible Colors. + /// Look at [Color](crate::Color) for a list of all possible Colors. /// ``` /// use comfy_table::Color; /// use comfy_table::Cell; @@ -121,8 +119,7 @@ impl Cell { /// Add a styling attribute to the content cell.\ /// Those can be **bold**, _italic_, blinking and many more. /// - /// comfy-table uses [Crossterm Attributes](crossterm::style::Attribute). - /// Look at their documentation for all possible [Attributes](Attribute). + /// Look at [Attribute](crate::Attribute) for a list of all possible Colors. /// ``` /// use comfy_table::Attribute; /// use comfy_table::Cell; diff --git a/src/style/attribute.rs b/src/style/attribute.rs new file mode 100644 index 0000000..82d1879 --- /dev/null +++ b/src/style/attribute.rs @@ -0,0 +1,129 @@ +/// Represents an attribute. +/// +/// # Platform-specific Notes +/// +/// * Only UNIX and Windows 10 terminals do support text attributes. +/// * Keep in mind that not all terminals support all attributes. +/// * Crossterm implements almost all attributes listed in the +/// [SGR parameters](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters). +/// +/// | Attribute | Windows | UNIX | Notes | +/// | :-- | :--: | :--: | :-- | +/// | `Reset` | ✓ | ✓ | | +/// | `Bold` | ✓ | ✓ | | +/// | `Dim` | ✓ | ✓ | | +/// | `Italic` | ? | ? | Not widely supported, sometimes treated as inverse. | +/// | `Underlined` | ✓ | ✓ | | +/// | `SlowBlink` | ? | ? | Not widely supported, sometimes treated as inverse. | +/// | `RapidBlink` | ? | ? | Not widely supported. MS-DOS ANSI.SYS; 150+ per minute. | +/// | `Reverse` | ✓ | ✓ | | +/// | `Hidden` | ✓ | ✓ | Also known as Conceal. | +/// | `Fraktur` | ✗ | ✓ | Legible characters, but marked for deletion. | +/// | `DefaultForegroundColor` | ? | ? | Implementation specific (according to standard). | +/// | `DefaultBackgroundColor` | ? | ? | Implementation specific (according to standard). | +/// | `Framed` | ? | ? | Not widely supported. | +/// | `Encircled` | ? | ? | This should turn on the encircled attribute. | +/// | `OverLined` | ? | ? | This should draw a line at the top of the text. | +/// +/// Usage: +/// +/// Check [crate::Cell::add_attribute] on how to use it. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[non_exhaustive] +pub enum Attribute { + /// Resets all the attributes. + Reset, + /// Increases the text intensity. + Bold, + /// Decreases the text intensity. + Dim, + /// Emphasises the text. + Italic, + /// Underlines the text. + Underlined, + + // Other types of underlining + /// Double underlines the text. + DoubleUnderlined, + /// Undercurls the text. + Undercurled, + /// Underdots the text. + Underdotted, + /// Underdashes the text. + Underdashed, + + /// Makes the text blinking (< 150 per minute). + SlowBlink, + /// Makes the text blinking (>= 150 per minute). + RapidBlink, + /// Swaps foreground and background colors. + Reverse, + /// Hides the text (also known as Conceal). + Hidden, + /// Crosses the text. + CrossedOut, + /// Sets the [Fraktur](https://en.wikipedia.org/wiki/Fraktur) typeface. + /// + /// Mostly used for [mathematical alphanumeric symbols](https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols). + Fraktur, + /// Turns off the `Bold` attribute. - Inconsistent - Prefer to use NormalIntensity + NoBold, + /// Switches the text back to normal intensity (no bold, italic). + NormalIntensity, + /// Turns off the `Italic` attribute. + NoItalic, + /// Turns off the `Underlined` attribute. + NoUnderline, + /// Turns off the text blinking (`SlowBlink` or `RapidBlink`). + NoBlink, + /// Turns off the `Reverse` attribute. + NoReverse, + /// Turns off the `Hidden` attribute. + NoHidden, + /// Turns off the `CrossedOut` attribute. + NotCrossedOut, + /// Makes the text framed. + Framed, + /// Makes the text encircled. + Encircled, + /// Draws a line at the top of the text. + OverLined, + /// Turns off the `Frame` and `Encircled` attributes. + NotFramedOrEncircled, + /// Turns off the `OverLined` attribute. + NotOverLined, +} + +/// Map the internal mirrored [Attribute] to the actually used [crossterm::style::Attribute] +pub(crate) fn map_attribute(attribute: Attribute) -> crossterm::style::Attribute { + match attribute { + Attribute::Reset => crossterm::style::Attribute::Reset, + Attribute::Bold => crossterm::style::Attribute::Bold, + Attribute::Dim => crossterm::style::Attribute::Dim, + Attribute::Italic => crossterm::style::Attribute::Italic, + Attribute::Underlined => crossterm::style::Attribute::Underlined, + Attribute::DoubleUnderlined => crossterm::style::Attribute::DoubleUnderlined, + Attribute::Undercurled => crossterm::style::Attribute::Undercurled, + Attribute::Underdotted => crossterm::style::Attribute::Underdotted, + Attribute::Underdashed => crossterm::style::Attribute::Underdashed, + Attribute::SlowBlink => crossterm::style::Attribute::SlowBlink, + Attribute::RapidBlink => crossterm::style::Attribute::RapidBlink, + Attribute::Reverse => crossterm::style::Attribute::Reverse, + Attribute::Hidden => crossterm::style::Attribute::Hidden, + Attribute::CrossedOut => crossterm::style::Attribute::CrossedOut, + Attribute::Fraktur => crossterm::style::Attribute::Fraktur, + Attribute::NoBold => crossterm::style::Attribute::NoBold, + Attribute::NormalIntensity => crossterm::style::Attribute::NormalIntensity, + Attribute::NoItalic => crossterm::style::Attribute::NoItalic, + Attribute::NoUnderline => crossterm::style::Attribute::NoUnderline, + Attribute::NoBlink => crossterm::style::Attribute::NoBlink, + Attribute::NoReverse => crossterm::style::Attribute::NoReverse, + Attribute::NoHidden => crossterm::style::Attribute::NoHidden, + Attribute::NotCrossedOut => crossterm::style::Attribute::NotCrossedOut, + Attribute::Framed => crossterm::style::Attribute::Framed, + Attribute::Encircled => crossterm::style::Attribute::Encircled, + Attribute::OverLined => crossterm::style::Attribute::OverLined, + Attribute::NotFramedOrEncircled => crossterm::style::Attribute::NotFramedOrEncircled, + Attribute::NotOverLined => crossterm::style::Attribute::NotOverLined, + } +} diff --git a/src/style/color.rs b/src/style/color.rs new file mode 100644 index 0000000..ea7ab7a --- /dev/null +++ b/src/style/color.rs @@ -0,0 +1,116 @@ +/// Represents a color. +/// +/// This type is a simplified re-implementation of crossterm's Color enum. +/// See [crossterm::style::color](https://docs.rs/crossterm/latest/crossterm/style/enum.Color.html) +/// +/// # Platform-specific Notes +/// +/// The following list of 16 base colors are available for almost all terminals (Windows 7 and 8 included). +/// +/// | Light | Dark | +/// | :--------- | :------------ | +/// | `DarkGrey` | `Black` | +/// | `Red` | `DarkRed` | +/// | `Green` | `DarkGreen` | +/// | `Yellow` | `DarkYellow` | +/// | `Blue` | `DarkBlue` | +/// | `Magenta` | `DarkMagenta` | +/// | `Cyan` | `DarkCyan` | +/// | `White` | `Grey` | +/// +/// Most UNIX terminals and Windows 10 consoles support additional colors. +/// See [Color::Rgb] or [Color::AnsiValue] for more info. +/// +/// Usage: +/// +/// Check [crate::Cell::bg], [crate::Cell::fg] and on how to use it. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub enum Color { + /// Resets the terminal color. + Reset, + + /// Black color. + Black, + + /// Dark grey color. + DarkGrey, + + /// Light red color. + Red, + + /// Dark red color. + DarkRed, + + /// Light green color. + Green, + + /// Dark green color. + DarkGreen, + + /// Light yellow color. + Yellow, + + /// Dark yellow color. + DarkYellow, + + /// Light blue color. + Blue, + + /// Dark blue color. + DarkBlue, + + /// Light magenta color. + Magenta, + + /// Dark magenta color. + DarkMagenta, + + /// Light cyan color. + Cyan, + + /// Dark cyan color. + DarkCyan, + + /// White color. + White, + + /// Grey color. + Grey, + + /// An RGB color. See [RGB color model](https://en.wikipedia.org/wiki/RGB_color_model) for more info. + /// + /// Most UNIX terminals and Windows 10 supported only. + /// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info. + Rgb { r: u8, g: u8, b: u8 }, + + /// An ANSI color. See [256 colors - cheat sheet](https://jonasjacek.github.io/colors/) for more info. + /// + /// Most UNIX terminals and Windows 10 supported only. + /// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info. + AnsiValue(u8), +} + +/// Map the internal mirrored [Color] enum to the actually used [crossterm::style::Color]. +pub(crate) fn map_color(color: Color) -> crossterm::style::Color { + match color { + Color::Reset => crossterm::style::Color::Reset, + Color::Black => crossterm::style::Color::Black, + Color::DarkGrey => crossterm::style::Color::DarkGrey, + Color::Red => crossterm::style::Color::Red, + Color::DarkRed => crossterm::style::Color::DarkRed, + Color::Green => crossterm::style::Color::Green, + Color::DarkGreen => crossterm::style::Color::DarkGreen, + Color::Yellow => crossterm::style::Color::Yellow, + Color::DarkYellow => crossterm::style::Color::DarkYellow, + Color::Blue => crossterm::style::Color::Blue, + Color::DarkBlue => crossterm::style::Color::DarkBlue, + Color::Magenta => crossterm::style::Color::Magenta, + Color::DarkMagenta => crossterm::style::Color::DarkMagenta, + Color::Cyan => crossterm::style::Color::Cyan, + Color::DarkCyan => crossterm::style::Color::DarkCyan, + Color::White => crossterm::style::Color::White, + Color::Grey => crossterm::style::Color::Grey, + Color::Rgb { r, g, b } => crossterm::style::Color::Rgb { r, g, b }, + Color::AnsiValue(value) => crossterm::style::Color::AnsiValue(value), + } +} diff --git a/src/style/mod.rs b/src/style/mod.rs index 6976cd1..44fbf19 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -1,24 +1,51 @@ -/// This module provides styling presets for tables.\ -/// Every preset has an example preview. -pub mod presets; - +#[cfg(all(feature = "tty", not(feature = "reexport_crossterm")))] +mod attribute; +mod cell; +#[cfg(all(feature = "tty", not(feature = "reexport_crossterm")))] +mod color; +mod column; /// Contains modifiers, that can be used to alter certain parts of a preset.\ /// For instance, the [UTF8_ROUND_CORNERS](modifiers::UTF8_ROUND_CORNERS) replaces all corners with round UTF8 box corners. pub mod modifiers; - +/// This module provides styling presets for tables.\ +/// Every preset has an example preview. +pub mod presets; mod table; -mod cell; - -mod column; - pub use cell::CellAlignment; pub use column::{ColumnConstraint, Width}; -pub use table::{ContentArrangement, TableComponent}; - -/// Attributes used for styling cell content. Reexport of crossterm's [Attributes](crossterm::style::Attribute) enum. #[cfg(feature = "tty")] -pub use crossterm::style::Attribute; -/// Colors used for styling cell content. Reexport of crossterm's [Color](crossterm::style::Color) enum. +pub(crate) use styling_enums::{map_attribute, map_color}; #[cfg(feature = "tty")] -pub use crossterm::style::Color; +pub use styling_enums::{Attribute, Color}; +pub use table::{ContentArrangement, TableComponent}; + +/// Convenience module to have cleaner and "identical" conditional re-exports for style enums. +#[cfg(all(feature = "tty", not(feature = "reexport_crossterm")))] +mod styling_enums { + pub use super::attribute::*; + pub use super::color::*; +} + +/// Re-export the crossterm type directly instead of using the internal mirrored types. +/// This result in possible ABI incompatibilities when using comfy_table and crossterm in the same +/// project with different versions, but may also be very convenient for developers. +#[cfg(all(feature = "tty", feature = "reexport_crossterm"))] +mod styling_enums { + /// Attributes used for styling cell content. Reexport of crossterm's [Attributes](crossterm::style::Attribute) enum. + pub use crossterm::style::Attribute; + /// Colors used for styling cell content. Reexport of crossterm's [Color](crossterm::style::Color) enum. + pub use crossterm::style::Color; + + /// Convenience function to have the same mapping code for reexported types. + #[inline] + pub(crate) fn map_attribute(attribute: Attribute) -> Attribute { + attribute + } + + /// Convenience function to have the same mapping code for reexported types. + #[inline] + pub(crate) fn map_color(color: Color) -> Color { + color + } +} diff --git a/src/utils/formatting/content_format.rs b/src/utils/formatting/content_format.rs index fbf35e0..93e8ee1 100644 --- a/src/utils/formatting/content_format.rs +++ b/src/utils/formatting/content_format.rs @@ -8,6 +8,8 @@ use super::content_split::split_line; use crate::cell::Cell; use crate::row::Row; use crate::style::CellAlignment; +#[cfg(feature = "tty")] +use crate::style::{map_attribute, map_color}; use crate::table::Table; use crate::utils::ColumnDisplayInfo; @@ -253,16 +255,16 @@ fn style_line(line: String, cell: &Cell) -> String { // Apply text color if let Some(color) = cell.fg { - content = content.with(color); + content = content.with(map_color(color)); } // Apply background color if let Some(color) = cell.bg { - content = content.on(color); + content = content.on(map_color(color)); } for attribute in cell.attributes.iter() { - content = content.attribute(*attribute); + content = content.attribute(map_attribute(*attribute)); } content.to_string() diff --git a/tests/all/property_test.rs b/tests/all/property_test.rs index 3e6435d..95df0dc 100644 --- a/tests/all/property_test.rs +++ b/tests/all/property_test.rs @@ -212,7 +212,7 @@ proptest! { #[cfg(feature = "integration_test")] // Only run this test, if the `integration_test` is enabled. // Without this flag, we don't have access to some util functions in comfy_table, that - // aren't by default. + // aren't exposed by default. enforce_constraints(&table, formatted, lines)? } } From 45abeefaf19693ecab80c9c78848cfae942c2e38 Mon Sep 17 00:00:00 2001 From: Arne Beer Date: Sun, 28 May 2023 18:39:54 +0200 Subject: [PATCH 2/3] meta: Bump rust version to v1.64 --- .github/workflows/test.yml | 2 +- CHANGELOG.md | 4 +++- Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a19ca9..94276a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: - x86_64-pc-windows-msvc - x86_64-apple-darwin - wasm32-wasi - toolchain: [stable, nightly, 1.62] + toolchain: [stable, nightly, 1.64] include: - target: x86_64-unknown-linux-gnu os: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 40ad564..468335a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), To fix this, these enums are now mirrored and internally mapped to their crossterm equivalents, which allows us to safely bump crossterm whenever a new version is released. This change will only affect you if your projects explicitly use crossterm and comfy-table at the same time **and** feed crossterm's native types into comfy-table. - This change allows us to bump the crossterm dependency in the future, without having to release a major version. + If one wants the old behavior for convenience reasons, this can be enabled via a feature flag. + However, **this is also a opt-in to potential breaking changes on minor/patch versions**. +- Bump minimum version to v1.64 ### Added diff --git a/Cargo.toml b/Cargo.toml index 28c9540..e1f76cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ documentation = "https://docs.rs/comfy-table/" license = "MIT" keywords = ["terminal", "table", "unicode"] readme = "README.md" -rust-version = "1.62" +rust-version = "1.64" edition = "2021" [badges] From 45cdce4904887e2ca32cc41fa0ed47bfe078b04f Mon Sep 17 00:00:00 2001 From: Arne Beer Date: Sun, 28 May 2023 18:46:50 +0200 Subject: [PATCH 3/3] ci: Don't fail fast --- .github/workflows/lint.yml | 1 + .github/workflows/test.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c2d1da4..11569d4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -21,6 +21,7 @@ jobs: name: Tests on ${{ matrix.os }} for ${{ matrix.toolchain }} runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 94276a8..4107095 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,6 +21,7 @@ jobs: name: Test target ${{ matrix.target }} on ${{ matrix.os }} for ${{ matrix.toolchain }} runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: target: - x86_64-unknown-linux-gnu