Skip to content
claudewheel.terminal
Edit
On this page

Terminal class for raw-mode input handling and screen management.

#claudewheel.terminal

#claudewheel.terminal

Raw terminal I/O: cbreak mode, escape sequence decoding, and alt screen.

#Terminal

Low-level terminal I/O: raw mode, key reading, alt screen, and size detection.

#get_size

python
def get_size(self) -> tuple[int, int]

Return the current terminal size as (rows, cols).

#enter_raw

python
def enter_raw(self, alt_screen: bool=True) -> None

Enter cbreak mode, optionally switching to the alt screen.

#subscribe_mode2031

python
def subscribe_mode2031(self) -> None

Subscribe to Mode 2031 theme-change notifications.

#exit_raw

python
def exit_raw(self) -> None

Restore the terminal to its pre-raw state.

#cooked

python
def cooked(self) -> Iterator[Terminal]

Temporarily leave raw mode for the duration of the with-block.

If the terminal is currently raw, exits raw mode on entry and re-enters it on exit with the same alt_screen flag it had before. If already cooked, this is a no-op passthrough (so nesting is safe). Raw mode is restored even if the body raises.

#read_key

python
def read_key(self) -> str

Read a single keypress, decoding escape sequences for arrow keys etc.

#read_masked_line

python
def read_masked_line(self, prompt: str='', mask: str='*') -> str

Read a line of input with echo suppressed, showing a mask per key.

Manages raw mode itself: if the terminal is not already raw it enters cbreak (alt-screen off) for the duration of the read and restores the prior mode afterward. Because :meth:enter_raw uses cbreak (not full raw), output newline translation stays on, so any surrounding prints still render correctly.

Key handling (over :meth:read_key semantics):

  • a printable single character accumulates and echoes mask;
  • BACKSPACE removes the last character and erases one mask glyph;
  • ENTER terminates and returns the accumulated string;
  • CTRL_C (also CTRL_D / ESC) raises KeyboardInterrupt;
  • any other key (arrows, function keys, paste-embedded control keys)

is ignored.

The typed characters are NEVER echoed and NEVER written to the tty in clear -- only mask glyphs are emitted -- so a secret can be entered without it appearing on screen or in captured output.

#_write_tty

python
def _write_tty(self, text: str) -> None

Write directly to the TTY device.

#write

python
def write(self, text: str) -> None

Write text to the terminal.

#flush

python
def flush(self) -> None

Flush the terminal output buffer.

#close

python
def close(self) -> None

Close the /dev/tty file handle.

#has_controlling_terminal

python
def has_controlling_terminal() -> bool

True when this process has a controlling terminal it can prompt at.

Every interactive surface here -- :class:Terminal, the PTY proxy, the forms -- reaches the user by opening /dev/tty rather than by reading stdin, precisely so a piped stdin does not disable them. So the honest test for "is there anybody to ask" is whether that same open succeeds: an isatty check on stdin or stdout would answer a different question and disagree in both directions (a piped stdin with a real terminal attached; a daemon with stdout on a pipe and no terminal at all).

Opens and immediately closes; nothing is read, written, or left open.

#detect_terminal_background

python
def detect_terminal_background() -> str | None

Detect whether the terminal has a light or dark background.

Uses the OSC 11 query (background color request) with a DA1 sentinel to detect terminals that do not support OSC 11. Returns "light", "dark", or None (unsupported / timeout / error).

Must be called BEFORE entering the TUI (before raw mode, before user input can race with the response).

#detect_mode2031_support

python
def detect_mode2031_support() -> str | None

Detect whether the terminal supports Mode 2031 (theme-change notifications).

Sends CSI ?996n (Mode 2031 query) + DA1 sentinel. If the terminal responds with CSI ?997;Xn (where X=1 for dark, X=2 for light), Mode 2031 is supported. Returns "dark", "light", or None.

Must be called BEFORE entering the TUI.

#_parse_mode2031_response

python
def _parse_mode2031_response(fd: int) -> str | None

Read and parse the Mode 2031 query response from the terminal.

Returns "dark" (mode=1), "light" (mode=2), or None (unsupported/timeout).

#_parse_osc11_response

python
def _parse_osc11_response(fd: int) -> str | None

Read and parse the OSC 11 response from the terminal.

Returns "light", "dark", or None.

#_classify_rgb

python
def _classify_rgb(rgb_str: str) -> str | None

Parse an rgb:RR/GG/BB (1-4 hex digits per channel) string and classify as light or dark.

Returns "light" if perceived luminance > 0.5, "dark" otherwise, or None on parse error.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • selfdoc Static Site Generator that builds a project's documentation site directly from its source code, so the docs can never drift from the code they describe, with SEO/AEO, first-class blog, search, and cross-project linking built in
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search