Skip to main content

ctl_term/
color.rs

1//! Colour policy and colour depth.
2
3use anstyle::Color;
4
5use crate::palette::{ansi256_to_ansi16, rgb_to_ansi16, rgb_to_ansi256};
6
7/// Whether to write colour, as the caller asked.
8///
9/// [`Always`](Self::Always) and [`Never`](Self::Never) ignore the variables
10/// that decide whether to write colour, `NO_COLOR`, `CLICOLOR`,
11/// `CLICOLOR_FORCE`, `FORCE_COLOR`, and `TERM=dumb`, and ask no stream. The
12/// depth and the width still follow their variables. [`Auto`](Self::Auto)
13/// follows the order in the Colour section of the [crate docs](crate).
14///
15/// ctl-core's own `ColorMode`, which its `--color` flag parses to, converts
16/// into this type with `From`.
17#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
18#[non_exhaustive]
19pub enum ColorMode {
20    /// Decide from the environment and the stream.
21    #[default]
22    Auto,
23    /// Write colour whatever the environment holds.
24    Always,
25    /// Write no colour whatever the environment holds.
26    Never,
27}
28
29/// How many colours the terminal can show.
30///
31/// The variants are ordered from fewest colours to most, so
32/// `ColorDepth::Ansi16 < ColorDepth::TrueColor`.
33#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
34#[non_exhaustive]
35pub enum ColorDepth {
36    /// The 16 named colours.
37    Ansi16,
38    /// The 256-colour palette.
39    Ansi256,
40    /// 24-bit colour.
41    TrueColor,
42}
43
44impl ColorDepth {
45    /// `color` converted to the nearest colour this depth can show.
46    ///
47    /// A colour that already fits comes back unchanged. At [`Ansi256`]
48    /// a 24-bit colour becomes the nearest palette colour. At [`Ansi16`] a
49    /// 24-bit or palette colour becomes the nearest named colour, measured
50    /// directly, so no colour is rounded twice.
51    ///
52    /// [`Ansi256`]: Self::Ansi256
53    /// [`Ansi16`]: Self::Ansi16
54    #[must_use]
55    pub fn downgrade(self, color: Color) -> Color {
56        match color {
57            Color::Ansi(_) => color,
58            Color::Ansi256(palette) => match self {
59                Self::Ansi16 => Color::Ansi(ansi256_to_ansi16(palette)),
60                Self::Ansi256 | Self::TrueColor => color,
61            },
62            Color::Rgb(rgb) => match self {
63                Self::Ansi16 => Color::Ansi(rgb_to_ansi16(rgb)),
64                Self::Ansi256 => Color::Ansi256(rgb_to_ansi256(rgb)),
65                Self::TrueColor => color,
66            },
67        }
68    }
69}