From 2906ece3f17e02613505d41d40ff74491e515450 Mon Sep 17 00:00:00 2001 From: Patrick LaFontaine <32135464+Pat-Lafon@users.noreply.github.com> Date: Tue, 21 May 2024 00:30:44 -0700 Subject: [PATCH 1/3] Try to port from Terminal to anstream/anstyle --- Cargo.toml | 3 +- src/lib.rs | 5 ++- src/row.rs | 5 ++- src/style.rs | 110 +++++++++++++++++++++++++-------------------------- 4 files changed, 61 insertions(+), 62 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1f51945..e704d85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,8 @@ license = "Apache-2.0/MIT" edition = "2018" [dependencies] -term = "0.7" +anstream = "0.6.0" +anstyle = "1.0" [dev-dependencies] diff = "0.1" diff --git a/src/lib.rs b/src/lib.rs index 4b8aa72..1be4f57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,11 +2,12 @@ //! fixed-sized canvas and then convert that canvas into ASCII //! characters. ANSI styling is supported. +use anstream::stream::RawStream; + use crate::style::Style; use std::cmp; use std::iter::ExactSizeIterator; use std::ops::Range; -use term::Terminal; mod row; #[cfg(test)] @@ -142,7 +143,7 @@ impl AsciiCanvas { self.in_range_index(r, self.columns) } - pub fn write_to(&self, term: &mut T) -> term::Result<()> { + pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { for row in self.to_strings() { row.write_to(term)?; writeln!(term, "")?; diff --git a/src/row.rs b/src/row.rs index c2bb259..c11b388 100644 --- a/src/row.rs +++ b/src/row.rs @@ -1,6 +1,7 @@ +use anstream::stream::RawStream; + use crate::style::{Style, StyleCursor}; use std::fmt::{Debug, Display, Error, Formatter}; -use term::{self, Terminal}; pub struct Row { text: String, @@ -16,7 +17,7 @@ impl Row { } } - pub fn write_to(&self, term: &mut T) -> term::Result<()> { + pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { let mut cursor = StyleCursor::new(term)?; for (character, &style) in self.text.trim_end().chars().zip(&self.styles) { cursor.set_style(style)?; diff --git a/src/style.rs b/src/style.rs index 8ad90b7..e84f045 100644 --- a/src/style.rs +++ b/src/style.rs @@ -4,7 +4,8 @@ //! etc. use std::default::Default; -use term::{self, Terminal}; + +use anstream::stream::RawStream; #[derive(Copy, Clone, Default, PartialEq, Eq)] pub struct Style { @@ -93,96 +94,91 @@ impl Style { /// Attempts to apply the given style to the given terminal. If /// the style is not supported, either there is no effect or else /// a similar, substitute style may be applied. - pub fn apply(self, term: &mut T) -> term::Result<()> { - term.reset()?; + pub fn apply(self, term: &mut T) -> std::io::Result<()> { + let mut s = anstyle::Style::new(); + s.write_reset_to(term)?; macro_rules! fg_color { ($color:expr, $term_color:ident) => { if self.contains($color) { - if term.supports_color() { - term.fg(term::color::$term_color)?; - } + s = s.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::$term_color))); } }; } - fg_color!(FG_BLACK, BLACK); - fg_color!(FG_BLUE, BLUE); - fg_color!(FG_BRIGHT_BLACK, BRIGHT_BLACK); - fg_color!(FG_BRIGHT_BLUE, BRIGHT_BLUE); - fg_color!(FG_BRIGHT_CYAN, BRIGHT_CYAN); - fg_color!(FG_BRIGHT_GREEN, BRIGHT_GREEN); - fg_color!(FG_BRIGHT_MAGENTA, BRIGHT_MAGENTA); - fg_color!(FG_BRIGHT_RED, BRIGHT_RED); - fg_color!(FG_BRIGHT_WHITE, BRIGHT_WHITE); - fg_color!(FG_BRIGHT_YELLOW, BRIGHT_YELLOW); - fg_color!(FG_CYAN, CYAN); - fg_color!(FG_GREEN, GREEN); - fg_color!(FG_MAGENTA, MAGENTA); - fg_color!(FG_RED, RED); - fg_color!(FG_WHITE, WHITE); - fg_color!(FG_YELLOW, YELLOW); + fg_color!(FG_BLACK, Black); + fg_color!(FG_BLUE, Blue); + fg_color!(FG_BRIGHT_BLACK, BrightBlack); + fg_color!(FG_BRIGHT_BLUE, BrightBlue); + fg_color!(FG_BRIGHT_CYAN, BrightCyan); + fg_color!(FG_BRIGHT_GREEN, BrightGreen); + fg_color!(FG_BRIGHT_MAGENTA, BrightMagenta); + fg_color!(FG_BRIGHT_RED, BrightRed); + fg_color!(FG_BRIGHT_WHITE, BrightWhite); + fg_color!(FG_BRIGHT_YELLOW, BrightYellow); + fg_color!(FG_CYAN, Cyan); + fg_color!(FG_GREEN, Green); + fg_color!(FG_MAGENTA, Magenta); + fg_color!(FG_RED, Red); + fg_color!(FG_WHITE, White); + fg_color!(FG_YELLOW, Yellow); macro_rules! bg_color { ($color:expr, $term_color:ident) => { if self.contains($color) { - if term.supports_color() { - term.bg(term::color::$term_color)?; - } + s = s.bg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::$term_color))); } }; } - bg_color!(BG_BLACK, BLACK); - bg_color!(BG_BLUE, BLUE); - bg_color!(BG_BRIGHT_BLACK, BRIGHT_BLACK); - bg_color!(BG_BRIGHT_BLUE, BRIGHT_BLUE); - bg_color!(BG_BRIGHT_CYAN, BRIGHT_CYAN); - bg_color!(BG_BRIGHT_GREEN, BRIGHT_GREEN); - bg_color!(BG_BRIGHT_MAGENTA, BRIGHT_MAGENTA); - bg_color!(BG_BRIGHT_RED, BRIGHT_RED); - bg_color!(BG_BRIGHT_WHITE, BRIGHT_WHITE); - bg_color!(BG_BRIGHT_YELLOW, BRIGHT_YELLOW); - bg_color!(BG_CYAN, CYAN); - bg_color!(BG_GREEN, GREEN); - bg_color!(BG_MAGENTA, MAGENTA); - bg_color!(BG_RED, RED); - bg_color!(BG_WHITE, WHITE); - bg_color!(BG_YELLOW, YELLOW); + bg_color!(BG_BLACK, Black); + bg_color!(BG_BLUE, Blue); + bg_color!(BG_BRIGHT_BLACK, BrightBlack); + bg_color!(BG_BRIGHT_BLUE, BrightBlue); + bg_color!(BG_BRIGHT_CYAN, BrightCyan); + bg_color!(BG_BRIGHT_GREEN, BrightGreen); + bg_color!(BG_BRIGHT_MAGENTA, BrightMagenta); + bg_color!(BG_BRIGHT_RED, BrightRed); + bg_color!(BG_BRIGHT_WHITE, BrightWhite); + bg_color!(BG_BRIGHT_YELLOW, BrightYellow); + bg_color!(BG_CYAN, Cyan); + bg_color!(BG_GREEN, Green); + bg_color!(BG_MAGENTA, Magenta); + bg_color!(BG_RED, Red); + bg_color!(BG_WHITE, White); + bg_color!(BG_YELLOW, Yellow); macro_rules! attr { ($attr:expr, $term_attr:expr) => { if self.contains($attr) { let attr = $term_attr; - if term.supports_attr(attr) { - term.attr(attr)?; - } + s = s.effects(attr); } }; } - attr!(BOLD, term::Attr::Bold); - attr!(DIM, term::Attr::Dim); - attr!(ITALIC, term::Attr::Italic(true)); - attr!(UNDERLINE, term::Attr::Underline(true)); - attr!(BLINK, term::Attr::Blink); - attr!(STANDOUT, term::Attr::Standout(true)); - attr!(REVERSE, term::Attr::Reverse); - attr!(SECURE, term::Attr::Secure); + attr!(BOLD, anstyle::Effects::BOLD); + attr!(DIM, anstyle::Effects::DIMMED); + attr!(ITALIC, anstyle::Effects::ITALIC); + attr!(UNDERLINE, anstyle::Effects::UNDERLINE); + attr!(BLINK, anstyle::Effects::BLINK); + attr!(STANDOUT, anstyle::Effects::BOLD | anstyle::Effects::INVERT); + attr!(REVERSE, anstyle::Effects::INVERT); + attr!(SECURE, anstyle::Effects::HIDDEN); - Ok(()) + s.write_to(term) } } /////////////////////////////////////////////////////////////////////////// -pub struct StyleCursor<'term, T: ?Sized + Terminal> { +pub struct StyleCursor<'term, T: RawStream> { current_style: Style, term: &'term mut T, } -impl<'term, T: ?Sized + Terminal> StyleCursor<'term, T> { - pub fn new(term: &'term mut T) -> term::Result> { +impl<'term, T: RawStream> StyleCursor<'term, T> { + pub fn new(term: &'term mut T) -> std::io::Result> { let current_style = Style::default(); current_style.apply(term)?; Ok(StyleCursor { @@ -195,7 +191,7 @@ impl<'term, T: ?Sized + Terminal> StyleCursor<'term, T> { self.term } - pub fn set_style(&mut self, style: Style) -> term::Result<()> { + pub fn set_style(&mut self, style: Style) -> std::io::Result<()> { if style != self.current_style { style.apply(self.term)?; self.current_style = style; From 18361294729e287771721cc09073bf16ff158edd Mon Sep 17 00:00:00 2001 From: Patrick LaFontaine <32135464+Pat-Lafon@users.noreply.github.com> Date: Tue, 21 May 2024 01:09:28 -0700 Subject: [PATCH 2/3] weaken bounds to just Write --- Cargo.toml | 1 - src/lib.rs | 4 +--- src/row.rs | 4 +--- src/style.rs | 8 +++----- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e704d85..4ab09dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ license = "Apache-2.0/MIT" edition = "2018" [dependencies] -anstream = "0.6.0" anstyle = "1.0" [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 1be4f57..05cf6f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ //! fixed-sized canvas and then convert that canvas into ASCII //! characters. ANSI styling is supported. -use anstream::stream::RawStream; - use crate::style::Style; use std::cmp; use std::iter::ExactSizeIterator; @@ -143,7 +141,7 @@ impl AsciiCanvas { self.in_range_index(r, self.columns) } - pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { + pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { for row in self.to_strings() { row.write_to(term)?; writeln!(term, "")?; diff --git a/src/row.rs b/src/row.rs index c11b388..2175c32 100644 --- a/src/row.rs +++ b/src/row.rs @@ -1,5 +1,3 @@ -use anstream::stream::RawStream; - use crate::style::{Style, StyleCursor}; use std::fmt::{Debug, Display, Error, Formatter}; @@ -17,7 +15,7 @@ impl Row { } } - pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { + pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { let mut cursor = StyleCursor::new(term)?; for (character, &style) in self.text.trim_end().chars().zip(&self.styles) { cursor.set_style(style)?; diff --git a/src/style.rs b/src/style.rs index e84f045..462960b 100644 --- a/src/style.rs +++ b/src/style.rs @@ -5,8 +5,6 @@ use std::default::Default; -use anstream::stream::RawStream; - #[derive(Copy, Clone, Default, PartialEq, Eq)] pub struct Style { bits: u64, @@ -94,7 +92,7 @@ impl Style { /// Attempts to apply the given style to the given terminal. If /// the style is not supported, either there is no effect or else /// a similar, substitute style may be applied. - pub fn apply(self, term: &mut T) -> std::io::Result<()> { + pub fn apply(self, term: &mut T) -> std::io::Result<()> { let mut s = anstyle::Style::new(); s.write_reset_to(term)?; @@ -172,12 +170,12 @@ impl Style { /////////////////////////////////////////////////////////////////////////// -pub struct StyleCursor<'term, T: RawStream> { +pub struct StyleCursor<'term, T: std::io::Write> { current_style: Style, term: &'term mut T, } -impl<'term, T: RawStream> StyleCursor<'term, T> { +impl<'term, T: std::io::Write> StyleCursor<'term, T> { pub fn new(term: &'term mut T) -> std::io::Result> { let current_style = Style::default(); current_style.apply(term)?; From 68c1f13d91d90cb5b0e5660840e074d42fab5406 Mon Sep 17 00:00:00 2001 From: Patrick LaFontaine <32135464+Pat-Lafon@users.noreply.github.com> Date: Mon, 27 May 2024 15:22:49 -0700 Subject: [PATCH 3/3] Add std::io::IsTerminal bounds for is_terminal() --- src/lib.rs | 5 ++++- src/row.rs | 5 ++++- src/style.rs | 23 ++++++++++++++++------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 05cf6f6..343dcbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,10 @@ impl AsciiCanvas { self.in_range_index(r, self.columns) } - pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { + pub fn write_to( + &self, + term: &mut T, + ) -> std::io::Result<()> { for row in self.to_strings() { row.write_to(term)?; writeln!(term, "")?; diff --git a/src/row.rs b/src/row.rs index 2175c32..4c34a1e 100644 --- a/src/row.rs +++ b/src/row.rs @@ -15,7 +15,10 @@ impl Row { } } - pub fn write_to(&self, term: &mut T) -> std::io::Result<()> { + pub fn write_to( + &self, + term: &mut T, + ) -> std::io::Result<()> { let mut cursor = StyleCursor::new(term)?; for (character, &style) in self.text.trim_end().chars().zip(&self.styles) { cursor.set_style(style)?; diff --git a/src/style.rs b/src/style.rs index 462960b..4c75d38 100644 --- a/src/style.rs +++ b/src/style.rs @@ -92,14 +92,19 @@ impl Style { /// Attempts to apply the given style to the given terminal. If /// the style is not supported, either there is no effect or else /// a similar, substitute style may be applied. - pub fn apply(self, term: &mut T) -> std::io::Result<()> { + pub fn apply( + self, + term: &mut T, + ) -> std::io::Result<()> { let mut s = anstyle::Style::new(); s.write_reset_to(term)?; macro_rules! fg_color { ($color:expr, $term_color:ident) => { if self.contains($color) { - s = s.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::$term_color))); + if term.is_terminal() { + s = s.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::$term_color))); + } } }; } @@ -124,7 +129,9 @@ impl Style { macro_rules! bg_color { ($color:expr, $term_color:ident) => { if self.contains($color) { - s = s.bg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::$term_color))); + if term.is_terminal() { + s = s.bg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::$term_color))); + } } }; } @@ -149,8 +156,10 @@ impl Style { macro_rules! attr { ($attr:expr, $term_attr:expr) => { if self.contains($attr) { - let attr = $term_attr; - s = s.effects(attr); + if term.is_terminal() { + let attr = $term_attr; + s = s.effects(attr); + } } }; } @@ -170,12 +179,12 @@ impl Style { /////////////////////////////////////////////////////////////////////////// -pub struct StyleCursor<'term, T: std::io::Write> { +pub struct StyleCursor<'term, T: std::io::Write + std::io::IsTerminal> { current_style: Style, term: &'term mut T, } -impl<'term, T: std::io::Write> StyleCursor<'term, T> { +impl<'term, T: std::io::Write + std::io::IsTerminal> StyleCursor<'term, T> { pub fn new(term: &'term mut T) -> std::io::Result> { let current_style = Style::default(); current_style.apply(term)?;