Skip to content

Fix block cursor glyph visibility when colors collide - #2491

Open
sinelaw wants to merge 1 commit into
masterfrom
claude/wonderful-bell-kbf8lu
Open

Fix block cursor glyph visibility when colors collide#2491
sinelaw wants to merge 1 commit into
masterfrom
claude/wonderful-bell-kbf8lu

Conversation

@sinelaw

@sinelaw sinelaw commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes an issue where glyphs under a block cursor become invisible when their foreground color matches the terminal cursor color (e.g., a keyword token in Dracula theme where both share the same magenta color).

Changes

  • Glyph collision detection and fix: Added fix_block_cursor_glyph_collision() method that detects when a glyph's foreground exactly matches the cursor color and recolors it to maintain visibility

    • Only applies to block-style cursors (Default, BlinkingBlock, SteadyBlock)
    • Inverts the glyph to its cell background color, with fallbacks to editor background and foreground if needed
    • Only touches the single cursor cell; non-cursor glyphs retain their syntax colors
  • Cursor style classification: Added is_block() method to CursorStyle to identify which cursor styles fully cover the glyph cell (block cursors) versus those that leave it visible (bar/underline)

  • Theme color override utility: Added override_theme_colors() method to Editor for test support, allowing runtime color manipulation to reproduce specific collision scenarios

  • Comprehensive test coverage:

    • Unit tests for the collision detection logic covering various color fallback scenarios
    • E2E tests verifying block cursors recolor colliding glyphs while bar cursors do not
    • Tests confirm non-cursor glyphs keep their original colors

Implementation Details

The fix avoids using the software REVERSED modifier (which would double-invert in multiplexers like tmux/zellij) and instead performs a targeted foreground inversion only on the colliding glyph. The replacement color selection prioritizes the cell's own background, then falls back to editor background and foreground to ensure the result never collides with the cursor color itself.

https://claude.ai/code/session_01Ta2tojr71nT75V96rmz9ci

@sinelaw
sinelaw force-pushed the claude/wonderful-bell-kbf8lu branch from 50701b5 to 2d0fdc4 Compare June 26, 2026 16:19
A hardware block cursor is drawn by the terminal: it fills the cursor
cell's background with the theme cursor color (sent via OSC 12) but
leaves the glyph in its own foreground color. The primary cursor cell
deliberately skips the software REVERSED modifier (it double-inverts
inside multiplexers like tmux/zellij), so a glyph whose foreground is
close to — or identical with — the cursor color is hard to read or
vanishes entirely (e.g. a syntax.keyword token in Dracula, where the
keyword and cursor share a color).

Always repaint the block-cursor cell's glyph to a high-contrast color
(black or white by the cursor color's luminance), independent of the
glyph's own color, so the cursor reads like a normal reverse-video
block. The recolor is applied after color conversion so the 256-color
contrast pass cannot undo it, and only the single cursor cell is
touched. Bar/underline cursors leave the glyph visible and are
unaffected; an unresolvable cursor color (no OSC 12) is left to the
terminal's own cursor.

Two existing rendering tests sampled the exact cell the caret sits on
(the first ANSI block; line 1's keyword in the CRLF highlight test);
move their caret off the sampled cells so they observe content color
rather than the cursor glyph.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ta2tojr71nT75V96rmz9ci
@sinelaw
sinelaw force-pushed the claude/wonderful-bell-kbf8lu branch from 2d0fdc4 to f975137 Compare July 17, 2026 11:55
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.

2 participants