Skip to main content

Crate ctl_term

Crate ctl_term 

Source
Expand description

Terminal output for CLIs. It decides whether to write colour and at what depth, how wide the output is, and where an escape sequence is written.

The crate works on the plain lines ctl_text produces, which it re-exports. A Terminal states what is known about one output stream. An Encoder turns lines into bytes, adding the styling after layout. A Console puts the two together: it renders any Renderable at the width of its stream and writes it.

§Quick start

Decide once for a stream, then print. from_probe takes the stream’s facts and an environment lookup, so this example needs no terminal; a program calls Console::from_process instead and passes ColorMode::Auto.

use std::collections::HashMap;

use ctl_term::ctl_text::anstyle::AnsiColor;
use ctl_term::ctl_text::{Style, Text};
use ctl_term::{ColorMode, Console, DetectOptions, Probe, Stream, Terminal};

let variables = HashMap::from([("FORCE_COLOR", "3")]);
let env = |name: &str| variables.get(name).map(|value| (*value).to_owned());
let terminal = Terminal::from_probe(
    Probe::Redirected,
    ColorMode::Auto,
    DetectOptions::new(),
    &env,
);
let console = Console::new(Stream::Stdout, terminal);

let red = Style::new().fg_color(Some(AnsiColor::Red.into()));
let text = Text::styled("failed", red);
assert_eq!(console.render(&text), "\u{1b}[31mfailed\u{1b}[0m\n");

§Colour

ColorMode::Always writes colour and ColorMode::Never writes none, whatever NO_COLOR, CLICOLOR, CLICOLOR_FORCE, FORCE_COLOR, and TERM=dumb hold. They still read the variables that set the depth and the width, COLORTERM, TERM, FORCE_COLOR, and COLUMNS. Under ColorMode::Auto these rules apply in order, and the first that matches wins:

  1. NO_COLOR set and non-empty: no colour.
  2. CLICOLOR_FORCE set, non-empty, and not 0: colour.
  3. FORCE_COLOR set, non-empty, and not 0 or false: colour.
  4. CLICOLOR=0: no colour.
  5. TERM=dumb: no colour.
  6. Otherwise colour only when the stream is a terminal.

FORCE_COLOR=0 and FORCE_COLOR=false are neutral: they neither force colour nor turn it off, so rules 4 to 6 still apply. When the crate reads the process environment, a value that is not valid UTF-8 counts as set, so such a NO_COLOR still turns colour off.

When colour is on, the depth is 24-bit when COLORTERM is truecolor or 24bit or FORCE_COLOR=3. It is 256 colours when TERM contains 256color or FORCE_COLOR=2, and 16 colours otherwise. Terminal::at_depth overrides it.

The Encoder converts every colour to the nearest colour at that depth. A 24-bit colour on a 16-colour terminal prints as the nearest named colour, and an underline colour is dropped at 16 colours.

§Width

Widths count terminal cells: a column is one terminal cell. A width takes the first of these that applies:

  1. An explicit width, which is exact.
  2. The window of the stream being written.
  3. COLUMNS, when it holds a number from 1 to 65535.
  4. The fallback of DEFAULT_FALLBACK_WIDTH, 80.

A detected width loses a column buffer of DEFAULT_COLUMN_BUFFER, 2 cells, and never drops below DEFAULT_MINIMUM_WIDTH, 20, unless the window itself is narrower. A width is at least 1.

The buffer reads no variable until DetectOptions::column_buffer_envs names some. DetectOptions overrides each of these and can turn each off.

§A closed pipe

When the reader closes the stream, as head does, a write fails with Error::BrokenPipe, which is a variant of its own. This crate reports it and leaves the exit code to the caller. A caller that returns std::io::Result converts Error with From, and a closed pipe stays std::io::ErrorKind::BrokenPipe.

§Platforms

The crate supports and tests Unix only. Windows is not supported: the crate does not turn on virtual-terminal mode. On other targets the crate builds but reports no window width.

§Cargo features

detect, on by default, asks the operating system about a stream. It adds Probe::of, Terminal::detect, the from_process constructors, and Console::print, and brings in terminal_size. Without it the crate holds the Encoder, the colour conversion, and Terminal::from_probe, which need no terminal.

Re-exports§

pub use ctl_text;

Structs§

Console
Writes widgets to one output stream, in the colour and at the width decided for that stream.
DetectOptions
How the width of a stream is decided, and every default it applies.
Encoder
Turns lines of styled spans into the bytes a terminal reads.
Terminal
What is known about one output stream: whether it is a terminal, whether to write colour, at what depth, and how wide the output is.

Enums§

ColorDepth
How many colours the terminal can show.
ColorMode
Whether to write colour, as the caller asked.
Error
Why writing failed.
Probe
What the operating system says about one stream: redirected away from a terminal, or a terminal of some width.
Stream
A standard output stream.

Constants§

DEFAULT_COLUMN_BUFFER
The cells reserved from a detected width, so a line never touches the edge of the window.
DEFAULT_FALLBACK_WIDTH
The width used when the stream gives none and COLUMNS is unset, empty, zero, or not a number from 1 to 65535.
DEFAULT_MINIMUM_WIDTH
The width a detected width never shrinks below, unless the window itself is narrower.
RESET
The SGR sequence that clears every attribute.

Functions§

ansi256_to_ansi16
The nearest of the 16 named colours to a colour of the 256-colour palette.
rgb_to_ansi16
The nearest of the 16 named colours to color.
rgb_to_ansi256
The nearest colour to color in the 256-colour palette.