codemirror-vim icon indicating copy to clipboard operation
codemirror-vim copied to clipboard

Fix cursor rendering for Arabic connected characters

Open diraneyya opened this issue 2 months ago • 5 comments

Problem

The block cursor in Vim mode breaks the visual continuity of Arabic connected characters, making text editing confusing and difficult for Arabic users.

Issue 1: Character Breaking

❌ Cursor breaking letter connection ✅ Cursor not breaking letter connection
image image

The opaque cursor background covers Arabic letters, disrupting their connected forms. Arabic letters change shape based on position (isolated/initial/medial/final), and these visual connections are essential for readability.

When the cursor is on a character like ن in the middle of a word, the character appears in its connected (medial) form in the actual text, but the cursor div contains the isolated form, creating visual disruption.

Issue 2: Incorrect Width

ا كـ ـتـ  ـب مسافة
image image image image image

The cursor width was based on the isolated form of characters rather than their actual rendered width in connected text:

  • Letter ن when connected (narrow): cursor was too wide with extra space
  • Letter ك in different positions: cursor didn't match actual glyph width
  • End of line: cursor extended far beyond the character

Issue 3: Newline Selection

In normal mode, the cursor could be positioned on newline characters at the end of lines (unlike standard Vim behavior where $ positions on the last character).

Solution

1. Transparent Cursor with Outline

  • Changed from opaque background: #ff9696 to background: transparent with box-shadow: 0 0 0 1px #ff9696 outline
  • Arabic letters remain visually connected underneath the cursor
  • Letter inside cursor div is always transparent (partial: true) to avoid covering the actual text

2. DOM-Based Width Measurement

  • Use browser's Range.getBoundingClientRect() to measure actual rendered character width
  • Captures the true width after Arabic text shaping is applied by the browser
  • Works correctly for all contextual forms (isolated/initial/medial/final)
  • Saves original DOM position before traversal to ensure accurate measurement

3. Smart Newline Handling

  • Narrow cursor (15% of font size) for newline characters
  • In normal mode, auto-adjust cursor from end-of-line newline to last real character
  • Preserve cursor on empty lines (consecutive newlines)

Technical Changes

  • Added width property to Piece class for explicit width control
  • Apply measured width via elt.style.width in adjust() method
  • Save original domAtPos before DOM traversal for accurate measurement
  • Use Range API to measure individual character width from text nodes
  • Force transparent letter rendering to avoid covering underlying text
  • Detect and handle newline positioning in normal mode

Testing

Tested with Arabic text in various scenarios:

  • Connected characters in middle of words (ـنـ, ـكـ, etc.)
  • Characters at beginning/end of words
  • Mixed Arabic and English text
  • End of line positioning
  • Empty lines
  • Mouse click positioning vs keyboard navigation ($, h, l)

All cursor positioning now matches standard Vim behavior while correctly handling Arabic character shaping.

Impact

This fixes a major usability issue for Arabic language users, making the Vim mode cursor work correctly with Arabic's connected writing system. The solution properly handles complex text shaping without breaking visual character connections.

diraneyya avatar Nov 08 '25 21:11 diraneyya