-
-
Notifications
You must be signed in to change notification settings - Fork 777
feat: add IME cursor positioning support #803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat: add IME cursor positioning support #803
Conversation
Add IME (Input Method Editor) cursor positioning support to enable proper placement of IME candidate windows during CJK text input. Key features: - New enableImeCursor option in render() (default: false, opt-in) - Private Use Area character (U+E000) as invisible cursor marker - Automatic cursor positioning using ANSI escape sequences - Cursor save/restore to prevent content jumping - Measure text without marker for accurate width calculation When enabled: - Terminal cursor moves to actual input position - IME candidate windows appear at correct location - Cursor visibility controlled by log-update Implementation: - src/cursor-marker.ts: Cursor marker constant and detection - src/ink.tsx: Add enableImeCursor option - src/log-update.ts: Cursor positioning logic with save/restore - src/components/App.tsx: Conditional cursor visibility control - src/render.ts: RenderOptions type extension - src/measure-text.ts: Strip marker before measuring 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Interactive demo showcasing IME cursor positioning with multi-line text editing. Features: - Multi-line text editing with automatic line wrapping at 80 cells - Full-width character support (CJK = 2 cells, ASCII = 1 cell) - Arrow key navigation (up/down/left/right) - Visual cursor display with position information - Environment variable to toggle IME cursor (ENABLE_IME_CURSOR) - Bilingual demo text (Japanese with English translation) Usage: # With IME cursor positioning (default) npx tsx examples/multiline-edit-demo/multiline-edit-demo.tsx # Without IME cursor positioning (for comparison) ENABLE_IME_CURSOR=false npx tsx examples/multiline-edit-demo/multiline-edit-demo.tsx Tests included: - Standalone test script for individual test cases - AVA integration tests with node-pty for automated testing - 15 test cases covering edge cases (empty lines, wrapping, mixed-width chars) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Replace U+E000 (Private Use Area) cursor marker with SGR 999 (undefined ANSI escape sequence). This eliminates the need for border alignment workarounds by ensuring the marker is automatically excluded from width calculations. Changes: - cursor-marker.ts: Change CURSOR_MARKER from '\uE000' to '\u001B[999m' - log-update.ts: Remove 37-line border alignment hack - measure-text.ts: Remove explicit marker removal (auto-excluded now) - ink.tsx: Revert unrelated changes The SGR 999 sequence: - Is recognized by ansi-tokenize as an ANSI token - Automatically excluded by widestLine() and stringWidth() - Does not interfere with existing text styles - Will never be standardized (999 is out of valid range) Result: -41 lines, cleaner code, proper fix for border misalignment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
After early return for !showCursor case, all subsequent code is guaranteed to have showCursor === true. Remove redundant conditions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
You will have to find some humans to review this code. I don't have time to review vibe coded PRs. Claude Code is not known for producing bug-free code, especially not for complex things like this. I also recommend getting ChatGPT 5 Thinking (with extended thinking) to review this. It's much smarter. |
|
Thank you for your reply. This is quite a complex change, but it’s an important one for people who need to use an IME. I realize it’s difficult for those who don’t rely on IME to fully understand the importance, so I’ve been thinking for a while about how best to explain it. In the end, I decided to go ahead and open the PR so you could take a look. Do you think there’s a possibility that this kind of approach could be accepted? |
Summary
Implements IME (Input Method Editor) cursor positioning to fix the issue where IME candidate windows appear at the end of output instead of at the actual input position when using CJK input methods.
Problem
When using Ink applications with CJK input methods (Japanese, Chinese, Korean), the IME candidate window appears at the wrong location because the terminal cursor stays at the end of the output instead of the actual input position.
Solution
This PR adds an
enableImeCursoroption that positions the terminal cursor at the actual input location using:Cursor marker detection (
src/cursor-marker.ts)Cursor positioning (
src/log-update.ts)API addition (
src/ink.tsx,src/render.ts,src/components/App.tsx)enableImeCursoroption (default:falsefor backward compatibility)Usage
To enable IME cursor positioning in your Ink application:
1. Enable the option when rendering
2. Insert cursor marker at the input position
The
CURSOR_MARKERshould be placed immediately before the visual cursor position. The terminal cursor will be positioned at this location.Demo Application
Interactive demo showing IME cursor positioning with multi-line text editing:
Key Features
Test Plan
Run the demo application and verify:
🤖 Generated with Claude Code