裏で動いているコマンドが完了したら通知が欲しい
小ネタ。
長く掛かる作業、例えば、コンパイルとかデプロイとか大きなファイルの圧縮とか、そういう作業を開始した後、待つ間に別のタブやアプリで作業を行う、こういうことは良くあると思います。その時に、開始しておいた作業が完了したら何らかの通知が欲しいです。
こういうソリューションはすでにあり、fish を使うなら franciscolourenco/done が有名です。僕もこれ使ってたのですが、一度動かなくなった時に理由が分からず、コードを見ようとしたら複雑過ぎて断念したので代替策を探していました。
すると、↓こちらの記事に同じような課題感から独自に機能を実装してるコードがあり、これを修正して僕の環境で動くようにしました。
「裏」で動いているかどうか判定する
先に載せた記事のコードには一点不満があり、それは、「現在まさに WezTerm で作業中のコマンドが完了した場合も通知が来る」というものでした。Neovim で文書を書いていて、それを終了させた時も通知が来ます。終了させたのは自分ですから通知は必要ありません。通知は「裏側」で動いているコマンドが終了した時のみにしたいのです。
僕は表題の通り、WezTerm を使っています。WezTerm で上記の問題を解決するなら以下のような方法を使えば良さそうです。
- コマンドが実行された pane の ID とアクティブな pane の ID が異なる時だけ通知する。
これだけですね。
しかし、一つ問題があります。僕はセッションを永続化するために Multiplexing 機能も利用しており、平たく言うなら tmux のような使い方をしています。
この場合何が困るかと言うと、「アクティブな pane を判定するのが難しい」という点です。WezTerm は wezterm cli
コマンドにより起動したシェルから様々な情報を取得できるようになっています。しかし、Multiplexing 機能を使っている関係上、一つのシェルが複数の WezTerm クライアントで表示される訳で、「今どのクライアントのどの pane がアクティブになっているか」は、シェルから知ることができません。
OS の機能で「アクティブ」か判定する
また、別の問題もありました。いくら WezTerm 上でアクティブな pane だとしても、別のアプリで作業中の時は通知が欲しいです。ウィンドウ自体が見えなくなってるかも知れませんからね。
これらの理由から、OS の機能を使って「アクティブ」かどうかを判定することにしました。「アクティブ」ということは GUI ウィンドウが最前面に来ているはずですから、そのウィンドウを開いているプロセスが何か分かれば良いです。このために僕の完成版スクリプトは macOS 限定のものになっています(元の記事のスクリプトは Linux でも動きます)。
ChatGPT に「最前面にあるウィンドウのプロセス番号を知りたい」と聞いたら一発で教えてくれました。Apple Script は良く知らないので助かります。
# 最前面のウィンドウを表示しているプロセスの ID を得る
osascript -e 'tell application "System Events" to get the unix id of first process whose frontmost is true'
このプロセス番号で wezterm cli list-clients
を検索すれば、「アクティブな pane の ID」が分かります。もし WezTerm が最前面でないなら、結果は空になる訳です。
# 指定したクライアントが表示しているアクティブな pane の ID を得る
wezterm cli list-clients | perl -anle 'print $F[5] if $F[2] == '$active_pid
完成版のスクリプト
長くなりましたが、以下のスクリプトが完成版です。これを config.fish
に書いておけば、5 秒以上掛かったコマンドについて通知が来ます。
既知の問題
かなりレアなパターンですが、別の端末で接続しているクライアントのプロセス番号が現在の端末の最前面のウィンドウと一致すると、「裏側」なのに通知が出ちゃいますね。厳密にやるならばホスト名も含めて比較すべきでしょう。これは宿題にしときます。
終わりに
WezTerm、多機能ですが痒い所に手が届く作りになっていていいですね!