#data #stylish #styling #details #format #macro #text

macro stylish-macros

Internal implementation details of stylish-core

3 unstable releases

0.1.1 Sep 13, 2022
0.1.0 Jul 29, 2022
0.0.0 Jan 3, 2021

#1808 in Procedural macros

Download history 102/week @ 2023-12-11 91/week @ 2023-12-18 59/week @ 2023-12-25 65/week @ 2024-01-01 101/week @ 2024-01-08 91/week @ 2024-01-15 54/week @ 2024-01-22 42/week @ 2024-01-29 64/week @ 2024-02-05 50/week @ 2024-02-12 59/week @ 2024-02-19 107/week @ 2024-02-26 81/week @ 2024-03-04 63/week @ 2024-03-11 62/week @ 2024-03-18 84/week @ 2024-03-25

295 downloads per month
Used in 6 crates (2 directly)

MIT/Apache

48KB
834 lines

version-badge license-badge rust-version-badge

Yet another crate implementing colorized text.

There was one primary design goal separating stylish from existing crates:

Applying styling to data should be decoupled from how that styling is output.

This came out of two usecases:

  1. A library crate that renders a "diagnostic" representation of a data format (think something JSON-like). This library is being used in both a WASM based web application and a CLI application; in both cases these applications would be improved by adding some syntax highlighting to the rendered data, but in one case we want to output HTML while the other requires ANSI color codes.

  2. A (different) CLI application which could use semantic coloring of different data types embedded in the output messages to make them easier to parse, with an option to turn the color off. To simplify toggling the color the rendering of the messages shouldn't need to continuously check whether color is currently on or not.

Along with this primary design goal, there was a secondary design goal:

Integrate into std::fmt as much as possible to leverage existing knowledge.

We already have a standardized formatting infrastructure in std::fmt. Developers already know how to work with this, and it is very easy to use. By reusing that existing design and just extending it where needed it should be trivial to get started with stylish.

Writing data with attributes

There are two primary mechanisms you can use to output data with attached attributes; either applying the attributes as part of the format string, or implementing stylish::Display to be able to print some type with attributes.

Applying attributes in format string

stylish's macros extend the standard fmt parameters to support setting attributes within (). These must come at the end of the parameters just before selecting which trait.

assert_eq!(
    stylish::html::format!("Hello {:(fg=red)}", "Ferris"),
    "Hello <span style=color:red>Ferris</span>",
);

Allowed attributes

There are two parameterised attributes, and 3 non-parameterised attributes:

  • fg specifies a Foreground style and takes a Color value in lowercase

  • bg specifies a Background style and also takes a Color value in lowercase

  • bold, normal and faint take no parameters and specify an Intensity style

Syntax change

The specific syntax change is extending format_spec like so:

format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][attributes]type
attributes := '(' [attribute [',' attribute]* [',']] ')'
attribute := key ['=' value]
key := identifier
value := identifier

Implementing a style for a type

stylish::Display is similar to std::fmt::Display but with a Formatter that supports setting style attributes. It can be specified by using the trait-selector s in a format string. See the Formatter docs for more details on how you can programmatically set the styles as you write out your data.

struct Name(&'static str);

impl stylish::Display for Name {
    fn fmt(&self, f: &mut stylish::Formatter<'_>) -> stylish::Result {
        let color = match self.0 {
            "Ferris" => stylish::Color::Red,
            "Gorris" => stylish::Color::Cyan,
            _ => stylish::Color::Default,
        };
        f.with(stylish::Foreground(color)).write_str(self.0)
    }
}

assert_eq!(
    stylish::html::format!("Hello {:s} and {:s}", Name("Ferris"), Name("Gorris")),
    "Hello <span style=color:red>Ferris</span> and <span style=color:cyan>Gorris</span>",
);

Features

Feature Activation Effect
std on-by-default Enables the io module (and io helpers in other modules)
alloc implied by std Enables String and a variety of items that use it
macros on-by-default Enables macros throughout the other enabled modules
ansi off-by-default Enables the ansi module and items that use it
html off-by-default Enables the html module and items that use it
plain off-by-default Enables the plain module and items that use it

Rust Version Policy

This crate only supports the current stable version of Rust, patch releases may use new features at any time.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~2.5MB
~51K SLoC