Skip to content

[ Deep dives ]

Troubleshooting

  • Cause: App::run() checks m_term.is_tty(), which requires both isatty(STDIN_FILENO) != 0 and isatty(STDOUT_FILENO) != 0 (src/terminal.cpp:221, 427). Running the binary with redirected input/output (./app > out.log or inside a non-interactive test runner) returns TerminalError::NotATty (system_errno = ENOTTY).
  • Fix: Run interactive binaries directly in a terminal emulator, or use app.draw_frame(false) and app.dispatch_event(...) for automated headless tests.

Terminal left in raw mode or mouse tracking after SIGKILL (kill -9)

Section titled “Terminal left in raw mode or mouse tracking after SIGKILL (kill -9)”
  • Cause: Terminal installs signal handlers for SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGSEGV, SIGABRT, SIGBUS, SIGFPE, SIGILL, std::terminate, and std::atexit that call restore_minimal() (src/terminal.cpp:27-38, 140-183). However, the kernel does not allow any process to catch SIGKILL (kill -9) or SIGSTOP.
  • Fix: Run the exact escape sequence from restore_minimal() (src/terminal.cpp:29-33) and reset termios:
Terminal window
printf "[?1006l[?1003l[?1002l[?1000l[<u[?2004l[?25h[?1049l"
stty sane

Colors are missing or quantized to 16 or 256 colors

Section titled “Colors are missing or quantized to 16 or 256 colors”
  • Cause: detect_system_color_mode() (src/color.cpp:226-273) evaluates environment variables in this exact order:
    1. If NO_COLOR is set and non-empty (no_color[0] != '�'), returns ColorMode::NoColor.
    2. If TERM equals "dumb", returns ColorMode::NoColor.
    3. If COLORTERM equals "truecolor" or "24bit", returns ColorMode::TrueColor.
    4. If TERM is set:
      • If TERM ends with "-direct" or contains "truecolor", returns ColorMode::TrueColor.
      • If TERM contains "256color" or "256", returns ColorMode::Ansi256.
      • Otherwise, returns ColorMode::Ansi16.
    5. If TERM is unset, defaults to ColorMode::TrueColor.
  • Fix: Export COLORTERM=truecolor in your shell or tmux environment, unset NO_COLOR, or override the mode in code via Terminal::color_mode(ColorMode::TrueColor).

Modified keys like Ctrl+Enter or Shift+Enter behave like plain Enter

Section titled “Modified keys like Ctrl+Enter or Shift+Enter behave like plain Enter”
  • Cause: Legacy VT100/xterm terminals send (0x0D) for both Enter and Ctrl+Enter / Shift+Enter. Terminal::enter_raw_mode() sends [>1u to enable Kitty keyboard protocol flag 1 (DISAMBIGUATE_ESCAPE_CODES) (src/terminal.cpp:347-355), which causes supporting terminals to emit  (Ctrl+Enter) and  (Shift+Enter) (src/event.cpp:269-280). Terminals that do not implement the Kitty keyboard protocol ignore [>1u and continue sending .
  • Fix: Provide fallback key bindings (such as Alt+Enter, which sends  and is decoded as KeyEvent{Key::Enter, false, false, true, false} at src/event.cpp:506, or Ctrl+S) for terminals without Kitty keyboard protocol support.

Global hotkeys stop working when TextInput, TextArea, List, or Tabs is focused

Section titled “Global hotkeys stop working when TextInput, TextArea, List, or Tabs is focused”
  • Cause: When app.use_focus(fm) is active, App::dispatch_event calls fm.handle_key(*key) before m_key_handler(*key) (src/app.cpp:166-180).
    • TextInputState and TextAreaState consume all unmodified printable characters (!key.ctrl && !key.alt && key.is_char()).
    • ListState consumes 'j', 'k', 'g', 'G', Up, Down, Home, and End.
    • TabsState consumes 'h', 'l', '1'..'9', Left, Right, Home, and End.
  • Fix: Use Key::Escape, ctrl combinations (key.ctrl && key.ch == 'Q'), or register a pre-hook via fm.interceptor(...) (src/focus.cpp:540-543).