前の記事の続きです。GNU Screen の最下行、caption に Last.fm の再生履歴を表示してみました。
一般的に、screen の caption に自由に文字列を描画するには backtick と呼ばれる仕組みを使います。
backtick とは?
Screen User’s Manual
http://www.gnu.org/software/screen/manual/screen.html#Backtickbacktick 登録コマンド:
backtick id lifespan autorefresh command [args]
backtick 解除コマンド:backtick id
(意訳)backtick コマンドにより指定されたコマンドの出力は
%`
エスケープと置換することで表示されます。一度コマンドが実行された後、
lifespan
値に表された秒数だけ待ってもう一度コマンドが実行されます。また、
autorefresh
値に表された秒数間隔で caption、及び、hardstatus が更新されます。コマンドの出力は最終行のみが利用されます。
lifespan、及び、autorefresh の値が両方とも 0 だった場合は、指定されたコマンドの出力を待ち、出力があるたびにそれを caption、または、hardstatus に表示します。
強調表示した部分が重要です。以前の記事で CPU 使用率などを caption 内に表示するために使ったコマンドは以下のようなものでした。
hardstatus alwayslastline "%{= Gk} %-Lw%40L>%{b kg} %n %?%h%:%t%? %{-}%+Lw%-0120=%{b ky} メモリ %0%% %{b kb}CPU %1
%% %{b kr}CPU温度 %2℃ %{b kw}%3
%{b km}%l %{.b}%Y/%m/%d %C %A" backtick 0 10 10 $HOME/.screen/memory backtick 1 1 1 $HOME/.screen/cpu backtick 2 5 5 $HOME/.screen/temperature.sh backtick 3 10 10 $HOME/.screen/battery.sh
これらのコマンドは定期的に実行することで最新の値を得るものですから、lifespan と autorefresh を適当な値に監視して実行しているわけです。
それと比較して、今回表示しようとしている Last.fm の利用履歴は定期的に内容が更新されるわけではありません。Screen 側で出力を待ち受けていて、変化のあったときだけ画面を更新するようにしたいです。
随時更新のために名前付きパイプを使う
このような用途を聞いてすぐに思い浮かぶのはパイプです。今回は名前付きパイプと呼ばれるものを使って実装してみます。
みます……っていいながら、この記事を参考にしただけなんですけどね。
screen の backtick をいつか使う(mkfifo使用) – l1o0の日記
http://d.hatena.ne.jp/l1o0/20110604/1307213405
これをアレンジして次のようなスクリプトにしました。Screen が終了したときに backtick.pl
プロセスが残ってしまう問題があったため、親プロセスが死んだときは自分でパイプを削除して終了するようにしています。
backtick.pl
は起動すると /tmp/backtick-プロセス番号.fifo
という名前付きパイプを作成します。そしてパイプからの入力を待ち、入力があったときは一行読み込み、それを標準出力に出力します。Screen 側ではこれを以下のような設定で利用するわけです。
caption always "%{= dd}%0`" backtick 0 0 0 $HOME/git/dotfiles/.screen/backtick.pl
caption
コマンド中、%0`
という部分が backtick.pl
の出力と置換されて表示されます。
後は、backtick.pl
の作成した名前付きパイプに出力を流し込んでやればいいわけです。たとえば、次のようにすると、直接 Screen の caption に書き込めます。
$ echo 'aiueo' >> /tmp/backtick-XXXX.fifo
簡単なアニメーション
これを応用し、簡単なアニメーションを作ってみます。連続してパイプに書き込むだけで簡単なアニメーションのできあがりです。
Last.fm からの表示履歴を得る
そして本題です。Last.fm から表示履歴を取得し、それを表示するスクリプトは以下のようになります。Last.fm へのアクセス方法は以前 jQuery プラグインを作ったときにまとめましたのでそちらを参考にしてください。
jQuery 版 Last.FM ウィジェットを導入してみた – blog.delphinus.dev
https://blog.delphinus.dev/2010/11/lastfm-widget-for-jquery.html
Last.fm for jQuery を改造してみました – blog.delphinus.dev
https://blog.delphinus.dev/2011/12/lastfm-for-jquery-mod.html
応用と注意点
今回は Last.fm の再生履歴を表示してみましたが、名前付きパイプに書き込むスクリプトなら何でもいいわけです。元ネタ記事では Twitter のタイムラインを表示しています。
以下は、同様のスクリプトを作るときの注意点です。
エスケープシーケンス
文字に色を付ける場合、.screenrc
内では %
文字を使って指定します。たとえば、%{yb}
ならば背景色は黄色、文字は青色というやたらと目立つ配色になります。
対して、backtick が認識するのは ^E
(Ctrl + E)というエスケープシーケンスです。同じ配色をスクリプトで出力するときは次のようにします。
$ perl -E 'say "\cE{yb}背景色は黄色、文字は青色\cE{-}"' >> /tmp/backtick-XXXX.fifo
*表示例では Solarized を使っているのでなんか違う色になってます。
無効な名前付きパイプ
何らかの原因で bactick.pl
が死んでいた場合、残された名前付きパイプに書き込もうとすると処理がブロックしてしまいます。
上に挙げたスクリプトではこれを回避するため、$SIG{ALRM}
を使って一定時間後にタイムアウトするようにしています。これではなんかいまいちなんで、無効なパイプを判断するいい方法はないんですかね。
日本語の扱い
もう一つ、いわゆる全角文字の表示にも注意が必要です。現在の安定版 v4.0.3 は caption に全角文字が表示できません。
開発ツリーの HEAD から取得したソースで Screen をビルド(この辺は前の記事を参照)した場合は表示自体はできるのですが、それでも完全ではありません。最大でも画面幅の 3 分の 2 しか文字が描画されないことがあります。
これは、Screen の実装では文字のバイト数で描画位置を決めていることが原因です。通常の全角文字は、UTF-8 で 3 バイトを要しますが、表示するときは 2 文字幅しか使いません。Screen ではこれに対処できず、表示位置がおかしくなってしまうのです。
終わりに
というわけで、がんばってここまで表示を充実させてきたわけですが、前回書きましたとおり、tmux ではもっといいのが出来てるんですね。
erikw/tmux-powerline · GitHub
https://github.com/erikw/tmux-powerline
このような表示は GNU Screen では実現できません。上に書きましたとおり、Unicode 文字(正確には、バイト数と文字幅が一致しない文字)を画面上に描画すると、大幅に構成が崩れてしまうのです。なんだかな〜。何とかなんないんですかね。何ともならないですよね。残念。