Skip to content

Commit

Permalink
Fix Style breakage
Browse files Browse the repository at this point in the history
Move OSControl out of Style

PR nushell#43 created a regression where code that manually instantiated
a Style could no longer be created without using the update
operator and Default trait on Style.

Rather than place non-public functions and data in Style move it
all into AnsiGenericString. This has the added benefit of greatly
simplifying the code.

Also encloses the control sequences in \x01 .. \x02 to mark those
portions which should be considered zero-width when displayed in
the terminal.

Fixes nushell#46
  • Loading branch information
Matt Helsley committed Jun 15, 2023
1 parent 98b763f commit c77adc5
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 313 deletions.
176 changes: 58 additions & 118 deletions src/ansi.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(missing_docs)]
use crate::style::{Color, OSControl, Style};
use crate::style::{Color, Style};
use crate::write::AnyWrite;
use std::fmt;

Expand All @@ -13,95 +13,75 @@ impl Style {
return Ok(());
}

if self.has_sgr() {
// Prefix everything with reset characters if needed
if self.with_reset {
write!(f, "\x1B[0m")?
}
// Prefix everything with reset characters if needed
if self.with_reset {
write!(f, "\x1B[0m")?
}

// "Specified Graphical Rendition" prefixes
// Write the codes’ prefix, then write numbers, separated by
// semicolons, for each text style we want to apply.
write!(f, "\x1B[")?;
let mut written_anything = false;

{
let mut write_char = |c| {
if written_anything {
write!(f, ";")?;
}
written_anything = true;
#[cfg(feature = "gnu_legacy")]
write!(f, "0")?;
write!(f, "{}", c)?;
Ok(())
};

if self.is_bold {
write_char('1')?
}
if self.is_dimmed {
write_char('2')?
}
if self.is_italic {
write_char('3')?
}
if self.is_underline {
write_char('4')?
}
if self.is_blink {
write_char('5')?
}
if self.is_reverse {
write_char('7')?
}
if self.is_hidden {
write_char('8')?
}
if self.is_strikethrough {
write_char('9')?
}
}
// Write the codes’ prefix, then write numbers, separated by
// semicolons, for each text style we want to apply.
write!(f, "\x1B[")?;
let mut written_anything = false;

// The foreground and background colors, if specified, need to be
// handled specially because the number codes are more complicated.
// (see `write_background_code` and `write_foreground_code`)
if let Some(bg) = self.background {
{
let mut write_char = |c| {
if written_anything {
write!(f, ";")?;
}
written_anything = true;
bg.write_background_code(f)?;
#[cfg(feature = "gnu_legacy")]
write!(f, "0")?;
write!(f, "{}", c)?;
Ok(())
};

if self.is_bold {
write_char('1')?
}

if let Some(fg) = self.foreground {
if written_anything {
write!(f, ";")?;
}
fg.write_foreground_code(f)?;
if self.is_dimmed {
write_char('2')?
}

// All the SGR codes end with an `m`, because reasons.
write!(f, "m")?;
}

// OS Control (OSC) prefixes
match self.oscontrol {
Some(OSControl::Hyperlink) => {
write!(f, "\x1B]8;;")?;
if self.is_italic {
write_char('3')?
}
if self.is_underline {
write_char('4')?
}
if self.is_blink {
write_char('5')?
}
Some(OSControl::Title) => {
write!(f, "\x1B]2;")?;
if self.is_reverse {
write_char('7')?
}
Some(OSControl::Icon) => {
write!(f, "\x1B]I;")?;
if self.is_hidden {
write_char('8')?
}
Some(OSControl::Cwd) => {
write!(f, "\x1B]7;")?;
if self.is_strikethrough {
write_char('9')?
}
}

// The foreground and background colors, if specified, need to be
// handled specially because the number codes are more complicated.
// (see `write_background_code` and `write_foreground_code`)
if let Some(bg) = self.background {
if written_anything {
write!(f, ";")?;
}
written_anything = true;
bg.write_background_code(f)?;
}

if let Some(fg) = self.foreground {
if written_anything {
write!(f, ";")?;
}
None => {}
fg.write_foreground_code(f)?;
}

// All the codes end with an `m`, because reasons.
write!(f, "m")?;

Ok(())
}

Expand All @@ -110,28 +90,14 @@ impl Style {
if self.is_plain() {
Ok(())
} else {
match self.oscontrol {
Some(OSControl::Hyperlink) => {
write!(f, "{}{}", HYPERLINK_RESET, RESET)
}
Some(OSControl::Title) | Some(OSControl::Icon) | Some(OSControl::Cwd) => {
write!(f, "{}", ST)
}
_ => {
write!(f, "{}", RESET)
}
}
write!(f, "{}", RESET)
}
}
}

/// The code to send to reset all styles and return to `Style::default()`.
pub static RESET: &str = "\x1B[0m";

// The "String Termination" code. Used for OS Control (OSC) sequences.
static ST: &str = "\x1B\\";
pub(crate) static HYPERLINK_RESET: &str = "\x1B]8;;\x1B\\";

impl Color {
fn write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
match self {
Expand Down Expand Up @@ -396,33 +362,7 @@ impl fmt::Display for Infix {
}
Difference::Reset => {
let f: &mut dyn fmt::Write = f;

match (self.0, self.1) {
(
Style {
oscontrol: Some(OSControl::Hyperlink),
..
},
Style {
oscontrol: None, ..
},
) => {
write!(f, "{}{}", HYPERLINK_RESET, self.1.prefix())
}
(
Style {
oscontrol: Some(_), ..
},
Style {
oscontrol: None, ..
},
) => {
write!(f, "{}{}", ST, self.1.prefix())
}
(_, _) => {
write!(f, "{}{}", RESET, self.1.prefix())
}
}
write!(f, "{}{}", RESET, self.1.prefix())
}
Difference::Empty => {
Ok(()) // nothing to write
Expand Down
12 changes: 0 additions & 12 deletions src/difference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ impl Difference {
return Empty;
}

if first.has_sgr() && !next.has_sgr() {
return Reset;
}

// Cannot un-bold, so must Reset.
if first.is_bold && !next.is_bold {
return Reset;
Expand Down Expand Up @@ -91,10 +87,6 @@ impl Difference {
return Reset;
}

if first.oscontrol.is_some() && next.oscontrol.is_none() {
return Reset;
}

let mut extra_styles = Style::default();

if first.is_bold != next.is_bold {
Expand Down Expand Up @@ -137,10 +129,6 @@ impl Difference {
extra_styles.background = next.background;
}

if first.oscontrol != next.oscontrol {
extra_styles.oscontrol = next.oscontrol;
}

ExtraStyles(extra_styles)
}
}
Expand Down
Loading

0 comments on commit c77adc5

Please sign in to comment.