Skip to content

[BUG] Thai text rendering is broken in TUI — combining characters cause layout misalignment #21712

@kingits

Description

@kingits

Description

Thai text renders incorrectly in the OpenCode TUI. Characters appear garbled with misaligned combining characters (vowels, tone marks), broken layout, and text overlapping. The same Thai text displays correctly in the terminal outside of OpenCode.

Steps to Reproduce

  1. Open OpenCode TUI in any terminal (tested with Warp on macOS)
  2. Type or receive a response containing Thai text (e.g. สวัสดีครับ ทดสอบภาษาไทย)
  3. Observe garbled/misaligned Thai text rendering

Expected Behavior

Thai text should render correctly with proper positioning of:

  • Combining vowels above/below consonants (สระบน/ล่าง): ิ ี ึ ื ุ ู
  • Tone marks (วรรณยุกต์): ่ ้ ๊ ๋
  • Leading vowels (สระหน้า): เ แ โ ไ ใ
  • Compound characters:

Actual Behavior

Thai combining characters are mispositioned, causing:

  • Vowels and tone marks appearing in wrong positions
  • Text overlapping and layout breaking
  • Overall garbled/unreadable Thai output

Environment

  • OpenCode version: 1.4.1
  • OS: macOS (Darwin, Apple Silicon)
  • Terminal: Warp (Thai renders correctly outside of OpenCode TUI)
  • Locale: LANG=C.UTF-8, LC_CTYPE=UTF-8
  • Shell: zsh

Root Cause Analysis

Thai script uses Unicode combining characters extensively. The TUI likely miscalculates character widths because:

  1. Grapheme cluster width: Thai combining characters (tone marks, vowels above/below) have zero display width but are separate Unicode codepoints. Width calculation that sums individual codepoint widths produces incorrect results.
  2. Related issues in the ecosystem:

Workaround

Using opencode web (browser UI) displays Thai correctly, but loses access to terminal-dependent plugins (e.g. tmux integration).

Additional Context

Thai is not the only complex script affected — any script using combining characters (Devanagari, Arabic, etc.) likely has the same issue. A proper fix would use grapheme-cluster-aware width calculation (e.g., rivo/uniseg) instead of per-rune width lookup.

Metadata

Metadata

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)opentuiThis relates to changes in v1.0, now that opencode uses opentui

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions