🐵

ターミナルページャー ovの紹介

2020/10/05に公開

私が作っているターミナルページャー ovを紹介します。
Goで作成した新しいページャーです。

従来のターミナルページャー(Terminal Pager)

ターミナルページャーとは、lessやmoreに代表されるようにテキストファイルを表示したときに1画面(端末の表示域)に収まる分だけ表示するアプリケーションです。
ユーザーがファイルを指定したり、パイプ(|)で渡したりしますが、それだけでなくmanやgitの様にアプリケーションから内部的に呼び出されている場合があります。

RDBMSのクライアントのPostgreSQLのクライアントpsqlやMySQLのCLIクライアントでも内部的に呼び出されます。これは主に表形式のデータを表示するのに使用します。

この表形式のデータを表示させていると不満な点がありました。

不満な点

  • ヘッダー行が最初しか表示されない ※
  • 同じような行が大量に表示されて見づらい
  • 折り返して表示すると列を見つけづらい

※(lessの開発版ではヘッダーが指定できるようになっています!)

これらの問題があるため、psqlやmysqlには表示を切り替える方法が存在しています。
psqlではメタコマンド\xで以後の結果を、mysqlではSELECT 〜 \G;により、縦に表示するモードに切り替えることが出来ます。

↓psqlの例。ヘッダー行もスクロールされて以下のような結果が画面いっぱいに表示される。

 pg_catalog.var_samp        | n       |                0 | int8_accum           
        | numeric_var_samp                     | numeric_combine      | numeric_
serialize      | numeric_deserialize      | int8_accum        | int8_accum_inv  
   | numeric_var_samp         | f             | f              |         0 |    
     2281 |           128 |          2281 |            128 |                    
 |                                                                              
 pg_catalog.var_samp        | n       |                0 | int4_accum           
        | numeric_poly_var_samp                | numeric_poly_combine | numeric_
poly_serialize | numeric_poly_deserialize | int4_accum        | int4_accum_inv  
   | numeric_poly_var_samp    | f             | f              |         0 |    
     2281 |            48 |          2281 |             48 |                    
 |                                                                              

↓ 縦表示に切り替え。「列名 | 値」で表示。

-[ RECORD 66 ]---+-------------------------------------
aggfnoid         | pg_catalog.var_samp
aggkind          | n
aggnumdirectargs | 0
aggtransfn       | int8_accum
aggfinalfn       | numeric_var_samp
aggcombinefn     | numeric_combine
aggserialfn      | numeric_serialize
aggdeserialfn    | numeric_deserialize
aggmtransfn      | int8_accum
aggminvtransfn   | int8_accum_inv
aggmfinalfn      | numeric_var_samp
aggfinalextra    | f
aggmfinalextra   | f
aggsortop        | 0
aggtranstype     | 2281
aggtransspace    | 128
aggmtranstype    | 2281
aggmtransspace   | 128
agginitval       | 
aggminitval      | 

非常に見やすくなりますが、1画面に表示できる量が少なくなってしまい、スクロール量が多くなってしまいます。そのため、列が多い場合のみ縦表示に切り替えたりしています。

また、これらの表形式に対応した専用のページャーにpspgというものがあります。

pspg

pspgは、上記の不満を解消していて良いのですが、列が多いと右側にはみ出して横スクロールする必要があり、一度に表示できる列が少なくなります。そのため、見たい列を固定しておく列の固定が指定出来るようになっています。

ですが、psqlなどを使用しているとSQL→結果表示を頻繁に行き来するので、結果を表示後、列を固定してスクロールするのが煩わしく感じられることがあり、私は常用するまでには至りませんでした。

そのため、従来のページャーの不満な点を解消すべくovを作りました。

ovの動作

ovでは、オプション無しで起動すると従来のノーマルのページャーのように表示し、キーにより表示を切り替えられるようになっています。

ヘッダー行が最初しか表示されない問題の対応

「h」キーによりヘッダー行数を指定することで指定した行数を常に表示するようになります。

ヘッダーなし

↓(ヘッダー2行を指定)

ヘッダーあり

同じような行が大量に表示されて見づらい問題の対応

「C」キーにより交互に背景色を変更します。

交互背景色

折り返して表示すると列を見つけづらい問題の対応

「w」キーにより折り返しと折り返し無しを切り替えます(これはless でも -S[Enter]で切替可能です)。

折り返しなし

または「d」キーにより列の区切り文字を指定(psqlでは「|」)して、「c」キーを押すと列モードになり、「←」「→」キーにより反転している列の移動ができます。

列モード

以上のように見づらいデータによって表示方法を切り替えることが可能です。

その他の特徴

ovは、表形式のみに使用するだけでなく、通常のターミナルページャーとしても使用できるようにしています。
環境変数 PAGER にovを指定(export PAGER=ov)しても、問題になることはないと考えています。

manコマンドからの使用

manコマンドは通常のエスケープシーケンスとは違った方法で文字装飾をかけています。
同じ文字を2回打って太字を表し、「(_)アンダーバー」を重ねることで、下線を表しています。この2つの効果をovのスタイルで設定することで、例えば色を変更できます。

StyleOverStrike:
  Foreground: "green"
  Bold: true
StyleOverLine:
  Foreground: "red"
  Underline: true

man コマンドに呼び出された例

man

gitコマンドからの使用

エスケープシーケンスによる文字色の変更にデフォルトで対応しています。
gitコマンドに呼び出された例

git

圧縮ファイルに対応

圧縮(gzip, bzip2, zstd, lz4, xz)されているファイルもそのまま開くことが可能です。圧縮形式はファイル名ではなくファイルのヘッダーを見て判断しています。

また、複数ファイルを開くことも可能なので、以下のように圧縮と非圧縮のファイルがあっても、

ls /var/log/syslog*
/var/log/syslog       /var/log/syslog.3.gz  /var/log/syslog.6.gz
/var/log/syslog.1     /var/log/syslog.4.gz  /var/log/syslog.7.gz
/var/log/syslog.2.gz  /var/log/syslog.5.gz

まとめて指定することも出来ます(](次) [(前)で移動)。

ov /var/log/syslog*

キーバインドを変更可能

https://github.com/noborus/ov/blob/master/ov.yaml を参考に ~/.ov.yamlを用意すれば上記で書いた以外も含めてキーバインドを設定できます。

ライブラリとしての使用も

Goの話となりますが、ovの機能は、oviewer Packageで実現されていて、一部は公開の関数として利用可能になっています。今後は別プロセスの呼び出しでは実現しづらい元のアプリケーションとの双方向のやりとりを可能にすることも考えています。

Discussion