fix(zsh): prevent output truncation by using send-break for prompt reset#2567
fix(zsh): prevent output truncation by using send-break for prompt reset#2567
Conversation
| zle -I | ||
| zle reset-prompt | ||
|
|
||
| zle .accept-line |
There was a problem hiding this comment.
Implementation does not match the PR description. The code calls zle .accept-line but the description explicitly states the fix should use zle .send-break. These are fundamentally different ZLE widgets:
.accept-line(Enter key) accepts and executes the current line.send-break(Ctrl+G) aborts the current edit cycle and starts fresh
The description's rationale is that .send-break "aborts the current ZLE edit cycle and triggers a fresh prompt cycle at the actual terminal cursor pos", which is the intended behavior. Using .accept-line instead will execute the empty buffer (after BUFFER="") rather than aborting the edit cycle, which may not properly reset the prompt at the correct cursor position.
Fix:
zle .send-break| zle .accept-line | |
| zle .send-break |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
|
Action required: PR inactive for 5 days. |
Summary
Fix output truncation in the shell plugin where the last few lines of forge's interactive output were overwritten by the new prompt after command completion.
Context
When a user runs an interactive forge command (e.g.,
: hello world), the forge binary writes output directly to/dev/ttyto bypass ZLE's terminal ownership. After completion,_forge_resetusedzle -I+zle reset-promptto redraw the prompt. However,zle reset-promptredraws at the cursor position ZLE internally tracks -- which is stale because ZLE has no awareness that the forge binary moved the terminal cursor by writing output to/dev/tty. This caused ZLE to redraw the prompt at the original pre-output row, overwriting the last few lines of output.Changes
zle -I+zle reset-promptwithzle .send-breakin_forge_reset().send-break(the builtin Ctrl+G handler) aborts the current ZLE edit cycle and triggers a fresh prompt cycle at the actual terminal cursor position, instead of ZLE's stale tracked positionKey Implementation Details
The core issue is a mismatch between ZLE's internal cursor tracking and the real terminal cursor:
forge-accept-linecallszle redisplay, which anchors ZLE's tracked position at row R_forge_exec_interactiveruns the forge binary with</dev/tty >/dev/tty, writing output that moves the real cursor to row R+NWhy
zle reset-promptfails: It redraws at row R (stale), overwriting the last N lines of output.Why
zle .send-breakworks: It exits the ZLE edit cycle entirely. ZSH's normal prompt machinery (precmd-> prompt display) then draws the new prompt wherever the terminal cursor actually is (row R+N).The
.prefix calls the builtinsend-break, bypassing any user-defined widget of the same name (and our customforge-accept-line).Affected actions (those using
_forge_exec_interactivewhich writes to/dev/tty):_forge_action_default-- main AI chat_forge_action_new-- new conversation with prompt_forge_action_login-- provider loginUnaffected actions (those using
_forge_execwhich goes through ZLE pipes): All other actions (:info,:env,:tools,:config, etc.) -- ZLE's cursor tracking remains accurate for these, and.send-breakworks correctly as a universal replacement.Testing
: write me a mass of numbered lines from 1 to 50, each saying "this is line N"Finished <uuid>line and all 50 numbered lines are visible (scroll up if needed): againto test a second conversation on the same sessionLinks
_forge_resetiterations: commitsa5d77d2c4,ca0fac8bf