tmux の表示が ambiguous width characters で乱れるのを何とかする

tmux を 1.6 から 1.7 にしたらさらに表示が乱れるようになった気がする。きっと ambiguous width characters の幅の判断が日本語の実情に合っていないせいだろうが,1.6 から 1.7 の utf8.c の変更は,utf8_width_table[] の一部を #ifndef でかこむようになっただけで,あまり影響があるようには思えない。utf8.c 内の関数の使いかたが変わったのかな。まあ 1.6 からすでに乱れていたんだから,あまりそこを調べても意味がない。

それぞれの文字の幅を tmux は自分で計算しているが,きっとこの計算に問題がある。修正するには utf8.c の utf8_width_table をいじればいいんだろうけど,おなじことをこないだシステムの locale データに対してやったなあ。おなじことをまたしたくないので,以前の修正結果を利用すべく,文字の幅を wcwidth() を使って求めるように修正する。そもそもシステムがまともな文字の幅を返しアプリはみんなそれを使うというのが正しい姿だろうし。

utf8.c の最初でこうして:
+#define _XOPEN_SOURCE
+#include <locale.h>
+#include <wchar.h>
utf8_width() でこうする:
+       static int inited = 0;

        value = utf8_combine(utf8data);
+       if (!inited) {
+               setlocale(LC_CTYPE, "");
+               inited = 1;
+       }
+       return wcwidth(value);
これでまったく(かな?)表示が崩れなくなった。

ここの value(utf8_combine() の戻り値)は UTF-32 ないし UCS-4 であり,うちは wchar_t がおなじく UCS-4(__STDC_ISO_10646__ が #define されていて sizeof(wchar_t) が 4)なのでこれでいいが,そうでない環境なら iconv などで変換してから wcwidth() にわたす必要がある。

「ASCII は幅 1,それ以外はすべて 2」ならこうでもいいだろう:
        value = utf8_combine(utf8data);
+       return (value <= 0x7f) ? 1 : 2;
どんなやりかたでも,それぞれの文字の幅の解釈が tmux と端末とで一致していればいい。

tmux の修正をしていてハマったこと:修正前の tmux サーバが動いている状態で修正後の tmux クライアントを起動すると,クライアントも修正前の tmux に取って代わられてしまう。だから修正が反映されない。修正前のサーバを止めるか,tmux -L hoge などとしてソケットに別名を指定して(既定値は "default")あらたにサーバを起動すればいい。

::2012-10-20 {unix}

update : 2012/10/20 (Sat) 16:38:31