Clamp window-point when TUI cursor lands at point-max (fix #138)#139
Merged
Clamp window-point when TUI cursor lands at point-max (fix #138)#139
Conversation
When a TUI's cursor is in pending-wrap state on the last visible row, the native redraw can set (point) to point-max (one past the last character). Emacs redisplay then treats that position as off-screen and — with ghostel-mode's scroll-conservatively=101 — shifts window-start up by a row to make it visible. This fights the viewport pin in ghostel--anchor-window and makes the block cursor disappear until the next focus event. Clamp window-point back by one in ghostel--anchor-window when pt equals point-max so it sits inside the viewport. Buffer-point is untouched, and subsequent redraws recapture the real cursor. Closes #138.
There was a problem hiding this comment.
Pull request overview
Fixes a TUI cursor “pending-wrap at point-max” edge case where Emacs redisplay (with scroll-conservatively=101) scrolls the window by one row, breaking Ghostel’s viewport pin and causing the block cursor to disappear.
Changes:
- Clamp the value passed to
set-window-pointinghostel--anchor-windowwhenpt == point-max(non-empty buffer) to keep the rendered point inside the viewport. - Add an ERT regression test covering clamp/non-clamp behavior plus empty-buffer and trailing-newline cases.
- Register the new test in the pure-Elisp test list.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
ghostel.el |
Adds point-max pending-wrap clamp in ghostel--anchor-window to prevent redisplay from auto-scrolling against the viewport anchor. |
test/ghostel-test.el |
Adds and registers an ERT regression test to ensure clamping behavior across key edge cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dakra
added a commit
that referenced
this pull request
Apr 19, 2026
PR #139 clamped `window-point` to pt-1 whenever pt equalled point-max to fix the TUI pending-wrap scenario from #138. That condition also matches the normal case of a user typing at a shell prompt, where the cursor legitimately sits at point-max after the last character. The block cursor was drawn on top of the last character instead of after it, which is very visible over SSH (no shell-integration OSC between keystrokes to nudge point off point-max). Only clamp when libghostty reports the active cursor in pending-wrap state. Expose that flag via a new `ghostel--cursor-pending-wrap-p' native function, backed by GHOSTTY_TERMINAL_DATA_CURSOR_PENDING_WRAP. Test changes: - Rename the elisp regression to `ghostel-test-anchor-window-no-clamp-without-pending-wrap' and assert the #146 contract (no term -> no clamp even at point-max). - Add native `ghostel-test-cursor-pending-wrap-p' covering the flag. - Add native `ghostel-test-anchor-window-clamps-on-pending-wrap' exercising both branches through a real terminal. Closes #146.
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
ghostel--anchor-windowreceivespt == point-max == window-end. Emacs redisplay then classifies point as off-screen and — becauseghostel-modesetsscroll-conservatively=101— shiftswindow-startup by a row to keep point visible, which fights the viewport pin and makes the block cursor disappear until the next focus event.ghostel--anchor-window, clamp the value passed toset-window-pointtopt-1whenpt == point-max(and the buffer is non-empty). Buffer(point)is untouched; the next redraw recaptures the real cursor.ghostel-test-anchor-window-clamps-pending-wrapcovering the clamp, non-clamp, empty-buffer, and trailing-newline cases.Test plan
make lint(byte-compile + checkdoc + package-lint)make -j4 all— 126/126 elisp tests + 78/78 native tests passemacs --batch: withpt=point-max,window-pointclamps topt-1; withpt<point-max, unchanged