Skip to main content

owo_colors/
lib.rs

1//! |**Quick Links**|[`OwoColorize`]|[`Style`]|[`StyledList`]|[`github`](https://github.com/owo-colors/owo-colors)|
2//! |-|-|-|-|-|
3//!
4//! ---
5//!
6//! This crate provides [`OwoColorize`], an extension trait for colorizing a
7//! given type.
8//!
9//! ## Example
10//!
11//! ```rust
12//! use owo_colors::OwoColorize;
13//!
14//! // Foreground colors
15//! println!("My number is {:#x}!", 10.green());
16//! // Background colors
17//! println!("My number is not {}!", 4.on_red());
18//! ```
19//!
20//! ## Generically color
21//!
22//! ```rust
23//! use owo_colors::OwoColorize;
24//! use owo_colors::colors::*;
25//!
26//! // Generically color
27//! println!("My number might be {}!", 4.fg::<Black>().bg::<Yellow>());
28//! ```
29//!
30//! ## Stylize
31//!
32//! ```rust
33//! use owo_colors::OwoColorize;
34//!
35//! println!("{}", "strikethrough".strikethrough());
36//! ```
37//!
38//! ## Only Style on Supported Terminals
39//!
40//! ```rust
41//! # #[cfg(feature = "supports-color")] {
42//! use owo_colors::{OwoColorize, Stream::Stdout};
43//!
44//! println!(
45//!     "{}",
46//!     "colored blue if a supported terminal"
47//!         .if_supports_color(Stdout, |text| text.bright_blue())
48//! );
49//! # }
50//! ```
51//!
52//! Supports `NO_COLOR`/`FORCE_COLOR` environment variables, checks if it's a tty, checks
53//! if it's running in CI (and thus likely supports color), and checks which terminal is being
54//! used. (Note: requires `supports-colors` feature)
55//!
56//! ## Style Objects
57//!
58//! owo-colors also features the ability to create a [`Style`] object and use it to
59//! apply the same set of colors/effects to any number of things to display.
60//!
61//! ```rust
62//! use owo_colors::{OwoColorize, Style};
63//!
64//! let my_style = Style::new()
65//!     .red()
66//!     .on_white()
67//!     .strikethrough();
68//!
69//! let text = "red text, white background, struck through";
70//! println!("{}", text.style(my_style));
71//! ```
72#![cfg_attr(not(test), no_std)]
73#![cfg_attr(doc_cfg, feature(doc_cfg))]
74#![doc(html_logo_url = "https://jam1.re/img/rust_owo.svg")]
75#![warn(missing_docs)]
76#![forbid(unsafe_code)]
77
78pub mod colors;
79mod combo;
80mod dyn_colors;
81mod dyn_styles;
82mod styled_list;
83pub mod styles;
84
85#[cfg(feature = "supports-colors")]
86mod overrides;
87
88#[cfg(feature = "supports-colors")]
89pub(crate) use overrides::OVERRIDE;
90
91use core::fmt;
92use core::marker::PhantomData;
93
94mod private {
95    // Not actually reachable.
96    #[doc(hidden)]
97    pub trait Sealed {}
98}
99
100/// A trait for describing a type which can be used with [`FgColorDisplay`] or
101/// [`BgColorDisplay`]
102pub trait Color: private::Sealed {
103    /// The ANSI format code for setting this color as the foreground
104    const ANSI_FG: &'static str;
105
106    /// The ANSI format code for setting this color as the background
107    const ANSI_BG: &'static str;
108
109    /// The raw ANSI format for settings this color as the foreground without the ANSI
110    /// delimiters ("\x1b" and "m")
111    const RAW_ANSI_FG: &'static str;
112
113    /// The raw ANSI format for settings this color as the background without the ANSI
114    /// delimiters ("\x1b" and "m")
115    const RAW_ANSI_BG: &'static str;
116
117    #[doc(hidden)]
118    type DynEquivalent: DynColor;
119
120    #[doc(hidden)]
121    const DYN_EQUIVALENT: Self::DynEquivalent;
122
123    #[doc(hidden)]
124    const DYN_COLORS_EQUIVALENT: crate::DynColors;
125}
126
127/// A trait describing a runtime-configurable color which can displayed using [`FgDynColorDisplay`]
128/// or [`BgDynColorDisplay`]. If your color will be known at compile time it
129/// is recommended you avoid this.
130pub trait DynColor: private::Sealed {
131    /// A function to output a ANSI code to a formatter to set the foreground to this color
132    fn fmt_ansi_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
133    /// A function to output a ANSI code to a formatter to set the background to this color
134    fn fmt_ansi_bg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
135
136    /// A function to output a raw ANSI code to a formatter to set the foreground to this color,
137    /// but without including the ANSI delimiters.
138    fn fmt_raw_ansi_fg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
139
140    /// A function to output a raw ANSI code to a formatter to set the background to this color,
141    /// but without including the ANSI delimiters.
142    fn fmt_raw_ansi_bg(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
143
144    #[doc(hidden)]
145    fn get_dyncolors_fg(&self) -> DynColors;
146    #[doc(hidden)]
147    fn get_dyncolors_bg(&self) -> DynColors;
148}
149
150/// Transparent wrapper around a type which implements all the formatters the wrapped type does,
151/// with the addition of changing the foreground color. Recommended to be constructed using
152/// [`OwoColorize`].
153#[repr(transparent)]
154pub struct FgColorDisplay<'a, C: Color, T: ?Sized>(&'a T, PhantomData<C>);
155
156/// Transparent wrapper around a type which implements all the formatters the wrapped type does,
157/// with the addition of changing the background color. Recommended to be constructed using
158/// [`OwoColorize`].
159#[repr(transparent)]
160pub struct BgColorDisplay<'a, C: Color, T: ?Sized>(&'a T, PhantomData<C>);
161
162/// Wrapper around a type which implements all the formatters the wrapped type does,
163/// with the addition of changing the foreground color. Is not recommended unless compile-time
164/// coloring is not an option.
165pub struct FgDynColorDisplay<'a, Color: DynColor, T: ?Sized>(&'a T, Color);
166
167/// Wrapper around a type which implements all the formatters the wrapped type does,
168/// with the addition of changing the background color. Is not recommended unless compile-time
169/// coloring is not an option.
170pub struct BgDynColorDisplay<'a, Color: DynColor, T: ?Sized>(&'a T, Color);
171
172macro_rules! style_methods {
173    ($(#[$meta:meta] $name:ident $ty:ident),* $(,)?) => {
174        $(
175            #[$meta]
176            #[must_use]
177            #[inline(always)]
178            #[rust_analyzer::completions(ignore_flyimport)]
179            fn $name(&self) -> styles::$ty<'_, Self> {
180                styles::$ty(self)
181            }
182         )*
183    };
184}
185
186const _: () = (); // workaround for syntax highlighting bug
187
188macro_rules! color_methods {
189    ($(
190        #[$fg_meta:meta] #[$bg_meta:meta] $color:ident $fg_method:ident $bg_method:ident
191    ),* $(,)?) => {
192        $(
193            #[$fg_meta]
194            #[must_use]
195            #[inline(always)]
196            #[rust_analyzer::completions(ignore_flyimport)]
197            fn $fg_method(&self) -> FgColorDisplay<'_, colors::$color, Self> {
198                FgColorDisplay(self, PhantomData)
199            }
200
201            #[$bg_meta]
202            #[must_use]
203            #[inline(always)]
204            #[rust_analyzer::completions(ignore_flyimport)]
205            fn $bg_method(&self) -> BgColorDisplay<'_, colors::$color, Self> {
206                BgColorDisplay(self, PhantomData)
207            }
208         )*
209    };
210}
211
212const _: () = (); // workaround for syntax highlighting bug
213
214/// Extension trait for colorizing a type which implements any std formatter
215/// ([`Display`](core::fmt::Display), [`Debug`](core::fmt::Debug), [`UpperHex`](core::fmt::UpperHex),
216/// etc.)
217///
218/// ## Example
219///
220/// ```rust
221/// use owo_colors::OwoColorize;
222///
223/// println!("My number is {:#x}!", 10.green());
224/// println!("My number is not {}!", 4.on_red());
225/// ```
226///
227/// ## How to decide which method to use
228///
229/// **Do you have a specific color you want to use?**
230///
231/// Use the specific color's method, such as [`blue`](OwoColorize::blue) or
232/// [`on_green`](OwoColorize::on_green).
233///
234///
235/// **Do you want your colors configurable via generics?**
236///
237/// Use [`fg`](OwoColorize::fg) and [`bg`](OwoColorize::bg) to make it compile-time configurable.
238///
239///
240/// **Do you need to pick a color at runtime?**
241///
242/// Use the [`color`](OwoColorize::color), [`on_color`](OwoColorize::on_color),
243/// [`truecolor`](OwoColorize::truecolor) or [`on_truecolor`](OwoColorize::on_truecolor).
244///
245/// **Do you need some other text modifier?**
246///
247/// * [`bold`](OwoColorize::bold)
248/// * [`dimmed`](OwoColorize::dimmed)
249/// * [`italic`](OwoColorize::italic)
250/// * [`underline`](OwoColorize::underline)
251/// * [`blink`](OwoColorize::blink)
252/// * [`blink_fast`](OwoColorize::blink_fast)
253/// * [`reversed`](OwoColorize::reversed)
254/// * [`hidden`](OwoColorize::hidden)
255/// * [`strikethrough`](OwoColorize::strikethrough)
256///
257/// **Do you want it to only display colors if it's a terminal?**
258///
259/// 1. Enable the `supports-colors` feature
260/// 2. Colorize inside [`if_supports_color`](OwoColorize::if_supports_color)
261///
262/// **Do you need to store a set of colors/effects to apply to multiple things?**
263///
264/// Use [`style`](OwoColorize::style) to apply a [`Style`].
265#[rust_analyzer::completions(ignore_flyimport_methods)]
266pub trait OwoColorize: Sized {
267    // Implementation note: even though the "OwoColorize: Sized" condition _can_ be dropped, we
268    // currently don't do that for API compatibility reasons.
269    //
270    // For example, currently, calling `OwoColorize::fg` on a &str results in a type signature of
271    // `FgColorDisplay<'_, C, &str>`. Dropping the "OwoColorize: Sized" condition would result in a
272    // type signature of `FgColorDisplay<'_, C, str>`, which is a visible change.
273    //
274    // If we ever do a breaking change to owo-colors in the future, this would be a good candidate.
275
276    /// Set the foreground color generically
277    ///
278    /// ```rust
279    /// use owo_colors::{OwoColorize, colors::*};
280    ///
281    /// println!("{}", "red foreground".fg::<Red>());
282    /// ```
283    #[must_use]
284    #[inline(always)]
285    #[rust_analyzer::completions(ignore_flyimport)]
286    fn fg<C: Color>(&self) -> FgColorDisplay<'_, C, Self> {
287        FgColorDisplay(self, PhantomData)
288    }
289
290    /// Set the background color generically.
291    ///
292    /// ```rust
293    /// use owo_colors::{OwoColorize, colors::*};
294    ///
295    /// println!("{}", "black background".bg::<Black>());
296    /// ```
297    #[must_use]
298    #[inline(always)]
299    #[rust_analyzer::completions(ignore_flyimport)]
300    fn bg<C: Color>(&self) -> BgColorDisplay<'_, C, Self> {
301        BgColorDisplay(self, PhantomData)
302    }
303
304    color_methods! {
305        /// Change the foreground color to black
306        /// Change the background color to black
307        Black    black    on_black,
308        /// Change the foreground color to red
309        /// Change the background color to red
310        Red      red      on_red,
311        /// Change the foreground color to green
312        /// Change the background color to green
313        Green    green    on_green,
314        /// Change the foreground color to yellow
315        /// Change the background color to yellow
316        Yellow   yellow   on_yellow,
317        /// Change the foreground color to blue
318        /// Change the background color to blue
319        Blue     blue     on_blue,
320        /// Change the foreground color to magenta
321        /// Change the background color to magenta
322        Magenta  magenta  on_magenta,
323        /// Change the foreground color to purple
324        /// Change the background color to purple
325        Magenta  purple   on_purple,
326        /// Change the foreground color to cyan
327        /// Change the background color to cyan
328        Cyan     cyan     on_cyan,
329        /// Change the foreground color to white
330        /// Change the background color to white
331        White    white    on_white,
332
333        /// Change the foreground color to the terminal default
334        /// Change the background color to the terminal default
335        Default default_color on_default_color,
336
337        /// Change the foreground color to bright black
338        /// Change the background color to bright black
339        BrightBlack    bright_black    on_bright_black,
340        /// Change the foreground color to bright red
341        /// Change the background color to bright red
342        BrightRed      bright_red      on_bright_red,
343        /// Change the foreground color to bright green
344        /// Change the background color to bright green
345        BrightGreen    bright_green    on_bright_green,
346        /// Change the foreground color to bright yellow
347        /// Change the background color to bright yellow
348        BrightYellow   bright_yellow   on_bright_yellow,
349        /// Change the foreground color to bright blue
350        /// Change the background color to bright blue
351        BrightBlue     bright_blue     on_bright_blue,
352        /// Change the foreground color to bright magenta
353        /// Change the background color to bright magenta
354        BrightMagenta  bright_magenta  on_bright_magenta,
355        /// Change the foreground color to bright purple
356        /// Change the background color to bright purple
357        BrightMagenta  bright_purple   on_bright_purple,
358        /// Change the foreground color to bright cyan
359        /// Change the background color to bright cyan
360        BrightCyan     bright_cyan     on_bright_cyan,
361        /// Change the foreground color to bright white
362        /// Change the background color to bright white
363        BrightWhite    bright_white    on_bright_white,
364    }
365
366    style_methods! {
367        /// Make the text bold
368        bold BoldDisplay,
369        /// Make the text dim
370        dimmed DimDisplay,
371        /// Make the text italicized
372        italic ItalicDisplay,
373        /// Make the text underlined
374        underline UnderlineDisplay,
375        /// Make the text blink
376        blink BlinkDisplay,
377        /// Make the text blink (but fast!)
378        blink_fast BlinkFastDisplay,
379        /// Swap the foreground and background colors
380        reversed ReversedDisplay,
381        /// Hide the text
382        hidden HiddenDisplay,
383        /// Cross out the text
384        strikethrough StrikeThroughDisplay,
385    }
386
387    /// Set the foreground color at runtime. Only use if you do not know which color will be used at
388    /// compile-time. If the color is constant, use either [`OwoColorize::fg`] or
389    /// a color-specific method, such as [`OwoColorize::green`],
390    ///
391    /// ```rust
392    /// use owo_colors::{OwoColorize, AnsiColors};
393    ///
394    /// println!("{}", "green".color(AnsiColors::Green));
395    /// ```
396    #[must_use]
397    #[inline(always)]
398    #[rust_analyzer::completions(ignore_flyimport)]
399    fn color<Color: DynColor>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self> {
400        FgDynColorDisplay(self, color)
401    }
402
403    /// Set the background color at runtime. Only use if you do not know what color to use at
404    /// compile-time. If the color is constant, use either [`OwoColorize::bg`] or
405    /// a color-specific method, such as [`OwoColorize::on_yellow`],
406    ///
407    /// ```rust
408    /// use owo_colors::{OwoColorize, AnsiColors};
409    ///
410    /// println!("{}", "yellow background".on_color(AnsiColors::BrightYellow));
411    /// ```
412    #[must_use]
413    #[inline(always)]
414    #[rust_analyzer::completions(ignore_flyimport)]
415    fn on_color<Color: DynColor>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self> {
416        BgDynColorDisplay(self, color)
417    }
418
419    /// Set the foreground color to a specific RGB value.
420    #[must_use]
421    #[rust_analyzer::completions(ignore_flyimport)]
422    fn fg_rgb<const R: u8, const G: u8, const B: u8>(
423        &self,
424    ) -> FgColorDisplay<'_, colors::CustomColor<R, G, B>, Self> {
425        FgColorDisplay(self, PhantomData)
426    }
427
428    /// Set the background color to a specific RGB value.
429    #[must_use]
430    #[rust_analyzer::completions(ignore_flyimport)]
431    fn bg_rgb<const R: u8, const G: u8, const B: u8>(
432        &self,
433    ) -> BgColorDisplay<'_, colors::CustomColor<R, G, B>, Self> {
434        BgColorDisplay(self, PhantomData)
435    }
436
437    /// Sets the foreground color to an RGB value.
438    #[must_use]
439    #[inline(always)]
440    #[rust_analyzer::completions(ignore_flyimport)]
441    fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self> {
442        FgDynColorDisplay(self, Rgb(r, g, b))
443    }
444
445    /// Sets the background color to an RGB value.
446    #[must_use]
447    #[inline(always)]
448    #[rust_analyzer::completions(ignore_flyimport)]
449    fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self> {
450        BgDynColorDisplay(self, Rgb(r, g, b))
451    }
452
453    /// Apply a runtime-determined style
454    #[must_use]
455    #[rust_analyzer::completions(ignore_flyimport)]
456    fn style(&self, style: Style) -> Styled<&Self> {
457        style.style(self)
458    }
459
460    /// Apply a given transformation function to all formatters if the given stream
461    /// supports at least basic ANSI colors, allowing you to conditionally apply
462    /// given styles/colors.
463    ///
464    /// Requires the `supports-colors` feature.
465    ///
466    /// ```rust
467    /// use owo_colors::{Stream, OwoColorize};
468    ///
469    /// println!(
470    ///     "{}",
471    ///     "woah! error! if this terminal supports colors, it's blue"
472    ///         .if_supports_color(Stream::Stdout, |text| text.bright_blue())
473    /// );
474    /// ```
475    ///
476    /// This function also accepts `supports_color` version 2's `Stream`, and also the deprecated
477    /// `supports_color` version 1's `Stream`.
478    ///
479    /// ```rust
480    /// use owo_colors::OwoColorize;
481    /// #[cfg(feature = "supports-colors")]
482    /// use supports_color::Stream;
483    ///
484    /// println!(
485    ///    "{}",
486    ///    "woah! error! if this terminal supports colors, it's blue"
487    ///       .if_supports_color(Stream::Stdout, |text| text.bright_blue())
488    /// );
489    #[must_use]
490    #[cfg(feature = "supports-colors")]
491    #[rust_analyzer::completions(ignore_flyimport)]
492    fn if_supports_color<'a, Out, ApplyFn>(
493        &'a self,
494        stream: impl Into<Stream>,
495        apply: ApplyFn,
496    ) -> SupportsColorsDisplay<'a, Self, Out, ApplyFn>
497    where
498        ApplyFn: Fn(&'a Self) -> Out,
499    {
500        SupportsColorsDisplay(self, apply, stream.into())
501    }
502}
503
504#[cfg(feature = "supports-colors")]
505mod supports_colors;
506
507#[cfg(feature = "supports-colors")]
508pub use {
509    overrides::{set_override, unset_override, with_override},
510    supports_colors::{Stream, SupportsColorsDisplay},
511};
512
513pub use colors::{
514    ansi_colors::AnsiColors, css::dynamic::CssColors, dynamic::Rgb, xterm::dynamic::XtermColors,
515};
516
517// TODO: figure out some wait to only implement for fmt::Display | fmt::Debug | ...
518impl<D> OwoColorize for D {}
519
520pub use {
521    combo::{ComboColorDisplay, ComboDynColorDisplay},
522    dyn_colors::*,
523    dyn_styles::*,
524};
525
526/// Module for drop-in [`colored`](https://docs.rs/colored) support to aid in porting code from
527/// [`colored`](https://docs.rs/colored) to owo-colors.
528///
529/// Just replace:
530///
531/// ```rust
532/// # mod colored {}
533/// use colored::*;
534/// ```
535///
536/// with
537///
538/// ```rust
539/// use owo_colors::colored::*;
540/// ```
541pub mod colored {
542    pub use crate::AnsiColors as Color;
543    pub use crate::OwoColorize;
544
545    /// A couple of functions to enable and disable coloring similarly to `colored`
546    #[cfg(feature = "supports-colors")]
547    pub mod control {
548        pub use crate::{set_override, unset_override};
549    }
550}
551
552pub use styled_list::StyledList;
553#[cfg(feature = "alloc")]
554pub use styled_list::StyledVec;
555
556#[cfg(test)]
557mod tests;