When I keep one chat pane at the bottom and another pane on earlier context, new assistant output should keep the bottom pane useful. It should not show a few new lines followed by a big empty area while the real tail is already visible.
A tmux-driven emacs -nw validation run found one way this can still happen. The thinking-collapse rewrite itself is fixed, but the next streamed output can leave a split tail-following pane underfilled.
What the user sees
In terminal Emacs with the chat buffer split into two stacked windows:
- the top window is following the chat tail;
- the bottom window is reading earlier context;
- after a thinking display toggle and the next assistant output starts, the top pane can show only a handful of new lines and then blank space.
The pane is technically at the tail, but it does not feel like a chat tail pane because it is not filled.
Observed during the visual run:
== after display-agent-start ==
tail: start L125 S10 after line 046
point L134 row 8
tail=t blank=9 body=17
== after display-message-delta ==
tail: start L138 S10 streamed tail line after toggle 005
point L146 row 8
tail=t blank=9 body=17
The context pane stayed anchored correctly. The problem is only the tail-following pane being underfilled.
Expected behavior
A following chat window should stay pinned to the useful tail view. If there is enough buffer text to fill the pane, it should leave at most the normal small amount of blank space below the tail.
A non-following sibling window should still keep its reading position.
Likely cause
The normal streaming scroll helper is weaker than the rewrite-preservation helper.
In pi-coding-agent-ui.el, pi-coding-agent--with-scroll-preservation detects following windows with pi-coding-agent--window-following-p. After the insert, it restores following windows with only:
(set-window-point win (point-max))
That puts point at the buffer end, but Emacs only has to make point visible. In a split window it may leave point around the middle of the pane, which leaves blank rows below it.
The new rewrite-preservation path in pi-coding-agent-render.el does the stronger thing for tail windows:
(goto-char point-max)
(recenter -1)
That is why the collapse/toggle rewrite stays filled, but the next normal stream can underfill the tail pane again.
A likely fix
Make following windows in pi-coding-agent--with-scroll-preservation bottom-pin themselves instead of only moving point.
The shape is probably a small helper in pi-coding-agent-ui.el:
(defun pi-coding-agent--scroll-window-to-tail (window)
"Move WINDOW to the current buffer tail and keep the view filled."
(when (and (window-live-p window)
(eq (window-buffer window) (current-buffer)))
(with-selected-window window
(goto-char (point-max))
(recenter -1))))
Then the following-window loop in pi-coding-agent--with-scroll-preservation can use that helper under save-selected-window. The existing non-following-window preservation should stay as-is.
Suggested test
A good red test would use a real windowed ERT setup:
- create a chat buffer with enough content to fill split windows;
- split the buffer into two stacked windows;
- put the top window at the tail;
- put the bottom window on earlier content;
- append a short assistant header or call
pi-coding-agent--display-agent-start;
- assert the top window still reaches the tail and has at most one blank row;
- assert the bottom window's start/point did not move.
A slightly fuller regression can include the path that found the issue: whole-chat thinking display toggle, then pi-coding-agent--display-agent-start, then pi-coding-agent--display-message-delta.
The important red assertion appears immediately after pi-coding-agent--display-agent-start, before any long stream is needed.
When I keep one chat pane at the bottom and another pane on earlier context, new assistant output should keep the bottom pane useful. It should not show a few new lines followed by a big empty area while the real tail is already visible.
A tmux-driven
emacs -nwvalidation run found one way this can still happen. The thinking-collapse rewrite itself is fixed, but the next streamed output can leave a split tail-following pane underfilled.What the user sees
In terminal Emacs with the chat buffer split into two stacked windows:
The pane is technically at the tail, but it does not feel like a chat tail pane because it is not filled.
Observed during the visual run:
The context pane stayed anchored correctly. The problem is only the tail-following pane being underfilled.
Expected behavior
A following chat window should stay pinned to the useful tail view. If there is enough buffer text to fill the pane, it should leave at most the normal small amount of blank space below the tail.
A non-following sibling window should still keep its reading position.
Likely cause
The normal streaming scroll helper is weaker than the rewrite-preservation helper.
In
pi-coding-agent-ui.el,pi-coding-agent--with-scroll-preservationdetects following windows withpi-coding-agent--window-following-p. After the insert, it restores following windows with only:That puts point at the buffer end, but Emacs only has to make point visible. In a split window it may leave point around the middle of the pane, which leaves blank rows below it.
The new rewrite-preservation path in
pi-coding-agent-render.eldoes the stronger thing for tail windows:That is why the collapse/toggle rewrite stays filled, but the next normal stream can underfill the tail pane again.
A likely fix
Make following windows in
pi-coding-agent--with-scroll-preservationbottom-pin themselves instead of only moving point.The shape is probably a small helper in
pi-coding-agent-ui.el:Then the following-window loop in
pi-coding-agent--with-scroll-preservationcan use that helper undersave-selected-window. The existing non-following-window preservation should stay as-is.Suggested test
A good red test would use a real windowed ERT setup:
pi-coding-agent--display-agent-start;A slightly fuller regression can include the path that found the issue: whole-chat thinking display toggle, then
pi-coding-agent--display-agent-start, thenpi-coding-agent--display-message-delta.The important red assertion appears immediately after
pi-coding-agent--display-agent-start, before any long stream is needed.