mltermのterminfoがおかしかった件

解決済。

何度か失敗したので、必要な手順だけ読みたければ概要まとめだけ参照。

概要

Zsh - ArchWikiを参考に以下のようなコードを書いたのだが、これが何故かmltermで動かない。

        typeset -A key
key[Home]=${terminfo[khome]}
key[End]=${terminfo[kend]}
[[ -n ${key[Home]}        ]] && bindkey "${key[Home]}"      beginning-of-line
[[ -n ${key[End]}         ]] && bindkey "${key[End]}"       end-of-line
      
~/.zshrc (抜粋)

具体的には、HomeキーやEndキーでの挙動がおかしくなる。 どうせterminfoが合っていないんだろうと思ったらその通りだった。

mltermのソースコードと一緒に配られているterminfoのソースを使おうにも、それも駄目だった。

状況把握

        $ printf '%q' "${terminfo[khome]}"
$'\033'OH
$ printf '%q' "(ここでCtrlvHome)"
$'\033'\[H

      
terminal

こんな感じの方法でHomeキーを使ったときのシーケンスと違うのがわかるので、どうにかしよう。

調査

何処からかmlterm-256colorのterminfoが導入されているようなので、それを把握する。

        $ infocmp mlterm-256color | head -2
#       Reconstructed via infocmp from file: /usr/share/terminfo/m/mlterm-256color
mlterm-256color|mlterm 3.0 with xterm 256-colors,

      
terminal

ファイルパスがわかったので、どのパッケージがそのファイルを導入したのか調べる。 gentoo linux ならqfileコマンドを使う。

        $ qfile /usr/share/terminfo/m/mlterm-256color
sys-libs/ncurses (/usr/share/terminfo/m/mlterm-256color)
$ ncurses6-config --version
6.0.20150808

      
terminal

ncurses-6.0 のファイルが古いのだということがわかった。

たぶん昔ncursesに追加されてから更新されていなかったのだろう。

mltermのバージョンを見てみる。

        $ mlterm --version
mlterm version 3.5.0

      
terminal

ソースコードを落とすなりしてChangeLogでsequence\x1bといったパターンで検索し確認すると、2012-09-04に以下のような変更があった。

- Following key sequences are changed.
  XK_BackSpace: \x7f -> \x08
  XK_Home:   \x1bOH -> \x1b[H
  XK_End:    \x1bOF -> \x1b[F
  XK_F1:     \x1b[11~ -> \x1bOP
  XK_F2:     \x1b[12~ -> \x1bOQ
  XK_F3:     \x1b[13~ -> \x1bOR
	XK_F4:     \x1b[14~ -> \x1bOS
ChangeLog (抜粋)

これに追従できていなかったのだろう。

対処

本家ファイルからして古かった

mlterm本家のterminfoをユーザーローカルで導入すればいいと、この時は思っていたのだ。

現時点(2015-11-18)で最新の、mlterm-3.6.0のソースを落とす。 ChangeLogを確認したところ、前述のもの以降でこれといったterminfoの変更は無さそうなので、バージョン違いは気にせず新しいやつを使ってしまうことにしよう。

展開したソースのdoc/term/mlterm.tiがterminfoのソースだ。

まあ念のためと思って中身を確認するじゃん?

          $ grep khome doc/term/mlterm.ti
        kfnd=\E[1~, khome=\EOH, kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~,

        
terminal

なんかもう、ダメダメだ。 ncurses、お前は悪くなかったんや……

自力で編集

仕方ないので、これをベースに自分でシーケンスの変更を適用していく。

以下mlterm-3.6.0.tiは、mltermのdoc/term/mlterm.tiをどこかにコピーしてきたものとする。

          $ sed \
    -e '1s/mlterm\|/mlterm|mlterm-256color|/' \
    -e 's/khome=\\EOH,/khome=\\E[H,/' \
    -e 's/kend=\\EOF,/kend=\\E[F,/' \
    -e 's/kf1=\\E\[11~,/kf1=\\EOP,/' \
    -e 's/kf2=\\E\[12~,/kf2=\\EOQ,/' \
    -e 's/kf3=\\E\[13~,/kf3=\\EOR,/' \
    -e 's/kf4=\\E\[14~,/kf4=\\EOS,/' \
    -i mlterm-3.6.0.ti

        
terminal

どうにも泥臭くて好きではないが、こんなの実行するのは一度きりなのでこれでいいだろう。

適用した変更は2種類。 シーケンスの変更の反映と、mlterm-256colorへの対応だ。

mlterm-256colorへの対応であるが、公式のソースがmlterm向けに記述されているため、TERM環境変数がmlterm-256colorの状態でもこれを適用してほしいのであれば、その指定も追加する必要がある。 その変更が-e '1s/mlterm\|/mlterm|mlterm-256color|/'だ。

sed-iオプションは、入力ファイルをそのまま置換結果で上書きしてくれるので、これでmlterm-3.6.0.tiは正しくmltermのシーケンスを解釈するterminfoのソースファイルとなった。

これをコンパイルし、~/.terminfo/m/mlterm-256colorというファイルとして置いてやればよい。

terminfoのソースのコンパイル

これといって特筆することもない。 本当にコンパイルするだけだ。

          $ ls ~/.terminfo
ls: cannot access /home/larry/.terminfo: No such file or directory
$ tic mlterm-3.6.0.ti
$ ls -l ~/.terminfo/m/
total 8
-rw-r--r-- 1 larry larry 1990 2015-11-18 13:24 mlterm
lrwxrwxrwx 1 larry larry    6 2015-11-18 13:24 mlterm-256color -> mlterm

        
terminal

配置先のディレクトリがなくてもticは勝手にディレクトリを作ってくれるので、 頭を空っぽにして実行すればいい。

これにて問題は解決した...と思うじゃん?

解決

残念ながらこの状態だと、tmuxが256色出してくれない。

256色が正しく表示されることが期待されていた。
期待していた結果
実際には、256色どころか16色さえ正しく表示されていない。
mlterm公式のterminfoをベースにした結果

つらい。

原因を探ったところ、setabsetafの指定が問題であることがわかった。

	setab=\E[4%p1%dm,
	setaf=\E[3%p1%dm,
tmuxが256色出さないterminfo (mlterm-3.6.0 公式)
	setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
	setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
tmuxが256色出すterminfo (ncurses-6.0 同梱)

結局、ncursesの方が正しかったらしい。 terminfo.src (colored) for NCURSESを見ると、mlterm3の項目のコメントに以下のようにあった。

# Tested mlterm 3.2.2:
# mlterm 3.x has made changes, but they are not reflected in the included
# mlterm.ti; this entry is based on testing with tack and vttest -TD
terminfo.srcのコメント (抜粋)

そういうわけで、折角一部キー以外問題ないものがあるのだから、それを使おう。

mlterm|mlterm-256color|multi lingual terminal emulator,
	khome=\E[H,
	kend=\E[F,
	kf1=\EOP,
	kf2=\EOQ,
	kf3=\EOR,
	kf4=\EOS,
	use=mlterm-256color,
mlterm用terminfoソース完成版(1)

use=で他のterminfoを参照できる。 ここではncursesが入れてくれたmlterm-256colorを参照する。 循環参照っぽさがあるが、とりあえず動いたので良しとしよう。 心配なら以下のようにしてやれば同じ結果が得られるだろう。

        $ infocmp -A /usr/share/terminfo mlterm-256color \
    | sed \
        -e 's/khome=\\EOH,/khome=\\E[H,/' \
        -e 's/kend=\\EOF,/kend=\\E[F,/' \
        -e 's/kf1=\\E\[11~,/kf1=\\EOP,/' \
        -e 's/kf2=\\E\[12~,/kf2=\\EOQ,/' \
        -e 's/kf3=\\E\[13~,/kf3=\\EOR,/' \
        -e 's/kf4=\\E\[14~,/kf4=\\EOS,/' \
	>mlterm-256color.ti
$ tic mlterm-256color.ti

      
mlterm用terminfoソース(2)の作り方

これでやっと意図した結果が得られた(何を隠そう、先の「期待される結果」の画像はこのファイルを使ったものだ)。

まとめ

問題

  • ncurses6に含まれているmlterm-256colorのterminfoは古く、一部キーが正常に認識されない原因になる。
  • かといってmltermのソースコードに含まれているものを使おうにも、これもまた古く、256色が正しく扱えないことがある。
  • よって、ncurses6mlterm-256colorのファイルをベースに、一部キーのシーケンスを変更し、これを優先的に使うことにした。
    • 古いバージョンから変更されたシーケンスは、mltermのChangeLogに記録されているため追跡できた。

手順

mlterm-256colorのterminfoのファイルがインストールされているか確認する。 このファイルがncursesによるものであるのが理想的だ。

          $ ncurses6-config --version
6.0.20150808
$ infocmp -D
/home/larry/.terminfo
/etc/terminfo
/usr/share/terminfo
$ ls /usr/share/terminfo/m/mlterm-256color
/usr/share/terminfo/m/mlterm-256color

        
terminal

ファイルがあったら、これを以下のコマンドで編集する。

          $ infocmp -A /usr/share/terminfo mlterm-256color \
  | sed \
    -e 's/khome=\\EOH,/khome=\\E[H,/' \
    -e 's/kend=\\EOF,/kend=\\E[F,/' \
    -e 's/kf1=\\E\[11~,/kf1=\\EOP,/' \
    -e 's/kf2=\\E\[12~,/kf2=\\EOQ,/' \
    -e 's/kf3=\\E\[13~,/kf3=\\EOR,/' \
    -e 's/kf4=\\E\[14~,/kf4=\\EOS,/' \
  >mlterm-256color.ti

        
terminal

このファイルをコンパイルし、インストールする。 このときroot権限だとシステムディレクトリに入れてしまう可能性があるので注意。

          $ tic mlterm-256color.ti

        
terminal

これでおしまい。