曖昧幅文字を全角にすると壊れる dpkg のダイアログについて
曖昧幅文字を全角にする と dpkg の設定ダイアログが壊れる、という話。
$ sudo dpkg-reconfigure keybooard-configuration
などとすると出てきて、インストール後にキーボード設定を変えさせてくれる、 あれのことだ。ほんらい上のコマンドはこのような画面を映し出すべきである。
glibc のロケールを変更して曖昧幅文字を全角にしていると次のようになるだ
ろう。(端末エミュレーターは rxvt-unicode
なので、自動的にロケールに登
録されている文字幅に従って描画される)
ウィンドウの枠やスクロールバーを描画している特殊文字の幅が全角になった 結果、表示がくずれていることがわかる。
ロケールの設定によって幅が変わることから、これらの文字は Unicode だと 推察できるが、そもそも Unicode 以前は端末はどのように罫線を表示してい たのだろうか?
代替文字集合
ASCII は罫線文字を含まない。VT100の時代から、端末は代替文字集合 (alternate character set)に切り替えることでフォームを描画していた。
例えば VT100 の場合は ^N で代替文字集合に切り替わり、^O で ASCII モー ドに戻る。代替文字モードの間は ASCII の小文字のアルファベットが罫線文 字に対応する。
terminfo データベースは種々の端末の差異を吸収するために、個々のエスケー プシーケンスに名前(ケーパビリティ)を付けて管理している。
文字集合の切り替えには smacs
と rmacs
が使われ、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 への変換を無効 にしてみたもの。