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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// SPDX-License-Identifier: GPL-3.0-only
//! The impure terminal-capability shell (SL-053 PHASE-02 colour; SL-054 PHASE-03 width).
//!
//! Two terminal capabilities are read HERE, in the thin shell, and injected as plain
//! values into the pure render layer ([`crate::listing`]) — which itself never touches
//! env, tty, clock, rng, git, or disk (the pure/imperative split, slices-spec
//! § Architecture, the date/uid injection pattern):
//!
//! - **colour** — reads `NO_COLOR` + isatty, injected as a `bool`. The bool is the
//! single authority: `owo_colors`' UNCONDITIONAL colorize methods are gated on it in
//! the leaf, never `if_supports_color` (which would re-read env+tty at apply-time and
//! smuggle impurity back into the pure layer).
//! - **width** — reads isatty + the `crossterm::terminal::size()` ioctl, injected as an
//! `Option<u16>`. `None` (a pipe / unreadable / degenerate size) ⇒ no wrapping, so
//! piped output stays width-free and the SL-053 deterministic goldens stay frozen.
//!
//! Each capability follows the same shape: a thin `stdout_*` wrapper holding the
//! impurities and a pure both-injected decision fn, testable without a real tty.
use OsStr;
/// Whether colour should be emitted on stdout.
///
/// Thin shell: the env read (`NO_COLOR`) and the tty probe are the only impurities;
/// the decision itself is the pure, env-injected [`color_enabled`] so it is testable
/// without mutating the process environment (`set_var` is forbidden crate-wide —
/// CLAUDE.md pure/imperative split, mirroring `git::trunk_tree_ish`). `var_os` — the
/// repo bans `std::env::var` (`disallowed_methods`).
pub
/// The pure colour-capability decision with both impurities injected.
///
/// `NO_COLOR` precedence: its mere *presence* (even empty, `Some("")`) disables
/// colour, per the `NO_COLOR` convention (<https://no-color.org>). Absent ⇒ colour
/// follows `is_tty`, so
/// piped/redirected output stays plain (the goldens run piped ⇒ colour-free, VT-4).
/// Terminal width for stdout, in columns — `None` ⇒ no wrapping.
///
/// Thin shell (mirrors [`stdout_color_enabled`]): the isatty probe and the
/// `crossterm::terminal::size()` ioctl are the only impurities; the decision is the
/// pure, both-injected [`terminal_width`], testable without a real tty. Wrapping
/// applies only on a tty — piped/redirected output gets `None` and stays width-free,
/// keeping the SL-053 deterministic goldens frozen. The live isatty branch is
/// documented-not-driven (mirrors [`stdout_color_enabled`]): under `cargo test`
/// stdout is not a terminal, so it returns `None`; a pty is out of scope.
pub
/// The pure width decision with both impurities injected (`is_tty`, `cols`).
///
/// `None` ⇒ no wrapping (the deterministic SL-053 path): a pipe (`!is_tty`), an
/// unreadable size (`cols == None`), or a degenerate width below [`MIN_WRAP_WIDTH`].
/// Otherwise the live column count flows to the pure render layer, which runs the
/// real grid-dependent fit test ([`crate::listing::render_table`]'s `grid_min_width`,
/// PHASE-02).
/// Coarse shell-side pre-filter for degenerate sizes (`size() == 0`, headless /
/// unreadably-narrow terminals): below it, skip wrapping and emit clean overflow.
/// NOT the authoritative fit test — that is grid-dependent (`render_table`'s
/// `grid_min_width`, PHASE-02), which the pure layer applies to the real column
/// count and which already falls back to `Disabled` for any width it can't seat. So
/// this floor protects nothing the grid floor wouldn't; it is a cheap shell-side
/// cutoff (the shell has no grid) that also, as a side effect, suppresses the rare
/// legitimate few-column wrap on a sub-`16` terminal in favour of clean overflow.
const MIN_WRAP_WIDTH: u16 = 16;