Skip to content

Commit

Permalink
Merge pull request #47 from roee88/no-tty
Browse files Browse the repository at this point in the history
Add a feature flag for tty support
  • Loading branch information
Nukesor committed Aug 11, 2021
2 parents 506a10e + 39369ec commit 9d58bd1
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 4 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Expand Up @@ -46,3 +46,27 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
wasm:
name: Check wasm32-wasi support with ${{ matrix.toolchain }} toolchain
runs-on: ubuntu-latest
strategy:
matrix:
toolchain: [stable, nightly]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
target: wasm32-wasi
toolchain: ${{ matrix.toolchain }}
override: true

- name: cargo build
uses: actions-rs/cargo@v1
with:
command: build
args: --release --no-default-features --target wasm32-wasi
15 changes: 14 additions & 1 deletion Cargo.toml
Expand Up @@ -15,11 +15,16 @@ edition = "2018"
maintenance = { status = "actively-developed" }

[dependencies]
crossterm = "0.20"
crossterm = {version = "0.20", optional = true }
strum = "0.21"
strum_macros = "0.21"
unicode-width = "0.1"


[features]
default = ["tty"]
tty = ["crossterm"]

[dev-dependencies]
pretty_assertions = "0.7"
doc-comment = "0.3"
Expand All @@ -29,3 +34,11 @@ criterion = "0.3"
[[bench]]
name = "build_tables"
harness = false

[[example]]
name = "no_tty"
path = "examples/readme_table_no_tty.rs"

[[example]]
name = "readme_table"
path = "examples/readme_table.rs"
27 changes: 27 additions & 0 deletions benches/build_tables.rs
Expand Up @@ -6,6 +6,7 @@ use comfy_table::Width::*;
use comfy_table::*;

