Skip to main content

Crate styled_str

Crate styled_str 

Source
Expand description

Tools for parsing and managing ANSI-styled strings.

This library allows to:

One of guiding use cases for the library is hassle-free snapshot testing for styled strings, without the need to compare literal strings with ANSI escapes (which is brittle and not human-readable), and outputting more informative diff info than a simple assert_eq! would.

For the example of real-world usage, see the term-transcript crate.

§Styled strings

The core types exposed by this crate are StyledStr and StyledString. Both are a container for text + styling signaled via ANSI escape codes. StyledStr is borrowed (analog to &str), while StyledString is owned (analog to String). Styling is represented as a sequence of spans (SpanStr type) that cover the text in its entirety. Styles reuse the model from anstyle; i.e., a style is just a Style.

§Rich syntax

One way to create Styled strings is parsing rich-inspired syntax, either in compile time via the styled! macro, or in runtime via FromStr. Conversely, a Styled string can be converted to the rich format via its Display implementation.

The format is as follows:

  • Styling directives are enclosed in double brackets: [[ + ]].
  • A directive is a list of tokens separated by whitespace and/or commas , or semicolons ;.
  • A token represents an effect, e.g. bold or underline, a foreground color (e.g., red or #fed), or a background color (on + a color token, e.g. on blue).
  • By default, a directive completely overrides the previously applied directive. Hence, there is no need for special closing directives.
  • A directive can be made to inherit from the previously applied style by preceding all tokens with a *. This also allows to subtract effects by specifying them with a - or ! in front, like -bold or !italic. Similarly, -color / !color (or -fg / !fg) switches off the foreground color, and -on, !on, -bg, or !bg switches off the background color.
  • A directive may be empty: [[]]. As a special case, [[/]] (i.e., a single / token) is equivalent to an empty directive.

§Effects

The following effects are supported:

EffectAliases
boldb
italicit, i
underlineul, u
strikethroughstrike, s
dimmeddim
invertinverted, inv
blink
concealedconceal, hide, hidden

§Color tokens

A color may be represented as follows:

  • One of the 8 base terminal colors (black, red, green, yellow, blue, magenta, cyan, white)
  • One of the 8 bright terminal colors signaled via ! suffix or bright- prefix (e.g., blue! or bright-blue).
  • One of 256 indexed ANSI colors specified as color$idx or color($idx), e.g. color23 or color(254).
  • A 24-bit RGB color written in CSS-like hex format, e.g. #fa4 or #c0ffee.

§Syntax examples

use styled_str::{styled, StyledStr};

const STYLED: StyledStr = styled!("[[green! on white, bold]]Hello,[[/]] world[[it]]!");
assert_eq!(STYLED.text(), "Hello, world!");
assert_eq!(STYLED.spans().len(), 3);

Here, the first style applies to Hello,, then it is completely reset for world, and finally, the italic effect (and only it) is applied to !.

const STYLED: StyledStr = styled!("[[bold green!]]Hello[[* -bold]], world[[* invert]]!");

Here, there are again 3 styled spans, but the second and third ones inherit the preceding style. The second span removes the bold effect, and the third one inverts foreground and background colors.

§Other string functionality

§Parsing ANSI escapes

StyledString::from_ansi() and StyledString::from_ansi_bytes() allow parsing a styled string from ANSI escapes (e.g., captured from a terminal).

let str = StyledString::from_ansi(
    "\u{1b}[32mHello,\u{1b}[m world\u{1b}[1m!\u{1b}[m",
)?;
assert_eq!(str.text(), "Hello, world!");
assert_eq!(str.to_string(), "[[green]]Hello,[[/]] world[[bold]]!");

§Comparing styled strings

StyledStr::diff() allows comparing two styled strings both in terms of text and styles. TextDiff and StyleDiff provide more fine-grained control over comparison logic. These types can be Displayed / Debugged in order to provide rich human-readable info about differences (e.g., in the test code).

let left = styled!("Hello, [[bold dim white on #fa4]]world!");
let right = styled!("Hello, [[bold]]world[[/]]!");
let diff = left.diff(right).unwrap_err();
assert_matches!(&diff, Diff::Style(_));

// Will output detailed human-readable info about the diff.
println!("{diff}");

§Limitations

  • ANSI escape sequences other than SGR ones are either dropped (in case of CSI sequences), or lead to an error.

§Alternatives and similar tools

  • This crate builds on the anstyle library, using its styling data model. anstyle together with anstream provides tools to create / output ANSI-styled strings in runtime. It doesn’t cover creating strings in compile time, parsing ANSI-styled strings, or comparing styled strings.
  • color_print provides proc macros to create / output ANSI-styled strings using rich-like syntax.
  • parse-style allows parsing rich-like style specs.

§Crate features

§std

(On by default)

Enables std-specific functionality, such as Error trait implementations. Note that disabling this feature for now doesn’t make this crate no-std compatible.

Macros§

styled
Parses rich syntax into a StyledStr in compile time.

Structs§

Lines
Iterator over lines in a StyledStr. Returned by StyledStr::lines().
ParseError
Errors that can occur parsing StyledStrings from the rich syntax.
RichStyle
Wrapper for a Style that allows to represent it in rich syntax.
SpanStr
Text with a uniform Style attached to it. Returned by the StyledStr::spans() iterator.
StyleDiff
Difference in styles between two styled strings that can be output in detailed human-readable format via Display.
StyledStr
Borrowed ANSI-styled string.
StyledString
Heap-allocated styled string.
StyledStringBuilder
Builder for StyledStrings.
TextDiff
Text difference between two strings. ANSI-styled when printed (powered by pretty_assertions::Comparison).

Enums§

AnsiError
Errors that can occur when processing terminal output.
Diff
Generic difference between two StyledStrs: either a difference in text, or in styling.
HexColorError
Error parsing hexadecimal RGB color.
ParseErrorKind
Kind of a ParseError.

Functions§

parse_hex_color
Parses a hexadecimal RGB color like #c0ffee or #fa4.
rgb_color_to_hex
Converts an RGB color to its rich text representation, like #fb4 or #c0ffee.