1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! 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`](ctl_text::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.
pub use ;
pub use ;
pub use ctl_text;
pub use ;
pub use ;
pub use ;
pub use ;
/// The README's examples, compiled and run as doctests.
;