/// Build the readme table
#[cfg(feature = "tty")]
fn build_readme_table() {
let mut table = Table::new();
table.load_preset(UTF8_FULL)
Expand Down Expand Up @@ -37,6 +38,32 @@ fn build_readme_table() {
let _ = table.lines();
}

#[cfg(not(feature = "tty"))]
fn build_readme_table() {
let mut table = Table::new();
table.load_preset(UTF8_FULL)
.set_content_arrangement(ContentArrangement::Dynamic)
.set_table_width(80)
.set_header(vec![
Cell::new("Header1"),
Cell::new("Header2"),
Cell::new("Header3"),
])
.add_row(vec![
Cell::new("This is a bold text"),
Cell::new("This is a green text"),
Cell::new("This one has black background"),
])
.add_row(vec![
Cell::new("Blinky boi"),
Cell::new("This table's content is dynamically arranged. The table is exactly 80 characters wide.\nHere comes a reallylongwordthatshoulddynamicallywrap"),
Cell::new("COMBINE ALL THE THINGS"),
]);

// Build the table.
let _ = table.lines();
}

/// Create a dynamic 10x10 Table with width 400 and unevenly distributed content.
/// On top of that, most of the columns have some kind of constraint.
fn build_huge_table() {
Expand Down
29 changes: 29 additions & 0 deletions examples/readme_table_no_tty.rs
@@ -0,0 +1,29 @@
use comfy_table::presets::UTF8_FULL;
use comfy_table::*;

// This example works even with the `tty` feature disabled
// You can try it out with `cargo run --example no_tty --no-default-features`

fn main() {
let mut table = Table::new();
table.load_preset(UTF8_FULL)
.set_content_arrangement(ContentArrangement::Dynamic)
.set_table_width(80)
.set_header(vec![
Cell::new("Header1"),
Cell::new("Header2"),
Cell::new("Header3"),
])
.add_row(vec![
Cell::new("No bold text without tty"),
Cell::new("No colored text without tty"),
Cell::new("No custom background without tty"),
])
.add_row(vec![
Cell::new("Blinky boi"),
Cell::new("This table's content is dynamically arranged. The table is exactly 80 characters wide.\nHere comes a reallylongwordthatshoulddynamicallywrap"),
Cell::new("Done"),
]);

println!("{}", table);
}
11 changes: 11 additions & 0 deletions src/cell.rs
@@ -1,3 +1,4 @@
#[cfg(feature = "tty")]
use crossterm::style::{Attribute, Color};

use crate::style::CellAlignment;
Expand All @@ -13,8 +14,11 @@ pub struct Cell {
/// The default is ` `.
pub(crate) delimiter: Option<char>,
pub(crate) alignment: Option<CellAlignment>,
#[cfg(feature = "tty")]
pub(crate) fg: Option<Color>,
#[cfg(feature = "tty")]
pub(crate) bg: Option<Color>,
#[cfg(feature = "tty")]
pub(crate) attributes: Vec<Attribute>,
}

Expand All @@ -29,8 +33,11 @@ impl Cell {
.collect(),
delimiter: None,
alignment: None,
#[cfg(feature = "tty")]
fg: None,
#[cfg(feature = "tty")]
bg: None,
#[cfg(feature = "tty")]
attributes: Vec::new(),
}
}
Expand Down Expand Up @@ -77,6 +84,7 @@ impl Cell {
/// let mut cell = Cell::new("Some content")
/// .fg(Color::Red);
/// ```
#[cfg(feature = "tty")]
pub fn fg(mut self, color: Color) -> Self {
self.fg = Some(color);

Expand All @@ -94,6 +102,7 @@ impl Cell {
/// let mut cell = Cell::new("Some content")
/// .bg(Color::Red);
/// ```
#[cfg(feature = "tty")]
pub fn bg(mut self, color: Color) -> Self {
self.bg = Some(color);

Expand All @@ -112,13 +121,15 @@ impl Cell {
/// let mut cell = Cell::new("Some content")
/// .add_attribute(Attribute::Bold);
/// ```
#[cfg(feature = "tty")]
pub fn add_attribute(mut self, attribute: Attribute) -> Self {
self.attributes.push(attribute);

self
}

/// Same as add_attribute, but you can pass a vector of [Attributes](Attribute)
#[cfg(feature = "tty")]
pub fn add_attributes(mut self, mut attribute: Vec<Attribute>) -> Self {
self.attributes.append(&mut attribute);

Expand Down
2 changes: 2 additions & 0 deletions src/style/mod.rs
Expand Up @@ -17,6 +17,8 @@ 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.
#[cfg(feature = "tty")]
pub use crossterm::style::Color;
19 changes: 19 additions & 0 deletions src/table.rs
Expand Up @@ -4,7 +4,9 @@ use std::fmt;
use std::iter::IntoIterator;
use std::slice::{Iter, IterMut};

#[cfg(feature = "tty")]
use crossterm::terminal::size;
#[cfg(feature = "tty")]
use crossterm::tty::IsTty;
use strum::IntoEnumIterator;

Expand Down Expand Up @@ -137,6 +139,7 @@ impl Table {
///
/// If neither is not possible, `None` will be returned.\
/// This implies that both the [Dynamic](ContentArrangement::Dynamic) mode and the [Percentage](crate::style::ColumnConstraint::Percentage) constraint won't work.
#[cfg(feature = "tty")]
pub fn get_table_width(&self) -> Option<u16> {
if let Some(width) = self.table_width {
Some(width)
Expand All @@ -151,6 +154,15 @@ impl Table {
}
}

#[cfg(not(feature = "tty"))]
pub fn get_table_width(&self) -> Option<u16> {
if let Some(width) = self.table_width {
Some(width)
} else {
None
}
}

/// Specify how Comfy Table should arrange the content in your table.
///
/// ```
Expand Down Expand Up @@ -196,6 +208,7 @@ impl Table {
///
/// This function respects the [Table::force_no_tty] function.\
/// Otherwise we try to determine, if we are on a tty.
#[cfg(feature = "tty")]
pub fn is_tty(&self) -> bool {
if self.no_tty {
return false;
Expand All @@ -204,6 +217,11 @@ impl Table {
::std::io::stdout().is_tty()
}

#[cfg(not(feature = "tty"))]
pub fn is_tty(&self) -> bool {
false
}

/// Enforce terminal styling.
///
/// Only useful if you forcefully disabled tty, but still want those fancy terminal styles.
Expand All @@ -215,6 +233,7 @@ impl Table {
/// table.force_no_tty()
/// .enforce_styling();
/// ```
#[cfg(feature = "tty")]
pub fn enforce_styling(&mut self) -> &mut Self {
self.enforce_styling = true;

Expand Down
22 changes: 19 additions & 3 deletions src/utils/formatting/content_format.rs
@@ -1,3 +1,4 @@
#[cfg(feature = "tty")]
use crossterm::style::{style, Stylize};
use unicode_width::UnicodeWidthStr;

Expand Down Expand Up @@ -123,12 +124,26 @@ pub fn format_row(
.iter()
.map(|line| align_line(line.to_string(), info, cell));

// Style the cell if necessary.
// Apply tty styling for this cell.
#[cfg(feature = "tty")]
let cell_lines = apply_tty_styling(table, cell, cell_lines).into_iter();

temp_row_content.push(cell_lines.collect());
}

#[cfg(feature = "tty")]
/// A small wrapper around the top-level cell styling logic. It's only used to have a clear
/// separation of our tty styling logic for the `tty` feature flag.
fn apply_tty_styling(
table: &Table,
cell: &Cell,
cell_lines: impl Iterator<Item = String>,
) -> Vec<String> {
if table.should_style() {
let cell_lines = cell_lines.map(|line| style_line(line, cell));
temp_row_content.push(cell_lines.collect());
cell_lines.collect()
} else {
temp_row_content.push(cell_lines.collect());
cell_lines.collect()
}
}

Expand Down Expand Up @@ -223,6 +238,7 @@ fn pad_line(line: String, info: &ColumnDisplayInfo) -> String {
padded_line
}

#[cfg(feature = "tty")]
fn style_line(line: String, cell: &Cell) -> String {
let mut content = style(line);

Expand Down
2 changes: 2 additions & 0 deletions tests/all/mod.rs
@@ -1,4 +1,5 @@
mod alignment_test;
#[cfg(feature = "tty")]
mod combined_test;
mod constraints_test;
mod content_arrangement_test;
Expand All @@ -9,5 +10,6 @@ mod padding_test;
mod presets_test;
mod property_test;
mod simple_test;
#[cfg(feature = "tty")]
mod styling_test;
mod utf_8_characters;

0 comments on commit 9d58bd1

Please sign in to comment.