Fix wide-character and input method text entry in the TUI - #10
Open
seungjuchoi wants to merge 3 commits into
Open
Fix wide-character and input method text entry in the TUI#10seungjuchoi wants to merge 3 commits into
seungjuchoi wants to merge 3 commits into
Conversation
added 3 commits
August 11, 2026 13:56
The TUI paints its own cursor cell and never reports a cursor position, so Ratatui hides the terminal cursor and leaves it wherever the buffer diff stopped writing. Input method editors draw in-progress composition at the terminal cursor, so Korean, Japanese, and Chinese preedit text appears at an unrelated cell instead of at the caret being typed into. Locate the painted caret in the rendered buffer by its cursor style and move the hidden terminal cursor there after every draw. Cells dimmed by a stacked dialog are skipped so only the active input qualifies, and the move is repeated after inline image emission because those writes reposition the cursor. The painted cursor remains the visible caret, so nothing about the rendered frame changes. Cover the reported position against the painted cell for narrow and wide characters.
Input rows counted their scroll budget in characters while the terminal allocates cells. A wide character occupies two cells, so CJK and emoji values rendered twice as wide as the field, overflowed the surrounding dialog, and pushed the caret off screen once the value passed half the available width. Wrapped editors split lines on the same character count and overflowed the same way. Budget the visible prefix, caret, and suffix in cells, dropping characters whole so a wide character never renders as half a cell. Replace the character-count line splitter with the existing cell-width splitter for the description editor and confirmation prompts, and share one segment lookup between the wrapped editors. Cover cell budgeting for clipped and unclipped rows, wide-character line splitting, and a long wide-character title scrolling within its dialog.
Task titles, project keys, dialog titles, and search results were shortened by character count while every caller passes a cell budget taken from the layout. Wide characters made those values render twice as wide as their column, so CJK text overflowed the sidebar, task rows, search results, and card titles. Truncate by display width everywhere and drop the character-count helper, its last remaining callers now covered by the width variant. Measure column card titles in cells too so wrapping matches what the terminal draws.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Typing Korean in the TUI misplaces the input method composition and, once the
value grows, pushes the caret off screen. Both come from the same root cause:
text layout is measured in characters, and the terminal cursor is never told
where the caret is.
Terminal cursor never follows the caret
The TUI paints its own cursor cell and never calls
set_cursor_position, soRatatui hides the terminal cursor and leaves it wherever the buffer diff
stopped writing. Input method editors draw in-progress composition at the
terminal cursor, so Korean, Japanese, and Chinese preedit text lands at an
unrelated cell — in the screenshot, at the far right of the row where a
placeholder had just been erased.
The painted caret is now located in the rendered buffer by its cursor style,
and the hidden terminal cursor is moved there after every draw. Nothing about
the rendered frame changes; the painted cursor is still the visible caret.
Character counts where the terminal counts cells
input_cursor_spansbudgeted its scroll window in characters, the wrappededitors split lines with a character-count splitter, and
truncate_charsshortened values that every caller sizes from a layout width. A wide character
takes two cells, so CJK values render twice as wide as the field: titles
overflow their dialog, the caret disappears past half the width, and sidebar
labels, task rows, search results, and column cards spill out of their
columns.
Each of those now measures cells, dropping characters whole so a wide
character never renders as half a cell.
Testing
cargo fmt,cargo clippy --all-targets, and the test suite are clean, plusnew coverage for cell budgeting, wide-character line splitting, and the
reported caret position matching the painted cell. Verified by hand on macOS
with a Korean input method: composition now appears at the caret, and long
Korean titles scroll inside the dialog.
Two
detail_modetests (detail_back_returns_from_epic_child_to_parent_detailand
clicking_detail_markdown_link_opens_browser) fail for me on an unmodifiedmainas well, so they look unrelated to this change.