ncurses 6.1にアップデートしたらatopなどのレイアウトが崩れる問題には環境変数TERMを変えれば良いことがわかりました,エスケープシーケンスrepが原因でした

要約

シェルの設定に

export TERM=gnome-256color

と書けば解決.

問題

ncursesが6.1にアップデートしてから,システム監視ツールのatopのレイアウトが崩れるという問題が発生していました.

I upgrade to ncurses 6.1, atop layout broken. · Issue #25 · Atoptool/atop

環境に関する情報提供もありましたし,今回調査してバグ修正を行ってみようとしました.

issueに寄せられたコメントによると,TERM環境変数によって動作が変わるようです.

TERMに使えるメジャーな環境変数はtoeコマンドで取得できます.

2018-06-11T15:13:26 ncaq@strawberry/pts/6(0) ~/Desktop/LilyTerm
% toe
screen          VT 100/ANSI X3.64 virtual terminal
screen-256color GNU Screen with 256 colors
xterm           xterm terminal emulator (X Window System)
xterm-color     generic color xterm
xterm-256color  xterm with 256 colors
ansi            ansi/pc-term compatible with color
dumb            80-column dumb tty
linux           linux console
rxvt            rxvt terminal emulator (X Window System)
rxvt-unicode    rxvt-unicode terminal (X Window System)
vt52            dec vt52
vt100           dec vt100 (w/advanced video)
vt102           dec vt102
vt220           dec vt220

崩れるものと崩れないものの調査

まずいろいろなTERMを試してみて,崩れるものと崩れないものを分類してみることにしました.

崩れなかった

  • screen
  • screen-256color
  • xterm-color
  • linux
  • rvxt
  • rxvt-unicode
  • vt100
  • vt102
  • vt220

  • gnome
  • gnome-256color

崩れた

  • xterm
  • xterm-256color
  • ansi

論外

  • dumb
  • vt52

崩れる条件の設定項目を探しました

を見て,崩れたxtermとxterm-colorの間で両方出力して,崩れたxtermの内容を二分探索的にxterm-colorに置換していきました.

そうすると項目rep=%p1%c\E[%p2%{1}%-%db,が書かれている場合はatopが崩れることがわかりました.

ncursesのソースコードでどのように生成されているか

ncursesのソースコードを読んでみたところ,misc/terminfo.srcxterm-newuse=ansi+repが指定されているのが生成の元凶らしいです.

6.1のアナウンスでxterm-newにrepを追加したと書かれていますね.

add rep to xterm-new, available since late 1996.

Announcing ncurses 6.1

repとは一体何なのか

terminfo(5) manページによるとrepは文字を繰り返すらしいです.

繰り返す…?つまりループ構文ですかね…?しかしそれがカスタム出来るというのは一体どういうことなのでしょう.

terminfoを参考にrepを使うプログラムを書いてみましょう.

ncursesのソースコードを読んで理解しようとしたけれどものすごい難しい.サンプルコードであるtparm(repeat_char, 'x', 5)を打ち込んでも文字が全く増殖しない…

以下のコードを実行しても文字が増えなくて悩んでいました.

#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>
#include <term.h>

int main() {
  setupterm(NULL, fileno(stdout), NULL);
  putp(tparm(repeat_char, 'x', 5));
  return 0;
}

何もわからないのでncursesをビルドしてデバッグシンボル付きのものをGCCのスタティックリンクの順番は大事 – ブーログを教えて貰って,start-groupでリンクしてgdbでたどってみることにしました.

かれこれソースコードを眺めること3時間.ふとKonsoleではこの問題は解決したということを思い出して,このプログラムをKonsoleで実行してみることにしました.そうしたら文字が増えました.LilyTerm, というかvteのこのバージョンがrepの形式に対応していなかったということのようですね.

xを5回繰り返すrepをtinfoが解凍したらエスケープシーケンスはxESC[4bになります.

KonsoleによるとREPはStandard ECMA-48の8.3.103に定義されているようですね.Konsoleのソースによるとbでトークンが終わる場合REPになって,前の数値が追加する数になるようですね.そんな定義PDFの何処にも見つからないんですけど何処に書いているんでしょうか…

解決法

解決法は原因を調べるずっと前からわかっていて,

export TERM=gnome-256color

と書くだけです.これでrepの設定が消えてncursesは正常に動くようになります.

lilytermの設定で

emulate_term = gnome-256color

とか書けば良いかと思いましたがこれはダメで,termcapを見に行くのでterminfoを見に行きません.

LilyTerm側で解決する方法が思いつかなかったので,とりあえず調査内容を関連issueに書き込んでおきました.

Default to TERM=xterm-256color · Issue #127 · Tetralet/LilyTerm

ひとまずzsh側で対策を取ることが出来てしまいましたが,根本的な解決には至りませんでした…LilyTermのvteのバージョンを上げれば良いのでしょうか?Konsoleはrepに対応することで対策したようですね.これで休日使い切ってしまい意欲も使い切ってしまってこれ以上調べる気になれません.今日はここまでです.

エスケープシーケンスrepに何の意味があるんでしょうか

同じ文字を追加するエスケープシーケンスの存在価値がわからない.アプリケーション側で出力する文字を増やせば良いじゃないですか…データ通信量節約にしても数文字節約することに価値を感じません.

このエントリーをはてなブックマークに追加 fb-like g-plusone pocket