
2026/03/22 18:31
**ターミナルで複雑なスクリプトを描画し、OSC 66 を利用する**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
現代のターミナルエミュレータは、1970年代のビデオ端末から継承された「固定幅文字セル」の単純なグリッドに依存しており、1つのUnicodeコードポイントを1つのセルにマッピングします。この設計では、アラビア語やインド系スクリプト(マレーラム語、タミル語、デーヴァナーガリー文字など)のような複雑な文字体系が必要とする文脈的整形・合字・非線形のグリフ融合を受け入れられず、文字が乱れたり重なったりします。
モノスペースフォントはすべてのグリフに対して水平幅を等しいものとして想定するため、単一コードポイントごとに0、1、または2を返す標準関数
wcwidth() は、複数コードポイントからなるグラフェムクラスターには不十分であり、カーソルのずれを引き起こします。Kitty(および Foot)は OSC 66 を実装することでこの問題の一部に対処しています。OSC 66 はアプリケーションが各グラフェムクラスターの正確なピクセル幅を宣言できるエスケープシーケンスです。Rust の CLI ツール
osc66 は HarfBuzz でテキストを整形し、グリフをクラスターにまとめ、参照進行距離に対するセル幅を計算し、Kitty で可読性を向上させる OSC 66 シーケンスを発行する方法を示しています。ただし、OSC 66 はセル単位の粒度しか指定できず、小数点以下のセルは四捨五入されます。これにより目立つギャップや切り取られたグリフ(Key point 8)が生じます。現在、OSC 66 は Kitty と Foot のみでサポートされており、Ghostty、tmux、Neovim に拡張する議論が進行中です。TCSS ワーキンググループは「ターミナルクラスター」モデルという長期的な提案をしており、文字列レベルで幅を測定し、各クラスターに明示的なセルメトリックを割り当て、コピー/ペーストや BiDi 処理のための論理順序を保持します(Key point 10)。もう一つの提案である Mode 2027 は完全なグラフェムクラスタリングサポートも求めていますが、最近はほとんど活動が見られません。
要するに、多言語コマンドラインワークフローを使用しているユーザーは今日 OSC 66 の恩恵を受けることができ、将来的には標準化されたクラスターモデルの導入でさらに利点があります。一方、Kitty、Foot、tmux、Neovim などのターミナル開発者は、プラットフォーム間で複雑な文字体系を完全にサポートするためにこれらのプロトコルを採用しなければなりません。
本文
私はプログラマとして、ほとんどの時間をKitty のようなターミナルアプリで過ごしています。
コード編集には Neovim を、CLI ベースの AI エージェントは同じくターミナル上で動かします。2026 年現在でも最大の痛手は、インド語族やアラビア文字のような複雑脚本を描画できるターミナルが存在しないことです。この制限は、私の仕事の大半が言語処理に関わるため、非常に重要です。
この記事では、未だ解決していない理由について簡潔にまとめます。
- 文字セルグリッドモデル
- 幅測定
- テキストシェーピングとレンダリングの区別
また、進行中の取り組みや最近作成した小さなツール(osc66)が示す解決策への道筋についても触れます。
ターミナルで複雑脚本が描画しにくい理由
現代のターミナルエミュレータ(GNOME Terminal、Kitty、Ghostty)は、1970 年代のビデオディスプレイ端末のハードウェア制約を再現しています。
「文字セルグリッド」―行と列からなるマトリクスで、各交点に正確に 1 つのグラフィック文字が配置されるという仮定を前提にしています。テキストユーザーインタフェースはこの仮定に基づいてレイアウトやカーソル位置を計算します。
「1 文字 → 1 セル」のマッピング
このマッピングは、アラビア語やインド語族(マレーラム・タミル・デーヴァナーガリーなど)のような複雑な書字体系と根本的に不整合です。これらの脚本には次の特徴があります。
- 文脈依存の形態変化
- 文字の再配置(リオーダリング)
- 非線形ギャフ融合
アラビア語は右から左へ書かれ、モノスペースフォントはすべての文字が同じ横幅を占めるように設計されているため、これらの脚本には対応できません。例えばマレーラムのリガチャは 1 つの視覚単位に折りたたまれるか、複数セルに広がる必要がありますが、硬直したグリッドに強制的に収めると文字が混乱・重なります。
2025 年時点でのターミナルエミュレータ:現状
幅予測
従来、ターミナルは
wcwidth() 関数を使って文字幅(0,1,2)を決定してきました。これは単一 Unicode コードポイントに対してのみ有効で、複雑脚本では 1 つのグラフェムクラスターが複数コードポイントから構成されるため失敗します。
Kitty は
wcwidth() を使用せず、マレーラムのリガチャ സന്തോഷ് が「3 セル」を必要と判断し、それぞれのリガチャを 3 セルに収めようとして入力位置がずれたりビジュアルが崩れるという現象が発生します(スクリーンショット参照)。
シェーピング vs. レンダリング
グラフィカル環境では シェーピング(Unicode コードポイントをギャフ ID とピクセル位置に変換)→ レンダリング(実際の描画)の流れが標準です。
ほとんどのターミナルはシェーピングを省略し、コードポイント単位で描画します。そのため正確なカーソル位置を必要とするアプリケーションでは不具合が生じます。
Kitty のテキストサイズプロトコル
Kitty(Kovid Goyal 氏開発)は「text‑sizing protocol」を導入し、プログラム側で文字が占めるセル数を明示的に制御できるようにしました。これにより
wcwidth() をバイパスし、複雑脚本の描画崩れを防げます。
OSC 66 フォーマット
ESC ] 66 ; <key>=<value>[:<key>=<value>...] ; <text> BEL
- メタデータ:コロン区切りで key=value ペア
- テキストペイロード:UTF‑8(最大 4096 バイト)
メタデータキー
| Key | 意味 |
|---|---|
| スケール係数 (1–7)。文字は セル幅、 セル高さで描画される。 |
| スケール済みセル幅 (0–7; 0 は Unicode から自動計算)。 |
| 分数スケールの分子/分母 (0–15)。 |
| 分数スケール時の垂直/水平揃え(0–2)。 |
クライアントは正しい
w を提供します。私が書いた osc66 は、形状付け済みインド語テキストに対してこれら値を計算します。
osc66 ツール
osc66 は Rust で作られた CLI ユーティリティです。
- 標準入力からテキスト読み込み
- HarfBuzz を使って文字列をシェーピングし、クラスターごとにギャフをグループ化
- ASCII の基準文字 (
) に対するアドバンスで各クラスターの幅を算出0 - 各クラスターについて OSC 66 エスケープシーケンスを出力
ツールは fontconfig で適切なフォントを検索し、HarfBuzz で読み込みます。基準アドバンス(1 セル相当)は
0 をシェーピングした結果から取得します。入力行ごとに:
cells = ceil(cluster_advance / ref_advance) 0–7 の範囲へクリップ
ゼロ幅クラスター(virama、ZWJ)はスキップ。
Kitty で osc66 を適用したマレーラムの描画スクリーンショットは可読性が格段に向上していますが、フラクショナルセルの欠如によりギャップが残ります。さまざまな丸め戦略を試しましたが、グリッドは連続的な脚本に対して離散数学を強いるため完全解決には至りません。
受容と制限
- サポート済み:Kitty, Foot
- 進行中:Ghostty(PR 中)、Neovim(issue 32539)
注意点:
- tmux を Kitty 内で使用するとレンダリングが上書きされる。
- osc66 を適用後は、Kitty のフォント設定をツールが使うフォントに合わせる必要がある。
標準化と未来
TCSS ワーキンググループ
2023 年、Unicode 技術委員会は Terminal Complex Script Support (TCSS) WG を設立しました。Microsoft, Apple などの代表者と主要ターミナルプロジェクトが参加しています。目的は、固定幅グリッド上でシェープド・双方向・ワイドテキストを扱う新しい標準です。
主な提案:
- Terminal Cluster model:コードポイントではなくクラスター単位で測定。
- String‑based measurement:ターミナルが文字列全体を解析して幅決定。
- Explicit metrics:各スクリーンバッファクラスターにセル数メトリックを付与。
- Logical ordering:内部表現は論理順(入力順)を保ち、コピー・ペーストや検索を正しく行えるように。
Mode 2027
Contour の作者が提案した「Mode 2027」はターミナルで完全なグラフェムクラスタリングを有効化する仕組みです。最近の活動は少なく、Ghostty 1.3.0 は改善を主張していますが、マレーラムやインド語脚本にはまだ対応していません。
結論
現状は断片的で、機能したプロトコルを持つターミナル(Kitty)と議論中の他数台、標準化努力も並行しています。進展はあるものの遅々としており、マレーラムやその他インド語脚本を書き込むターミナルユーザーにとっては、osc66 のような部分的サポートでも「何もしないよりはるかに良い」改善です。
勢いがつくことを願っています。読んでいただきありがとうございました!
さらに読む
- The TTY demystified
- What happens when you press a key in your terminal?
- A history of the tty
- Understanding ASCII (and terminals)
- Comprehensive keyboard handling in terminals
- Fix Keyboard Input on Terminals – Please
- Grapheme Clusters and Terminal Emulators
- State of the Terminal Control Sequences – Ghostty documentation