1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
//! A dead simple ANSI terminal color painting library.
//!
//! # Features
//!
//! Why *y*et another *ANSI* terminal coloring library? Here are some reasons:
//!
//! * This library makes simple things _simple_: `use` [`Paint`] and go!
//! * Zero dependencies by default. It really is simple.
//! * Zero allocations except as needed by opt-in [wrapping](#wrapping).
//! * [Automatic Windows support] for the vast majority (95%+) of Windows
//! users.
//! * [Featureful `no_std`], no-`alloc`, support with `default-features =
//! false`.
//! * [`Style` constructors are `const`]: store styles statically, even with
//! dynamic conditions!
//! * _Any_ type implementing a formatting trait can be styled, not just
//! strings.
//! * Styling can be [enabled] and [disabled] globally and [dynamically], on
//! the fly.
//! * A `Style` can be predicated on arbitrary [conditions](#per-style).
//! * Formatting specifiers like `{:x}` and `{:08b}` are supported and
//! preserved!
//! * [Built-in (optional) conditions] for [TTY detection] and [common
//! environment variables].
//! * Arbitrary items can be [_masked_] for selective disabling.
//! * Styling can [_wrap_] to preserve styling across resets.
//! * Styling can [_linger_] beyond a single value.
//! * Experimental support for [hyperlinking] is included.
//! * The name `yansi` is pretty cool 😎.
//!
//! All that said, `yansi` borrows API ideas from older libraries as well as
//! implementation details from [`ansi_term`].
//!
//! [`ansi_term`]: https://crates.io/crates/ansi_term
//! [`colored`]: https://crates.io/crates/colored
//! [`term_painter`]: https://crates.io/crates/term-painter
//! [_masked_]: #masking
//! [_wrap_]: #wrapping
//! [_linger_]: #lingering
//! [enabled]: crate::enable
//! [disabled]: crate::disable
//! [dynamically]: crate::whenever
//! [enabled conditionally]: Condition
//! [TTY detection]: Condition#impl-Condition-1
//! [common environment variables]: Condition#impl-Condition-2
//! [Automatic Windows support]: #windows
//! [Built-in (optional) conditions]: Condition#built-in-conditions
//! [`Style` constructors are `const`]: #uniform-const-builders
//! [hyperlinking]: hyperlink
//! [Featureful `no_std`]: #crate-features
//!
//! # Usage
//!
//! The [`Paint`] trait is implemented for every type. Import it and call
//! chainable builder methods:
//!
//! ```rust
//! use yansi::Paint;
//!
//! println!("Testing, {}, {}, {}!",
//! "Ready".bold(),
//! "Set".yellow().italic(),
//! "STOP".white().on_red().bright().underline().bold());
//! ```
//!
//! `>` Testing,
//! <b>Ready</b>,
//! <span style="color: yellow;"><i><b>Set</b></i></span>,
//! <span style="color: white; background: red;"><u><b>STOP</b></u></span>!
//!
//! The methods return a [`Painted`] type which consists of a [`Style`] and a
//! reference to the receiver. Displaying a [`Painted`] (via `print!()`,
//! `format!()`, etc) results in emitting ANSI escape codes that effectuate the
//! style.
//!
//! ## Uniform `const` Builders
//!
//! All builder methods are uniformly available for [`Style`], [`Color`], and
//! [`Painted`], which means you can chain calls across library types. All
//! methods are `const`, allowing creations of `const` or `static` [`Style`]s. A
//! `Style` can be directly applied to values with [`.paint()`](Paint::paint()),
//! from [`Paint::paint()`], available for every type:
//!
//! ```rust
//! use yansi::{Paint, Style, Color::*};
//!
//! // `const` constructors allow static `Style`s for easy reuse
//! static ALERT: Style = White.bright().underline().italic().on_red();
//!
//! println!("Testing, {}, {}, {}!",
//! "Ready".bold(),
//! "Set".yellow().bold(),
//! "STOP".paint(ALERT));
//! ```
//!
//! `>` Testing,
//! <b>Ready</b>,
//! <span style="color: yellow;"><b>Set</b></span>,
//! <span style="color: white; background: red;"><u><em>STOP</em></u></span>!
//!
//! ## Conditional Styling
//!
//! ### Globally
//!
//! Styling is enabled by default but can be enabled and disabled globally via
//! [`enable()`] and [`disable()`]. When styling is disabled, no ANSI escape
//! codes are emitted, and [_masked_] values are omitted entirely.
//!
//! Global styling can also be dynamically enabled and disabled using
//! [`whenever()`] with an arbitrary [`Condition`]: a function that returns
//! `true` or `false`. This condition is evaluated each time a [`Painted`] item
//! is displayed. The associated styling is enabled, and mask values emitted,
//! exactly when and only when the condition returns `true`.
//!
//! ### Per-`Style`
//!
//! A specific `Style` can itself be conditionally applied by using
//! [`.whenever()`](Style::whenever()):
//!
//! ```rust
//! # #[cfg(feature = "detect-tty")] {
//! use yansi::{Paint, Style, Color::*, Condition};
//!
//! static WARNING: Style = Black.bold().on_yellow().whenever(Condition::STDERR_IS_TTY);
//!
//! eprintln!("{}", "Bees can sting!".paint(WARNING));
//! # }
//! ```
//!
//! With the above, if `stderr` is a TTY, then:
//! `>` <span style="background: yellow; color: black;"><b>Bees can sting!</b></span>
//!
//! If it is not a TTY, styling is not emitted:
//! `>` Bees can sting!
//!
//! See [`Condition`] for a list of built-in conditions which require enabling
//! crate features.
//!
//! # Quirks
//!
//! As a convenience, `yansi` implements several "quirks", applicable via
//! [`Quirk`] and the respective methods, that modify if and how styling is
//! presented to the terminal. These quirks do not correspond to any ANSI
//! styling sequences.
//!
//! ## Masking
//!
//! Items can be arbitrarily _masked_ with the [`mask()`](Paint::mask()) builder
//! method. Masked values are not emitted when styling is disabled, globally or
//! for a given style. This allows selective output based on whether styling is
//! enabled.
//!
//! One use for this feature is to print certain characters only when styling is
//! enabled. For instance, you might wish to emit the 🎨 emoji when coloring is
//! enabled but not otherwise. This can be accomplished by masking the emoji:
//!
//! ```rust
//! use yansi::Paint;
//!
//! println!("I like colors!{}", " 🎨".mask());
//! ```
//!
//! When styling is enabled, this prints: `>` I like colors! 🎨
//!
//! With styling disabled, this prints: `>` I like colors!
//!
//! ## Wrapping
//!
//! **Note:** _Either the `std` or `alloc` feature is required for wrapping.
//! `std` is enabled by default. See [crate features](#crate-features)._
//!
//! Styling can _wrap_ via [`Quirk::Wrap`] or the equivalent
//! [`wrap()`](Painted::wrap()) constructor. A wrapping style modifies any
//! styling resets emitted by the internal value so that they correspond to the
//! wrapping style. In other words, the "reset" style of the wrapped item is
//! modified to be the style being `.wrap()`d.
//!
//! Wrapping is useful in situations where opaque and arbitrary values must be
//! styled consistently irrespective of any existing styling. For example, a
//! generic logger might want to style messages based on log levels
//! consistently, even when those messages may already include styling. Wrapping
//! exists to enable such consistent styling:
//!
//! ```rust
//! use yansi::Paint;
//!
//! // Imagine that `inner` is opaque and we don't know it's styling.
//! let inner = format!("{} and {}", "Stop".red(), "Go".green());
//!
//! // We can use `wrap` to ensure anything in `inner` not styled is blue.
//! println!("Hey! {}", inner.blue().wrap());
//! ```
//!
//! Thanks to wrapping, this prints:
//! `>` Hey! <span style="color: blue">
//! <span style="color: red">Stop</span> and
//! <span style="color: green">Go</span>
//! </span>
//!
//! Without wrapping, the reset after `"Stop".red()` would not be overwritten:
//! `>` Hey! <span style="color: red">Stop</span> and <span style="color: green">Go</span>
//!
//! Wrapping incurs a performance cost due to an extra allocation and
//! replacement if the wrapped item has styling applied to it. Otherwise, it
//! does not allocate nor incur a meaningful performance cost.
//!
//! ## Lingering
//!
//! Styling can _linger_ beyond a single value via [`Quirk::Linger`] or the
//! equivalent [`linger()`](Painted::linger()) constructor. A lingering style
//! does not reset itself after being applied. In other words, the style lingers
//! on beyond the value it's applied to, until something else resets the
//! respective styling.
//!
//! The complement to lingering is force resetting via [`Quirk::Resetting`] or
//! the equivalent [`resetting()`](Painted::resetting()) constructor. Force
//! resetting, as the name implies, forces a reset suffix to be emitted after
//! the value, irrespective of any lingering applied. It can be used as a way to
//! finalize a lingering style.
//!
//! Lingering itself is useful in situations where a given style is to be
//! repeated across multiple values, or when style is intended to persist even
//! across values that are not styled with `yansi`. It also allows avoiding
//! unnecessarily repeated ANSI code sequences. The examples below illustrate
//! some scenarios in which lingering is useful:
//!
//! ```rust
//! use yansi::Paint;
//!
//! println!("Hello! {} {} things with {} {}?",
//! "How".magenta().underline().linger(),
//! "are".italic().linger(),
//! "you".on_yellow(), // doesn't linger, so all styling is reset here
//! "today".blue());
//! ```
//!
//! `>` Hello!
//! <span style="color: magenta;">
//! <u>How <i>are things with <span style="background: yellow;">you</span></i></u>
//! </span>
//! <span style="color: blue;">today</span>?
//!
//! ```rust
//! use yansi::Paint;
//!
//! println!("Hello! {} {} things with {} {}?",
//! "How".magenta().underline().linger(),
//! "are".italic(), // doesn't linger, so all styling is reset here
//! "you".on_yellow().linger(),
//! "today".blue()); // doesn't linger; styling is reset
//! ```
//!
//! `>` Hello!
//! <span style="color: magenta;">
//! <u>How <i>are</i></u>
//! </span>
//! things with
//! <span style="background: yellow;">
//! you
//! <span style="color: blue;">today</span></span>?
//!
//! ```rust
//! use yansi::Paint;
//!
//! println!("{} B {} {} {} F",
//! "A".red().linger(),
//! "C".underline().linger(),
//! "D", // doesn't linger, but no styling applied, thus no reset
//! "E".resetting()); // explicitly reset
//! ```
//!
//! `>` <span style="color: red;"> A B <u>C D E</u> </span> F
//!
//! ## Brightening
//!
//! Most pimrary colors are available in regular and _bright_ variants, e.g.,
//! [`Color::Red`] and [`Color::BrightRed`]. The [`Quirk::Bright`] and
//! [`Quirk::OnBright`] quirks, typically applied via
//! [`.bright()`](Painted::bright()) and [`.on_bright()`](Painted::on_bright()),
//! provide an alternative, convenient mechanism to select the bright variant of
//! the selected foreground or background color, respectively. The quirk
//! provides no additional colors and is equivalent to selecting the bright
//! variants directly.
//!
//! ```rust
//! use yansi::Paint;
//!
//! // These are all equivalent.
//! print!("{}", "Regular".red());
//! print!("{}", "Bright".bright_red());
//! print!("{}", "Bright".bright().red());
//! print!("{}", "Bright".red().bright());
//!
//! # static STYLE: yansi::Style = yansi::Color::Green.bold();
//! // The `bright` quirk lets use choose the bright variants of _any_ color,
//! // even when the color or style is unknown at the call site.
//! print!("{}", "Normal".paint(STYLE));
//! print!("{}", "Bright".paint(STYLE).bright());
//! ```
//!
//! `>` <span style="color: red;">Regular</span>
//! <span style="color: hotpink;">Bright</span>
//! <span style="color: hotpink;">Bright</span>
//! <span style="color: hotpink;">Bright</span>
//! <span style="color: green;"><b>Normal</b></span>
//! <span style="color: greenyellow;"><b>Bright</b></span>
//!
//! The `bright()` quirk can be applied before or after a color is selected
//! while having the same effect.
//!
//! # Windows
//!
//! Styling is supported and enabled automatically on Windows beginning with
//! the Windows 10 Anniversary Update, or about [96% of all Windows machines
//! worldwide](https://gs.statcounter.com/os-version-market-share/windows/desktop/worldwide),
//! and likely closer to 100% of developer machines (e.g., 99% of visitors to
//! [rocket.rs](https://rocket.rs) on Windows are on Windows 10+).
//!
//! Yansi enables styling support on Windows by querying the Windows API on the
//! first attempt to color. If support is available, it is enabled. If support
//! is not available, styling is disabled and no styling sequences are emitted.
//!
//! # Crate Features
//!
//! | Feature | Default? | Also Enables | Notes |
//! |--------------|----------|--------------|----------------------------------|
//! | `std` | **Y** | `alloc` | Use `std` library. |
//! | `alloc` | **Y** | | Use `alloc`. Enables [wrapping]. |
//! | `detect-tty` | N | `std` | See [optional conditions]. |
//! | `detect-env` | N | `std` | See [optional conditions]. |
//! | `hyperlink` | N | `std` | Enables [hyperlinking] support. |
//!
//! With `default-features = false`, this crate is `#[no_std]`.
//!
//! Without any features enabled, all functionality except [wrapping] is
//! available. To recover wrapping _with_ `#[no_std]`, set `default-features =
//! false` and enable the `alloc` feature, which requires `alloc` support.
//!
//! [optional conditions]: Condition#built-in-conditions
//! [wrapping]: #wrapping
#![doc(html_logo_url = "https://raw.githubusercontent.com/SergioBenitez/yansi/master/.github/yansi-logo.png")]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "_nightly", feature(doc_cfg))]
#![deny(missing_docs)]
// FIXME: Remove once `clear()` and `Quirk::Clear` are removed.
#![allow(useless_deprecated, deprecated)]
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
#[macro_use]
mod macros;
mod windows;
mod attr_quirk;
mod style;
mod color;
mod paint;
mod global;
mod condition;
mod set;
#[cfg(feature = "hyperlink")]
#[cfg_attr(feature = "_nightly", doc(cfg(feature = "hyperlink")))]
pub mod hyperlink;
pub use paint::{Painted, Paint};
pub use attr_quirk::{Attribute, Quirk};
pub use style::Style;
pub use color::Color;
pub use condition::Condition;
pub use global::{enable, whenever, disable, is_enabled};