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}