package spectrum_capabilities

  1. Overview
  2. Docs

Spectrum Capabilities - Terminal Color Detection

Overview

Spectrum Capabilities detects the color support level of a terminal by examining environment variables, the TERM setting, CI providers, and OS version information. The heuristics are adapted from the JavaScript supports-color library (used by Chalk).

This library has no dependency on the rest of the Spectrum family and can be used standalone.

Color Levels

Detection returns one of four levels:

type color_level =
  | Unsupported  (* No color support *)
  | Basic        (* 16 colors: ANSI codes 30-37, 90-97 *)
  | Eight_bit    (* 256 colors: xterm palette *)
  | True_color   (* 24-bit RGB *)

Basic Usage

The typical entry point queries both stdout and stderr at once:

let info = Spectrum_capabilities.Capabilities.supported_color_levels () in
match info.stdout with
| True_color -> print_endline "24-bit color supported"
| Eight_bit -> print_endline "256 colors supported"
| Basic -> print_endline "16 colors supported"
| Unsupported -> print_endline "No color support"

For a specific file descriptor, pass the result of Unix.isatty directly:

let level =
  Spectrum_capabilities.Capabilities.supported_color_level
    (Unix.isatty Unix.stdout)

Detection Heuristics

The detection logic checks the following, in priority order:

  1. Not a TTY and no FORCE_COLOR: returns Unsupported
  2. TERM=dumb: returns Unsupported (unless FORCE_COLOR sets a floor)
  3. Windows: checks OS build number (>= 14931 for True_color, >= 10586 for Eight_bit, otherwise Basic)
  4. CI environment: recognizes Travis, CircleCI, AppVeyor, GitLab CI, GitHub Actions, Buildkite, Drone, and Codeship
  5. TeamCity: version >= 9.1 returns Basic
  6. Azure DevOps (TF_BUILD + AGENT_NAME): returns Basic
  7. COLORTERM=truecolor: returns True_color
  8. TERM_PROGRAM: iTerm.app >= 3.0 returns True_color, Apple_Terminal returns Eight_bit
  9. TERM suffix -256color or -256: returns Eight_bit
  10. TERM prefix matching known terminals (xterm, screen, vt100, rxvt, ansi, linux, etc.): returns Basic
  11. Any COLORTERM value: returns Basic
  12. Fallback: Unsupported

Overriding Detection

The FORCE_COLOR environment variable acts as a floor for detection:

FORCE_COLOR=0       Unsupported
FORCE_COLOR=1       Basic (16 colors)
FORCE_COLOR=2       Eight_bit (256 colors)
FORCE_COLOR=3       True_color (24-bit)
FORCE_COLOR=true    Basic
FORCE_COLOR=false   Unsupported

Custom Providers for Testing

The Spectrum_capabilities.Capabilities.Make functor accepts custom environment and OS information providers, allowing deterministic testing without real terminal state:

open Spectrum_capabilities.Capabilities

let env_map = StrMap.(
    empty
    |> add "COLORTERM" "truecolor"
  ) in
let env = env_provider_of_map env_map in
let os = os_info_provider false None in

let module Caps = Make((val env))((val os)) in
let level = Caps.supported_color_level true in
assert (equal_color_level level True_color)

API Reference

See Also