fix: Disable hl-line-mode in chat buffer to prevent scroll oscillation#100
Merged
fix: Disable hl-line-mode in chat buffer to prevent scroll oscillation#100
Conversation
The combination of hl-line-mode's post-command-hook overlay mutation, invisible text (markdown-hide-markup), and variable line heights (heading faces) triggers a redisplay feedback loop in GUI Emacs — the window oscillates ±25 lines when scrolling past headings. This is a known class of bugs in hl-line.el going back to 2004. Emacs 31 fixes it for global-hl-line-mode by moving to pre-redisplay-functions (commit 40a22ced147), but local hl-line-mode still uses post-command-hook on all versions. Disable both local and global hl-line-mode in chat-mode using the documented opt-out mechanism (hl-line.el line 50). Add regression test following the existing chat-mode property test pattern.
dnouri
added a commit
that referenced
this pull request
Feb 25, 2026
#100) The combination of hl-line-mode's post-command-hook overlay mutation, invisible text (markdown-hide-markup), and variable line heights (heading faces) triggers a redisplay feedback loop in GUI Emacs — the window oscillates ±25 lines when scrolling past headings. This is a known class of bugs in hl-line.el going back to 2004. Emacs 31 fixes it for global-hl-line-mode by moving to pre-redisplay-functions (commit 40a22ced147), but local hl-line-mode still uses post-command-hook on all versions. Disable both local and global hl-line-mode in chat-mode using the documented opt-out mechanism (hl-line.el line 50). Add regression test following the existing chat-mode property test pattern.
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.
Problem
In GUI Emacs, scrolling through the chat buffer with
global-hl-line-modeactive causes the window to jump ~27 lines and oscillate between two positions. Three factors must combine to trigger it:hl-line-mode(overlay mutation onpost-command-hook)markdown-hide-markup)Background
hl-line-modecallsmove-overlayinpost-command-hook, which setsprevent_redisplay_optimizations_pin the C display engine. This forces a fullwindow-startrecalculation viatry_to_scroll— but with invisible text and variable pixel heights, the engine picks a different position each frame, creating an oscillation loop. Terminal Emacs is unaffected because all lines have identical pixel height.This is a known bug class going back to 2004. Emacs 31 fixes it for
global-hl-line-modeby moving topre-redisplay-functions(commit40a22ced147), but localhl-line-modestill uses the buggy path on all versions.Fix
Disable both local and global
hl-line-modeinpi-coding-agent-chat-modeusing the documented opt-out. Users lose line highlighting in the chat buffer — acceptable for a buffer that was unusable with it enabled.Changes
pi-coding-agent.el: Disable hl-line in chat-mode bodytest/pi-coding-agent-test.el: Regression test following existing chat-mode property test pattern424/424 tests pass.