Anchor window-point clamp via pos-visible-in-window-p#158
Closed
emil-e wants to merge 1 commit intodakra:mainfrom
Closed
Anchor window-point clamp via pos-visible-in-window-p#158emil-e wants to merge 1 commit intodakra:mainfrom
emil-e wants to merge 1 commit intodakra:mainfrom
Conversation
The pending-wrap-narrowed clamp from ad8536e fixes dakra#146 but reopens a variant of dakra#138 for TUIs that move the cursor to the bottom row via CUP rather than by writing-then-wrapping. In that case pt = point-max and the cursor sits on the last viewport row, but ghostel--cursor-pending-wrap-p returns nil, so the clamp does not fire and Emacs scrolls window-start by one row to make pt visible — fighting the viewport pin. The real precondition for the bug is "Emacs considers pt = point-max off-screen given the just-pinned window-start", which is exactly what pos-visible-in-window-p answers. Replace the pending-wrap predicate with that direct check. pending-wrap becomes a special case of "pt off-screen", so the dakra#138 fix is preserved; mid-window typing at a shell prompt continues to render the block cursor after the last character (dakra#146).
Contributor
Author
|
Closing — the proposed approach (replace |
5 tasks
dakra
added a commit
that referenced
this pull request
Apr 20, 2026
ad8536e narrowed the `ghostel--anchor-window' clamp to fire only when libghostty reports pending-wrap, which fixed the #146 regression but reopened a variant of #138 for TUIs that move their cursor to the bottom of the screen via absolute positioning (CUP) rather than via writing-then-wrapping. In that case `pt' equals `point-max' and the cursor sits on the last viewport row, but pending-wrap is nil — so the clamp doesn't fire and Emacs shifts `window-start' by one row to make `pt' "visible," fighting the viewport pin. Expose a second terminal-side predicate `ghostel--cursor-on-empty-row-p' backed by a new `render.isRowEmptyAt' helper, and widen the clamp guard to `(or pending-wrap cursor-on-empty-row)'. The predicate returns t iff the row containing the cursor has no written cells and no cells with non-default styling — exactly the condition under which `buildRowContent' produces `byte_len == 0'. Wide-spacer-tail cells are skipped to mirror `buildRowContent' (defensive — in practice spacer tails always follow a wide grapheme). Source `cy' from `RS_DATA_CURSOR_VIEWPORT_Y' gated by `...HAS_VALUE' so the coordinate space matches the viewport row iterator that `isRowEmptyAt' walks, and the predicate returns nil when the cursor isn't visible in the current viewport. Caller owns the `ghostty_render_state_update' refresh so it only happens once per call. An earlier draft (#158) tried `pos-visible-in-window-p' but it reflects the previous redisplay rather than the just-pinned `window-start', and breaks in batch. The terminal-side predicate answers the real question — is there anything on this row to anchor `pt' to? — without consulting Emacs redisplay state. Bump module version to 0.16.3 (new exported function). Test changes: - `ghostel-test-cursor-on-empty-row-p' covers the predicate across fresh-terminal / post-write / post-CRLF / post-CUP cursor positions. - `ghostel-test-anchor-window-clamps-on-empty-row' is the #157 regression test: feeds "foo\r\nbar\r\n" to park the cursor on an empty last row, asserts PT lands at `point-max', pending-wrap is nil, empty-row is t, and the clamp fires. - `ghostel-test-anchor-window-no-clamp-on-populated-last-row' complements #146: cursor at `point-max' on a last row that does have content (e.g. a shell prompt) must NOT be clamped regardless of which predicate is consulted. Closes #157.
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.
Fixes #157.
Summary
ghostel--cursor-pending-wrap-ppredicate inghostel--anchor-windowwith(not (pos-visible-in-window-p pt win)).pending-wrapis one way to land atpt = point-maxon a position Emacs treats as off-screen, but not the only one — CUP placements to(0, last-row)reach the same state without setting pending-wrap, which lets the redisplay-inducedwindow-startscroll re-emerge (variant of ghostel--anchor-window + scroll-conservatively: cursor-past-last-row shifts viewport up by one row #138).window-startto bringptinto view.pending-wrapbecomes a special case of this, so the ghostel--anchor-window + scroll-conservatively: cursor-past-last-row shifts viewport up by one row #138 fix is preserved; mid-window typing at a shell prompt continues to render the block cursor after the last character (PR #139 broke cursor in normal terminal usage #146).See #157 for reproduction, evidence (focus-change/anchor-window log on Claude Code as the example TUI), and case-by-case coverage table.
Test plan
(0, body-height - 1)via CUP (not pending-wrap) withpt = point-max, assertwpis clamped.Marked draft pending the regression test and a maintainer sanity check on
pos-visible-in-window-pperformance inside the redraw path (called once per anchored window per redraw — likely fine but worth confirming against any existing benchmarks).