曖昧幅文字を全角にする と dpkg の設定ダイアログが壊れる、という話。

$ sudo dpkg-reconfigure keybooard-configuration

などとすると出てきて、インストール後にキーボード設定を変えさせてくれる、 あれのことだ。ほんらい上のコマンドはこのような画面を映し出すべきである。

glibc のロケールを変更して曖昧幅文字を全角にしていると次のようになるだ ろう。(端末エミュレーターは rxvt-unicode なので、自動的にロケールに登 録されている文字幅に従って描画される)

ウィンドウの枠やスクロールバーを描画している特殊文字の幅が全角になった 結果、表示がくずれていることがわかる。

ロケールの設定によって幅が変わることから、これらの文字は Unicode だと 推察できるが、そもそも Unicode 以前は端末はどのように罫線を表示してい たのだろうか?

代替文字集合

ASCII は罫線文字を含まない。VT100の時代から、端末は代替文字集合 (alternate character set)に切り替えることでフォームを描画していた。

例えば VT100 の場合は ^N で代替文字集合に切り替わり、^O で ASCII モー ドに戻る。代替文字モードの間は ASCII の小文字のアルファベットが罫線文 字に対応する。

terminfo データベースは種々の端末の差異を吸収するために、個々のエスケー プシーケンスに名前(ケーパビリティ)を付けて管理している。

文字集合の切り替えには smacsrmacs が使われ、VT100 がサポートし ていた代替文字集合との対応表は acsc に格納されている。

ただし、現行のターミナルエミュレーターはそっくり VT100 の代替文字集合 をサポートしているので、acsc は

$ TERM=xterm infocmp | grep acsc
        acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,

のように同じ文字へのマップになっているだけである。このようなエミュレー ターでは、以下のコマンドラインで長方形が描画できるはずだ。

$ tput smacs; echo -e 'lqqqqqqqk\nx       x\nmqqqqqqqj'; tput rmacs

これらの罫線文字は恐らく表示できる全ての端末で、曖昧幅文字の解釈によら ず半角であろう。

dpkg の設定ダイアログ表示の仕組み

dpkg の設定ダイアログは whiptail というコマンドが描画しており、これは newt というツールキットを利用しており、このツールキットは slang ライブ ラリを使っている。

枠線を描画するのに使う罫線文字を実際に決定しているの slang だ。

Slang の挙動

Slang はロケールが UTF-8 を使用していると判断すると、代替文字集合の描 画要求を Unicode 文字に変換することがある。これはterminfo の情報が不適 切であったり、端末が代替文字集合をサポートしていない場合でもきちんとし た罫線文字を描画できる方法であるが、残念ながら Unicode の罫線文字は曖 昧幅なので、端末の解釈によって全角・半角のどちらでもありうる。

既存のソフトウェアは代替文字集合は半角であると(正しく)仮定しているので、 ウィンドウ枠の描画が乱れてしまうわけだ。

ただし、Slang は曖昧幅=全角の環境に無頓着なわけではなくて、 WCWIDTH_CJK_LEGACY という環境変数が yes ならば代替文字は ASCII にフォールバックする。

解決?

従って dpkg の設定ダイアログが乱れてしまう問題への対処は 「WCWIDTH_CJK_LEGACY=yes にせよ」というのが答えになる。

ただし、先に述べたように曖昧幅=全角の端末であっても、半角の罫線文字を 代替文字集合を用いて描画することは可能なので、ASCII にフォールバックす るよりは、terminfoに設定された代替文字集合を使って欲しいところだ。

おまけ:いくつかのスクリーンショット

曖昧幅=半角

Ubuntu 15 のデフォルト。

曖昧幅=全角

曖昧幅=全角、WCWIDTH_CJK_LEGACY=yes

曖昧幅=全角、WCWIDTH_CJK_LEGACY=yes、代替文字集合

slang のソースコードを変更して代替文字集合から Unicode への変換を無効 にしてみたもの。