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
def get_size(self) -> tuple[int, int]Return the current terminal size as (rows, cols).
#enter_raw
def enter_raw(self, alt_screen: bool=True) -> NoneEnter cbreak mode, optionally switching to the alt screen.
#subscribe_mode2031
def subscribe_mode2031(self) -> NoneSubscribe to Mode 2031 theme-change notifications.
#exit_raw
def exit_raw(self) -> NoneRestore the terminal to its pre-raw state.
#cooked
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
def read_key(self) -> strRead a single keypress, decoding escape sequences for arrow keys etc.
#read_masked_line
def read_masked_line(self, prompt: str='', mask: str='*') -> strRead 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;
BACKSPACEremoves the last character and erases one mask glyph;ENTERterminates and returns the accumulated string;CTRL_C(alsoCTRL_D/ESC) raisesKeyboardInterrupt;- 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
def _write_tty(self, text: str) -> NoneWrite directly to the TTY device.
#write
def write(self, text: str) -> NoneWrite text to the terminal.
#flush
def flush(self) -> NoneFlush the terminal output buffer.
#close
def close(self) -> NoneClose the /dev/tty file handle.
#detect_terminal_background
def detect_terminal_background() -> str | NoneDetect 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
def detect_mode2031_support() -> str | NoneDetect 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
def _parse_mode2031_response(fd: int) -> str | NoneRead and parse the Mode 2031 query response from the terminal.
Returns "dark" (mode=1), "light" (mode=2), or None (unsupported/timeout).
#_parse_osc11_response
def _parse_osc11_response(fd: int) -> str | NoneRead and parse the OSC 11 response from the terminal.
Returns "light", "dark", or None.
#_classify_rgb
def _classify_rgb(rgb_str: str) -> str | NoneParse 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.