Skip to content

fix(ink): sync native cursor for CJK IME and optimize frame rendering#2297

Open
HUQIANTAO wants to merge 1 commit into
esengine:mainfrom
HUQIANTAO:fix/ime-cursor-sync
Open

fix(ink): sync native cursor for CJK IME and optimize frame rendering#2297
HUQIANTAO wants to merge 1 commit into
esengine:mainfrom
HUQIANTAO:fix/ime-cursor-sync

Conversation

@HUQIANTAO
Copy link
Copy Markdown
Contributor

@HUQIANTAO HUQIANTAO commented May 29, 2026

Problem

CJK IME candidate popups appeared at wrong position (top-left) because the native terminal cursor was not synced to the visual input position. The custom ▌ cursor character also animated left-to-right during IME composition because each keystroke triggered a separate re-render.

Solution

Cursor sync

  • Export useDeclaredCursor hook from Ink and use it in PromptInput to park the native cursor at the visual input position — fixes IME popup alignment
  • Skip redundant cursor declaration updates when position is unchanged (prevents jitter during IME preedit commit)
  • Use native terminal cursor instead of custom ▌ character

Frame rendering optimization

  • Merge cursorMove + stdout patches and consecutive stdout patches in the optimizer — reduces per-cell rendering
  • Always send BSU/ESU in inline mode for atomic frame rendering
  • Batch rapid input (IME pinyin + committed CJK) via setTimeout(0) so multiple keystrokes coalesce into a single re-render — the cursor jumps directly to the final position

Files changed

  • packages/ink/src/components/App.tsx — stop hiding native cursor
  • packages/ink/src/hooks/use-declared-cursor.ts — add position-comparison guard
  • packages/ink/src/index.ts — export useDeclaredCursor
  • packages/ink/src/ink.tsx — always send BSU/ESU in inline mode
  • packages/ink/src/optimizer.ts — merge consecutive stdout patches
  • packages/ink/src/terminal.ts — import cursorPosition
  • src/cli/ui/PromptInput.tsx — cursor sync + input batching

@HUQIANTAO HUQIANTAO force-pushed the fix/ime-cursor-sync branch 2 times, most recently from 03576d9 to ea21c20 Compare May 29, 2026 15:05
@HUQIANTAO HUQIANTAO marked this pull request as draft May 29, 2026 15:45
@HUQIANTAO HUQIANTAO force-pushed the fix/ime-cursor-sync branch 2 times, most recently from a6405ab to e41c69c Compare May 29, 2026 16:30
@HUQIANTAO HUQIANTAO changed the title fix(ink): sync terminal cursor position for IME preedit alignment fix(ink): sync native cursor for CJK IME and optimize frame rendering May 29, 2026
@HUQIANTAO HUQIANTAO marked this pull request as ready for review May 29, 2026 16:31
Problem:
- CJK IME candidate popups appeared at wrong position (top-left) because
  the native terminal cursor was not synced to the visual input position
- Custom ▌ cursor character animated left-to-right during IME composition
  because each keystroke triggered a separate re-render
- Per-cell diff patches caused visible cursor movement on terminals without
  DEC 2026 (synchronized output) support

Solution:
- Export useDeclaredCursor hook from Ink and use it in PromptInput to park
  the native cursor at the visual input position (fixes IME popup alignment)
- Skip redundant cursor declaration updates when position is unchanged
  (prevents jitter during IME preedit commit)
- Optimize diff output: merge cursorMove+stdout patches and consecutive
  stdout patches in the optimizer (reduces per-cell rendering)
- Always send BSU/ESU in inline mode for atomic frame rendering
- Use native terminal cursor instead of custom ▌ character
- Batch rapid input (IME pinyin + committed CJK) via setTimeout(0) so
  multiple keystrokes coalesce into a single re-render — the cursor jumps
  directly to the final position instead of moving per-character
@HUQIANTAO HUQIANTAO force-pushed the fix/ime-cursor-sync branch from e41c69c to caf058f Compare May 29, 2026 16:33
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