Edited at

端末エミュレーションを知覚する - Trachetチュートリアル

More than 5 years have passed since last update.

trachet


はじめに

このポストでは、端末(VT互換端末)でおこる諸問題の診断、追跡を可能にするツール、Trachetの使い方をざっと説明してみようと思います。

じつのところ今回は第一・第二端末特性応答(DA1/DA2)の話を書こうとしていたのですが、やはり一般的にはあまり実体が知覚されていないものの話になってくるあたりからもうピンとこないどころか雲を掴むような印象になりがちで、つまり筆力の限界を感じざるを得なかったので、先にこれを紹介しておけばクエリ・応答シーケンスの話題をいくらか具体的なものとして感じてもらうことが可能なのではないか、と考えたのが、この話を書くきっかけです。


Trachetの概要

Trachetは特に、キーボードやマウス入力周りの不具合、描画周りがおかしくなる現象など、入出力を追跡・監視して対応する必要がある諸問題に対して、アプリケーションと端末の間の具体的な会話を見える化し、原因の究明とその解決を支援します。

また端末アプリケーションのほとんどはTTYデバイスとのI/Oでブロックするように書かれているため、「なんかおかしいことがおこったけど、はやすぎて何がどうなってるのかわからない(><)」といった状況で、アプリケーションをステップ実行することが可能になる、という効果もあります。

このツールが想定するユーザは、


  1. 端末または端末エミュレータ、ターミナルマルチプレクサなどの開発者

  2. 端末で動作するアプリケーションを書いている人

  3. 端末や端末アプリケーションでおこる諸問題の原因を追求し、完全解決を目指す人

などです。

3.で「完全解決を目指す人」と限定したのは、とってつけた対処療法もばかにできないし、むしろそちらのほうが生産性の観点で有用な場合が多いからです。

2.のアプリケーションを書いている人も、一般的な枠組み(terminfo/cursesなど)からはずれないように注意すればTrachetを必要とする状況はほとんど無いような気がします。しかし誤ってちょっとセンシティブな問題(歴史的経緯やおっさんたちの微妙なコンセンサスで物事が決まる領域)を踏み抜いてしまったときの無力感をいくらか解消できる局面もあるかもしれません。


インストール

Trachetが想定している動作環境は、各種Unix/Linux系OSです。

WindowsでもCygwinがあれば普通に動きます。

インストールはpipで入れる方法が簡単だと思います。

$ pip install trachet

とすると入ります。

pipが入っていない場合は、ez_setup.pyを実行してeasy_installをインストールしてから、

$ easy_install pip

としておきましょう。


準備と起動


  1. まず、デバッグターゲットとなる端末(左)のほかに、もうひとつトレース用の端末(右)を用意します。

    trachet_prepare


  2. つぎにトレース用の端末のデバイス名をttyコマンドで調べます。ここではデバイス名「/dev/ttys002」が得られました。

    trachet_get_tty


  3. 起動します。


もっとも単純な起動方法は、

$ trachet -o<デバイス名>

です。さきほどのデバイス名の例の場合は、

$ trachet -o/dev/ttys002

とします。

トレース用の端末に、ログっぽいものがいっぱい出てくれば成功です。おめでとうございます。

trachet_install_done


簡単な例

デバッグターゲットの端末(いまの例で言うと、白いほうの端末)で、

$ tput smkx

と、打ってみましょう。smkxが何かという話は、ここでは割愛します。tputが無いと言われてしまったら、ncursesをインストールしてみてください。

trachet_smkx

こうなりました。プロンプト「>>>」ではじまる行は端末への出力をあらわし、「<<<」ではじまる行はキー入力をあらわしています。

「tput smkx」が一文字づつエコーバック(入力が出力へそのままエコーされること)されている様子がわかりますね。

2文字目でBS(バックスペース)が呼ばれていったん行が書き直されているのは、zshのクセです。

改行(CR)を入力したあとは、拡張モード1番のDECCKMと、DECKPAMが呼ばれているようです。

この時点で、DECSET、DECCKM、DECKPAMというニーモニック名を得ることができました。

