fix(runtime): throw a descriptive error when raw mode is unsupported (Ink parity, G10) (#40)

* fix(runtime): throw a descriptive error when raw mode is unsupported (Ink parity, G10)

Previously the raw-mode acquire path silently no-opped on a stdin where raw mode
is unsupported (non-TTY / isRawModeSupported false), so using useInput on such a
stdin did nothing with no diagnostic. Ink's handleSetRawMode (App.tsx:315-327)
instead throws immediately when enabling raw mode is unsupported, with two
distinct messages (default process.stdin vs a custom stdin) both pointing at the
isRawModeSupported docs.

StdinController.acquireRawMode now throws that two-message error on
!isRawModeSupported. The unguarded useInput path surfaces it (matching Ink's
use-input.ts, which calls setRawMode(true) ungated). useFocus now guards on
isRawModeSupported before acquiring (matching Ink's use-focus.ts), so focus
degrades to a safe no-op on a non-TTY rather than throwing. releaseRawMode keeps
its no-op guard — Ink only throws when enabling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(parity): ledger — G10 pr-open, reconcile G09 merged

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(runtime): assert full raw-mode error message for exact Ink parity (G10, codex)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Yunfei He
2026-05-30 03:07:32 +08:00
committed by GitHub
parent 61e4e09a1e
commit 33055e429c
4 changed files with 112 additions and 4 deletions
+16 -1
View File
@@ -1048,7 +1048,22 @@ function createStdinController(
internal_eventEmitter: emitter,
internal_exitOnCtrlC: opts.exitOnCtrlC,
acquireRawMode() {
if (!appCtx.isRawModeSupported) return;
if (!appCtx.isRawModeSupported) {
// Match Ink's handleSetRawMode (App.tsx): enabling raw mode on an
// unsupported stdin throws a descriptive error rather than silently
// no-opping. Two messages — one for the default process.stdin, one for
// a custom stream — both pointing at the isRawModeSupported docs. The
// unguarded useInput path surfaces this; useFocus guards before calling
// (see composables/useFocus.ts), so it degrades to a no-op like Ink.
if (stdin === process.stdin) {
throw new Error(
"Raw mode is not supported on the current process.stdin, which Vue TUI uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported",
);
}
throw new Error(
"Raw mode is not supported on the stdin provided to Vue TUI.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported",
);
}
const state = getRawModeState(stdin);
if (state.refs === 0) {
state.prevRaw = (stdin as { isRaw?: boolean }).isRaw ?? false;