Skip to content

Add blinking cursor support#434

Merged
dakra merged 1 commit into
mainfrom
cursor-blink
Jun 20, 2026
Merged

Add blinking cursor support#434
dakra merged 1 commit into
mainfrom
cursor-blink

Conversation

@dakra

@dakra dakra commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Summary

Adds blinking cursor support — the one cursor capability ghostel was missing versus eat. ghostty's VT engine already computes the blink state (DECSCUSR mode 12), but the renderer was dropping it; now a terminal app that requests a blinking bar/block/underline actually blinks in the Emacs buffer instead of rendering steady.

How it works

  • Renderer forwards render_state.cursor.blinking to the buffer-local ghostel--cursor-blinking (threaded like ghostel--cursor-pos, so ghostel--set-cursor-style keeps its 2-arg signature — no churn for evil-ghostel's advice or existing tests).
  • A per-buffer timer blinks the cursor with internal-show-cursor — the same cheap primitive Emacs's own blink-cursor-mode uses (no redraw-frame, unlike eat).
  • Yields to a globally-enabled blink-cursor-mode to avoid a double beat, and only runs on graphical frames.

Window-leak fix

internal-show-cursor sets a per-window "cursor off" flag, so a window the blink left mid-"off" would hide the cursor of whatever buffer it showed next (e.g. split the terminal's window, switch it to *scratch* → no cursor). The blinked window is restored both when the blink stops and on window-buffer-change-functions — deferred via run-at-time 0 because internal-show-cursor is inert during redisplay, which is when those functions run. Both hooks are installed only while actively blinking and removed on stop (no per-command hooks).

Other

  • evil-ghostel ends any terminal-driven blink when evil reclaims the cursor on leaving the alt-screen.
  • Docs: README feature comparison now splits "Cursor shapes" (ghostel 4, incl. hollow / vterm 3 / eat 3) from "Blinking cursor" (ghostel ✅ / vterm partial / eat ✅); CHANGELOG entry added.

Testing

  • Unit test ghostel-test-cursor-blink (timer start/stop + hook install/removal).
  • Verified live in a GUI Emacs via elate: DECSCUSR \e[5 q starts a real toggling blink, \e[2 q goes steady, copy mode cancels it, and C-x b *scratch* from the blinked window leaves the cursor visible (the leak fix).
  • make -j8 all green.

Honor the terminal's DECSCUSR blink request (mode 12), which the
renderer previously dropped. The renderer forwards
`render_state.cursor.blinking' as the buffer-local
`ghostel--cursor-blinking', and a per-buffer timer blinks the cursor
via `internal-show-cursor' (the primitive Emacs's own
`blink-cursor-mode' uses) for the bar, block, and underline shapes.
The blink yields to a globally-enabled `blink-cursor-mode' to avoid a
double beat, and only runs on graphical frames.

`internal-show-cursor' sets a per-window flag, so a window the blink
left in its "off" phase would hide the next buffer's cursor. The
blinked window is restored both when the blink stops and on
`window-buffer-change-functions' (deferred out of redisplay, where
`internal-show-cursor' is inert). Both hooks are installed only while
actively blinking and removed on stop.

evil-ghostel ends any terminal-driven blink when evil reclaims the
cursor on leaving the alt-screen. README/CHANGELOG updated; the
feature comparison now splits cursor shapes from blink support.
@dakra
dakra force-pushed the cursor-blink branch 2 times, most recently from d7013e4 to a551781 Compare June 20, 2026 20:43
@dakra
dakra merged commit a551781 into main Jun 20, 2026
19 checks passed
@dakra
dakra deleted the cursor-blink branch June 20, 2026 20:43
@dakra
dakra temporarily deployed to github-pages June 20, 2026 20:43 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant