Skip to content

Fix wide-character and input method text entry in the TUI - #10

Open
seungjuchoi wants to merge 3 commits into
raine:mainfrom
seungjuchoi:fix-wide-character-text-input
Open

Fix wide-character and input method text entry in the TUI#10
seungjuchoi wants to merge 3 commits into
raine:mainfrom
seungjuchoi:fix-wide-character-text-input

Conversation

@seungjuchoi

Copy link
Copy Markdown

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, 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 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_spans budgeted its scroll window in characters, the wrapped
editors split lines with a character-count splitter, and truncate_chars
shortened 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, plus
new 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_mode tests (detail_back_returns_from_epic_child_to_parent_detail
and clicking_detail_markdown_link_opens_browser) fail for me on an unmodified
main as well, so they look unrelated to this change.

seungju24.choi 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.
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