fix(zsh): prevent output truncation by using send-break for prompt reset#2567
Open
fix(zsh): prevent output truncation by using send-break for prompt reset#2567
Conversation
| zle -I | ||
| zle reset-prompt | ||
|
|
||
| zle .accept-line |
Contributor
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
Suggested change
| zle .accept-line | |
| zle .send-break |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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