Color.ANSI (Color v0.4.0)

Copy Markdown

ANSI SGR (Select Graphic Rendition) colour parsing and encoding.

Supports the three common forms of ANSI colour used by modern terminals:

  • 16-colour palette\e[30m..\e[37m (foreground), \e[40m..\e[47m (background), plus the bright versions \e[90m..\e[97m and \e[100m..\e[107m.

  • 256-colour indexed palette\e[38;5;Nm (foreground), \e[48;5;Nm (background). Indices 0–15 are the base 16-colour palette; 16–231 are a 6×6×6 colour cube with levels [0, 95, 135, 175, 215, 255]; 232–255 are a 24-step grayscale ramp starting at 8 with a step of 10.

  • Truecolor (24-bit)\e[38;2;R;G;Bm (foreground), \e[48;2;R;G;Bm (background), where R, G and B are 0..255 bytes.

The :mode option on to_string/2 selects which form to emit. When the target is the 16- or 256-colour palette and the input colour isn't an exact palette entry, the encoder picks the perceptually nearest palette entry using CIEDE2000 in CIELAB.

Examples

iex> Color.ANSI.to_string("red") == "\e[38;2;255;0;0m"
true

iex> Color.ANSI.to_string("red", mode: :ansi256) == "\e[38;5;196m"
true

iex> Color.ANSI.to_string("red", mode: :ansi16, layer: :background) == "\e[101m"
true

iex> {:ok, c, :foreground} = Color.ANSI.parse("\e[38;2;255;0;0m")
iex> Color.to_hex(c)
"#ff0000"

iex> {:ok, c, :background} = Color.ANSI.parse("\e[41m")
iex> Color.to_hex(c)
"#aa0000"

iex> Color.ANSI.nearest_256("#ff0000")
196

iex> Color.ANSI.wrap("hello", "red") == "\e[38;2;255;0;0mhello\e[0m"
true

Summary

Types

Which ANSI layer a colour targets.

How to_string/2 should encode the colour.

Functions

Returns the 16-colour palette index of the entry perceptually nearest to color, using CIEDE2000 in CIELAB.

Returns the 256-colour palette index of the entry perceptually nearest to color, using CIEDE2000 in CIELAB.

Returns the 16-colour palette as a list of {index, {r, g, b}} tuples.

Returns the full 256-colour palette as a list of {index, {r, g, b}} tuples, with each channel in 0..255.

Parses an ANSI SGR escape sequence and returns the encoded colour.

Returns the ANSI reset escape sequence (ESC[0m).

Serialises a colour to an ANSI SGR escape sequence.

Wraps string in the ANSI escape that sets the given colour, followed by a reset.

Types

layer()

@type layer() :: :foreground | :background

Which ANSI layer a colour targets.

mode()

@type mode() :: :truecolor | :ansi256 | :ansi16

How to_string/2 should encode the colour.

Functions

nearest_16(color)

@spec nearest_16(Color.input()) :: 0..15

Returns the 16-colour palette index of the entry perceptually nearest to color, using CIEDE2000 in CIELAB.

Arguments

Returns

  • An integer in 0..15.

Examples

iex> Color.ANSI.nearest_16("#ff0000")
9

iex> Color.ANSI.nearest_16("#000000")
0

nearest_256(color)

@spec nearest_256(Color.input()) :: 0..255

Returns the 256-colour palette index of the entry perceptually nearest to color, using CIEDE2000 in CIELAB.

Arguments

Returns

  • An integer in 0..255.

Examples

iex> Color.ANSI.nearest_256("#ff0000")
196

iex> Color.ANSI.nearest_256("#000000")
0

palette_16()

@spec palette_16() :: [{0..15, {0..255, 0..255, 0..255}}]

Returns the 16-colour palette as a list of {index, {r, g, b}} tuples.

Examples

iex> length(Color.ANSI.palette_16())
16

palette_256()

@spec palette_256() :: [{0..255, {0..255, 0..255, 0..255}}]

Returns the full 256-colour palette as a list of {index, {r, g, b}} tuples, with each channel in 0..255.

Examples

iex> length(Color.ANSI.palette_256())
256

iex> Enum.find(Color.ANSI.palette_256(), &match?({196, _}, &1))
{196, {255, 0, 0}}

parse(sequence)

@spec parse(binary()) :: {:ok, Color.SRGB.t(), layer()} | {:error, Exception.t()}

Parses an ANSI SGR escape sequence and returns the encoded colour.

The function accepts any of the three canonical ANSI colour forms. Style parameters (bold, italic, reverse, …) that precede or follow the colour are ignored; only the colour is extracted. Sequences that contain no colour descriptor (for example \e[0m reset, \e[39m default-foreground, or \e[1m bold-only) return an error.

Arguments

  • sequence is a binary string starting with ESC [ and ending with m. The leading ESC character may be written using the Elixir "\e" escape or the raw byte 0x1b.

Returns

  • {:ok, %Color.SRGB{}, :foreground | :background} on success.

  • {:error, %Color.ANSI.ParseError{}} if the sequence cannot be interpreted.

reset()

@spec reset() :: String.t()

Returns the ANSI reset escape sequence (ESC[0m).

Examples

iex> Color.ANSI.reset() == "\e[0m"
true

to_string(color, options \\ [])

@spec to_string(
  Color.input(),
  keyword()
) :: String.t()

Serialises a colour to an ANSI SGR escape sequence.

Arguments

  • color is any input accepted by Color.new/1 — a colour struct, a bare list, a hex string, a CSS named colour, or an atom.

  • options is a keyword list.

Options

  • :mode — one of:

    • :truecolor (default) — emits \e[38;2;R;G;Bm (24-bit, modern terminals only).

    • :ansi256 — emits \e[38;5;Nm using the perceptually nearest 256-colour palette index.

    • :ansi16 — emits \e[30m..\e[37m or \e[90m..\e[97m using the perceptually nearest 16-colour palette index.

  • :layer:foreground (default) or :background.

Returns

  • A binary string containing the escape sequence.

Examples

iex> Color.ANSI.to_string("red") == "\e[38;2;255;0;0m"
true

iex> Color.ANSI.to_string(%Color.SRGB{r: 0.0, g: 1.0, b: 0.0}) == "\e[38;2;0;255;0m"
true

iex> Color.ANSI.to_string("red", layer: :background) == "\e[48;2;255;0;0m"
true

wrap(string, color, options \\ [])

@spec wrap(String.t(), Color.input(), keyword()) :: String.t()

Wraps string in the ANSI escape that sets the given colour, followed by a reset.

Arguments

Returns

  • A binary string with the wrapped text.

Examples

iex> Color.ANSI.wrap("hi", "red") == "\e[38;2;255;0;0mhi\e[0m"
true

iex> Color.ANSI.wrap("hi", "red", mode: :ansi256) == "\e[38;5;196mhi\e[0m"
true