ニーモニックというのは、マシン語のあれとだいたい似たようなもので、便宜をはかるために端末シーケンスに名前をつけているだけです。

これらが何をやっているか、あとはぐぐるだけですね。

もうひとつ、別の例でやってみましょう。

$ tput u7

と打ちこみます。

trachet_u7

こうなりました。

DSR-CPR以降は、zshが出してるシーケンスですが、もっと下のほうをみると何か入力されているように見えます。

キーボードで何か入力したつもりはありません。なんでしょう。

実は、端末からアプリケーションへの応答でした。

今の例ではカーソル位置の問い合わせをやっていたのですが、このようにしてアプリケーションと端末は会話しているのだということを感じていただけたらいいなと思います。


ステップ実行

Trachetのモードコントロールやステップ実行は、デフォルトではファンクションキーで行います。

キーアサインは以下のようになっています。

- <F6> 

トレースのON/OFFをトグルする(デフォルトはON)

- <F7>
ブレーク状態(逐次的実行状態)のON/OFFをトグルする(デフォルトはOFF)

- <F8>
認識したシーケンスをひとつずつステップ実行

- <F9>
コントロールキャラクタ(\x00-\x1fの範囲の文字)を飛ばしてステップ実行

つまり、プログラムをブレークして止めるには、F7を押せばよいです。

もういちどを押せば、I/Oでブロックされていたプログラムの実行が再開します。

F7でブレーク状態に入った後は、またはでステップ実行できます。

F8とF9の違いは、コントロールキャラクタを飛ばすかどうかです。

F8やF9を押し続けていると、だんだんアクセラレーションするようなつくりになってますので、飛ばし過ぎないように注意してください。


ブレーク条件の設定

Trachetは、$HOME/.trachet/conf.pyに設定を追記することで、動作をいくらかカスタマイズすることが可能です。

たとえば、マウスを利用するアプリケーションでは、


ESC [ ? 1 0 0 0 h


または


ESC [ ? 1 0 0 2 h


を端末に出力しているのですが、これを検出したときに自動でブレークするような設定を書いてみます。


$HOME/.trachet/conf.py

_SEQDB_OVERLAY['> CSI ?1000h'] = '!controller.set_break()'

_SEQDB_OVERLAY['> CSI ?1002h'] = '!controller.set_break()'


さらに便利な使い方

trachet_on_tmux


  • 上のように、GNU Screenやtmuxでペイン分割してやって、ターゲットとトレース用端末が同時に見えるようにしてやると、とてもはかどります。


  • mltermのソースにはmltracelog.shというツールが付属していて、mlterm --logseqで採取したログを別ウィンドウで観察することができます。

    これはOSC 5380シーケンスの使用例としても興味深いものですが、ステップ実行やトレースログの表示にはtrachetを使っています。


  • -oオプションをつけずにtrachetを起動することもできます。この場合、ステップ実行機能だけは生きていますので、あまり動体視力がよくない人が端末画面上でおきている現象を把握するのに役立つかもしれません。



さいごに

アプリケーション動作基盤としての端末は、さまざまな理由からterminfo/termcap、termios、端末エミュレーション等の複数のレイヤが一見協調するように見えながらも実はそれぞれの理屈で動いているような部分があったりして、これらのどこで問題がおきているのか、切り分けにはけっこう頭を痛めるところでもあります。

しかし入出力の観察に慣れてくると、だんだんとそれぞれのレイヤに特徴的な異状の傾向を見てとることができるようになります。いわば端末の脈診です。

そればかりではなく、個々のアプリケーション特有の動きの特徴とか、端末側の挙動や応答のクセなども把握できるようになってきます。

いままで端末にかかわる人にとっては、scriptコマンドなどで採取されたログを読むことは必須スキルでしたが、ちょっとした訓練が必要でした。

Trachetはこの作業をリアルタイムに、かつひとつづつのシーケンスを説明つきで見せてくれるので、敷居は大幅に下がったのではないかと思います。

端末に親しむための入門・教育用ツールとしても、ぜひTrachetを活用してみてください。