Skip to content

Fix cursor visibility and command palette rendering in zellij#1338

Merged
sinelaw merged 1 commit intomasterfrom
claude/fix-cursor-palette-issues-ci6ZP
Mar 24, 2026
Merged

Fix cursor visibility and command palette rendering in zellij#1338
sinelaw merged 1 commit intomasterfrom
claude/fix-cursor-palette-issues-ci6ZP

Conversation

@sinelaw
Copy link
Copy Markdown
Owner

@sinelaw sinelaw commented Mar 24, 2026

Summary

Fixes #1255 — cursor disappearing and command palette not visible when running fresh inside zellij.

  • Wrap terminal.draw() with crossterm's BeginSynchronizedUpdate / EndSynchronizedUpdate (DEC private mode 2026)
  • This tells terminal multiplexers like zellij to batch the entire render atomically instead of displaying intermediate frames

Root Cause

Without synchronized updates, zellij splits fresh's single render into multiple output frames. This causes two user-visible bugs:

  1. Command palette invisible until interaction: Zellij emits a SHOW_CURSOR (signaling "frame complete") 13ms before the palette content arrives. The terminal renders a phantom frame showing the editor without the palette. The palette only appears on the next frame — which in some cases doesn't arrive until the next user input.

  2. Cursor flickering/disappearing during navigation: Zellij adds HIDE_CURSOR/SHOW_CURSOR pairs around its redraws. Without sync updates, intermediate states (cursor hidden, content partially drawn) are visible between frames.

Verification

Measured palette rendering through zellij before and after:

Metric Before After
Gap between SHOW_CURSOR and palette content +13.5ms +0.0ms
SHOW_CURSOR events before palette appears 1 (phantom frame) 0
Output chunks from zellij 2 (split render) 1 (atomic)

Cursor movement also now arrives in a single atomic chunk instead of being split across frames.

Test plan

  • cargo test --lib — 95 passed, 0 failed
  • Verified palette opens atomically in zellij (0 phantom frames)
  • Verified cursor movement renders in single chunk through zellij
  • Verified synchronized update sequences (?2026h/?2026l) are emitted by fresh
  • Manual testing in zellij by a user who can reproduce the original issue

https://claude.ai/code/session_01W6Pe5tA84E8rBjVcRNwCur

Wrap terminal.draw() with crossterm's BeginSynchronizedUpdate /
EndSynchronizedUpdate (DEC private mode 2026). Without synchronized
updates, zellij splits fresh's render into multiple frames, causing:

1. Command palette appearing invisible until the next user interaction
   (zellij renders a phantom frame without palette content before the
   palette data arrives)
2. Cursor flickering/disappearing during navigation (intermediate
   frames show hidden cursor state between redraws)

With this fix, zellij batches the entire render atomically - palette
opens in 1 chunk instead of 2, with 0 phantom frames.

https://claude.ai/code/session_01W6Pe5tA84E8rBjVcRNwCur
@sinelaw sinelaw merged commit dadce54 into master Mar 24, 2026
8 checks passed
@spTorin
Copy link
Copy Markdown

spTorin commented Mar 24, 2026

@sinelaw
The cursor still doesn't render properly in Zellij :(
It's visible on empty lines and hidden on lines with characters.

Builded from master with dadce54 commit

sinelaw added a commit that referenced this pull request Mar 24, 2026
The REVERSED cell modifier + hardware block cursor caused double-inversion
in terminal multiplexers like zellij, making the cursor invisible. Now
REVERSED is only applied to the primary cursor in software_cursor_only mode
(GUI backend). When a hardware cursor is available, it alone provides the
primary cursor visual; secondary cursors still use REVERSED.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
sinelaw added a commit that referenced this pull request Mar 24, 2026
The REVERSED cell modifier + hardware block cursor caused double-inversion
in terminal multiplexers like zellij, making the cursor invisible. Now
REVERSED is only applied to the primary cursor in software_cursor_only mode
(GUI backend). When a hardware cursor is available, it alone provides the
primary cursor visual; secondary cursors still use REVERSED.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
sinelaw added a commit that referenced this pull request Mar 24, 2026
The REVERSED cell modifier + hardware block cursor caused double-inversion
in terminal multiplexers like zellij, making the cursor invisible. Now
REVERSED is only applied to the primary cursor in software_cursor_only mode
(GUI backend). When a hardware cursor is available, it alone provides the
primary cursor visual; secondary cursors still use REVERSED.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
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.

Hidden cursor, if editor run into zellij terminal workspace

3 participants