Open-Source Wikis

/

GitHub CLI

/

Systems

/

IOStreams

cli/cli

IOStreams

Active contributors: Mislav, Andy Feller, vilmibm

Purpose

pkg/iostreams abstracts everything terminal-related: stdin/stdout/stderr handles, ANSI color, the pager subprocess, spinners, progress indicators, terminal width detection, accessibility-aware rendering, and TTY status. It exists so that command code never has to call os.Stdout directly and so tests can swap in bytes.Buffers with the same shape.

Directory layout

pkg/iostreams/
  iostreams.go             # IOStreams struct and constructors
  color.go                 # Color helpers (ColorEnabled, NewColorScheme, ...)
  console.go               # POSIX TTY check
  console_windows.go       # Windows-specific TTY + ANSI support
  epipe_other.go / epipe_windows.go  # SIGPIPE handling per platform

Key abstractions

Symbol File Role
IOStreams iostreams.go The struct passed everywhere via Factory.IOStreams.
System iostreams.go Returns an IOStreams wired to real stdin/stdout/stderr.
Test iostreams.go Returns an IOStreams plus three *bytes.Buffer pointers for assertions.
IsStdoutTTY / IsStdinTTY / IsStderrTTY iostreams.go TTY queries. Tests set them via SetStdoutTTY etc.
ColorEnabled color.go Honours NO_COLOR, CLICOLOR, accessibility settings, and TTY status.
ColorScheme color.go Project-specific palette (ColorScheme.Yellow, Bold, Red, ...).
StartProgressIndicator / StopProgressIndicator iostreams.go Wraps briandowns/spinner.
StartPager / StopPager iostreams.go Pipes output to the configured pager.
TerminalWidth iostreams.go Width detection (golang.org/x/term).

How it works

IOStreams is created in internal/ghcmd/cmd.go (newIOStreams), which reads the user's pager, prompt_disabled, and accessible settings out of the config to populate the streams. From there it travels to every command via the factory.

ColorEnabled rules of precedence:

  1. NO_COLOR=1 -> false.
  2. CLICOLOR_FORCE=1 -> true.
  3. CLICOLOR=0 -> false.
  4. Accessibility setting from config -> false if "screen-reader".
  5. Falls back to IsStdoutTTY().

Pager handling:

graph TD
    A[command writes to opts.IO.Out] --> B{Pager configured?}
    B -->|yes & TTY| C[StartPager replaces Out with a pipe]
    C --> D[child process: less -FRX]
    A -->|after run| E[StopPager waits for child]
    B -->|no or non-TTY| F[Out stays as os.Stdout]

Integration points

  • Created by internal/ghcmd/newIOStreams and held on the factory.
  • Consumed by virtually every command and shared subsystem (table printer, markdown renderer, progress indicators).
  • Tests use iostreams.Test() and assert on the returned buffers; assertions on rendered output are common in pkg/cmd/*/list_test.go files.

Entry points for modification

  • New color or icon: add to ColorScheme in color.go. Avoid scattering ANSI escapes through commands.
  • New rendering mode (e.g. minimal-noise mode for AI agents): extend the construction in newIOStreams and gate behind a config key.
  • Pager change: edit StartPager. Be careful with Windows behaviour; the platform-specific files exist for a reason.

Key source files

File Purpose
pkg/iostreams/iostreams.go Streams, pager, spinner.
pkg/iostreams/color.go Color enable/disable rules.
pkg/iostreams/console.go / console_windows.go TTY detection.
internal/ghcmd/cmd.go (newIOStreams) Construction with config-derived options.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

IOStreams – GitHub CLI wiki | Factory