Keep point with the prompt across streamed fragment inserts#13
Draft
timvisher-dd wants to merge 1 commit into
Draft
Keep point with the prompt across streamed fragment inserts#13timvisher-dd wants to merge 1 commit into
timvisher-dd wants to merge 1 commit into
Conversation
The shell render path (agent-shell--update-fragment/--update-text) leaned on shell-maker-with-auto-scroll-edit's save-excursion to preserve point. That marker is insertion-type nil, so when the insert-cursor sits exactly at point — an empty prompt, or point at the start of pending input — and auto-scroll is suppressed (window-end trails point-max while data streams), text inserted at the marker leaves it behind. Point ends up above the freshly inserted fragment and the prompt drops below it. Add agent-shell--with-preserved-point, which saves point in an insertion-type t marker (so it advances past insertions made at point) and snaps to point-max when point was at end-of-buffer. Wrap both shell-branch call sites. This mirrors agent-shell--append-tool-call-output, which was already immune for the same reason. Regression of the class fixed by 6babf80, re-exposed by the insert-cursor streaming rework in 25a3b75 — neither shipped a test covering point at the insert position, so add two. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
An old bug came back: while the agent streams, the cursor jumps up and gets stranded above the freshly inserted text instead of staying with the prompt. It reproduces across machines and is intermittent, which is what makes it annoying to pin down.
Problem
When point is sitting right at the prompt — an empty prompt, or point moved to the start of pending input — a streamed message fragment can land above point, leaving the cursor behind the new text with the prompt pushed below it. It only happens when the buffer is not auto-scrolling at that instant (you've scrolled up a touch, or
window-endis momentarily trailingpoint-maxwhile data flows), so it feels random.Cause
The shell render path (
agent-shell--update-fragment/agent-shell--update-text) leans onshell-maker-with-auto-scroll-edit'ssave-excursionto hold point across the insertion. In the non-auto-scroll branch that's a plainsave-excursion, whose marker is insertion-type nil. New fragments are inserted at the insert-cursor (the process-mark). When point happens to sit exactly at that position, inserting there leaves an insertion-type nil marker before the inserted text — so point is restored above the new fragment.The tool-call output path (
agent-shell--append-tool-call-output) never had this problem because it already saves point as(copy-marker (point) t)— an insertion-type t marker advances past insertions made at point. The message/fragment path was simply never given the same treatment.This is a regression of the class fixed in 6babf80 ("Preserve point and window-start across streaming rerenders"), which was superseded by the insert-cursor streaming rework in 25a3b75 (PR #7). Neither shipped a test that put point at the insert position, so nothing failed when the architecture changed underneath it.
Fix
Add
agent-shell--with-preserved-point, a small macro that:point-maxwhen point was at end-of-buffer — i.e. the prompt — so a streaming chunk never leaves the cursor behind regardless of shell-maker's auto-scroll decision.Both shell-branch call sites (
agent-shell--update-fragmentandagent-shell--update-text) are wrapped in it, outsideagent-shell--with-preserved-process-markso the point restore is the final word. This mirrors the already-immune tool-output path rather than reaching back into shell-maker'ssave-excursion.Tests
Two ERT regression tests in
tests/agent-shell-streaming-tests.el:agent-shell--with-preserved-point-keeps-cursor-at-empty-prompt-test— point at an empty prompt (end-of-buffer); a fragment inserted there must leave point atpoint-max, not stranded behind it.agent-shell--with-preserved-point-advances-past-insertion-test— point at the start of pending input but not at end-of-buffer; point must advance past the inserted text, staying with the input.Both were verified to fail against the old insertion-type nil
save-excursionbehavior and pass with the fix, so they actually guard the regression rather than just exercising the happy path. Fullbin/testis green (246 tests, 0 unexpected, 1 expected skip). README features list updated.Checklist
I've filed a feature request/discussion for a new feature.N/A — bug fix (tracked in private bd).I'm making visual changes, so I'm including screenshots so you can view and discuss.N/A — cursor-position behavior; no static screenshot captures it.M-x checkdocandM-x byte-compile-file.