Skip to content

Avoid terminal rendering for non-TTY readline output - #922

Open
JoelTowell wants to merge 3 commits into
ruby:masterfrom
JoelTowell:fix-non-tty-readline-output
Open

Avoid terminal rendering for non-TTY readline output#922
JoelTowell wants to merge 3 commits into
ruby:masterfrom
JoelTowell:fix-non-tty-readline-output

Conversation

@JoelTowell

@JoelTowell JoelTowell commented Aug 25, 2026

Copy link
Copy Markdown

Problem

Reline decides which IO gate to use before readline knows whether it is actually writing to a terminal. On non-Windows platforms, Reline::IO.decide_io_gate can select Reline::ANSI whenever TERM is not dumb.

That selection is currently treated as enough for inner_readline to run the interactive display path. It updates dialogs, renders the line editor, renders the accepted line, and finally moves the cursor back to column 0. That is fine when stdout is a terminal, because those operations update what the user sees in place. It is an issue when stdout is a pipe, because the display output is captured as ordinary output.

With the ANSI IO gate, the final cursor movement writes an escape sequence, so captured output can contain bytes such as \e[1G. That is the escape-sequence symptom in #886.

TERM=dumb doesn't help. It switches to Reline::Dumb, where cursor methods intentionally do nothing. But inner_readline is still trying to render the line editor. Since the cursor methods do not move back over the previous display, the prompt and input text are left in place and appended again. That is the repeated-output symptom in #886, and related TERM=dumb behaviour is discussed in #660.

Reproduction

The first commit on this branch adds failing coverage for the non-TTY cases this PR changes. It can be checked out independently to see the behaviour currently on master.

Solution

Reline::Core already stores the configured output, but input= only forwards the input to the IO gate. This change stores the configured input as well.

readline now uses the interactive display path only when both input and output are TTYs. When that check passes, the existing terminal behaviour is unchanged. When it fails, readline writes plain output instead: the prompt once, then the accepted line once. EOF still returns nil, so there is no accepted line to echo.

This PR only changes the non-TTY path. It does not try to fix rendering in real TTY sessions, including TERM=dumb TTY sessions. Those still use the existing terminal path.

@JoelTowell
JoelTowell force-pushed the fix-non-tty-readline-output branch from 3a2c856 to 09436af Compare August 25, 2026 15:17
@JoelTowell
JoelTowell marked this pull request as draft August 25, 2026 15:25
@JoelTowell
JoelTowell force-pushed the fix-non-tty-readline-output branch from 09436af to 5513a1a Compare August 25, 2026 15:42
@JoelTowell
JoelTowell marked this pull request as ready for review August 25, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant