std.term
What touches the terminal itself: whether stdout is one, how big it is, whether colour should be written, and key input.
import std.term
print(term.is_tty()) # is stdout a terminal?
print(term.color_enabled()) # should escape codes be written?
print(term.size()) # { rows, cols }
Styling - colours, bold and the other attributes, rgb, style, link, cursor movement and clearing, strip and width - is string building, and lives in the tui package under the same names. It was in this module until 0.61; calling one of those here is now an error that names the tui function to use.
color_enabled
term.color_enabled() says whether escape codes should be written, by the usual conventions in order: CLICOLOR_FORCE set forces colour on (for piping deliberately into something that renders it, like less -R), NO_COLOR set forces it off, and otherwise colour is on exactly when stdout is a terminal. So ecko report.ecko > out.txt comes out clean without a flag.
Anything that styles its own output should ask this first - the tui package does - and write plain text when it says no:
import std.term
fn green(s) = if term.color_enabled() { "\u{1b}[32m{s}\u{1b}[0m" } else { s }
print(green("ok"))
Size
term.size() reports the terminal as { rows, cols }. It has a sensible 80x24 fallback when there is no terminal, so code that uses it still works under a pipe.
Key input
term.read_key() reads a single keypress without waiting for Enter, blocking until one arrives, and returns null if a passed timeout expires (or stdin hits EOF) with no key read: term.read_key(timeout: 500) waits at most 500 milliseconds. A key is a string - the character itself, or a name such as "enter", "up" or "ctrl-c". That is what makes a menu or a prompt possible. term.poll() checks whether a key is waiting without blocking, returning a boolean, and term.raw_mode(true) / term.raw_mode(false) toggle raw input mode (no line buffering, no local echo). Both return a boolean too: false when stdin is not a terminal (a harmless no-op, so a piped run stays pipeline-friendly), true otherwise. Always pair raw_mode(true) with raw_mode(false) - it is also restored automatically on exit even if the program errors, and when a signal kills it. Ctrl-C, an orchestrator's SIGTERM, or the terminal window closing all put the settings back before the process dies, so a TUI cannot strand your shell with no echo.
Unix only, for now. read_key, poll and raw_mode are implemented on top of termios, which does not exist on Windows. On any non-Unix platform - including the shipped Windows x86-64 build - all three raise an error saying keyboard input needs a Unix terminal, rather than silently doing nothing. A key-input UI built on this module does not yet run cross-platform; the rest of the module is portable (size, is_tty and color_enabled all work on Windows too).
Building a UI
For styling, padding that ignores escape codes, bordered boxes and aligned tables, use the tui package (0.39 or later for the styling). It asks this module's color_enabled whether to write escape codes. It measures width in characters, so wide characters still throw alignment off.