Python
iTerm2
Python3

iTerm2 にステータスバーが付いた

3.3.0 beta2 がリリースされましたね! だいぶ安定して動くようになったので記事を更新しました。


スクリーンショット 2019-05-11 20.18.04.png

左から順に今いるディレクトリのブランチ名、実行中のプロセス、バッテリー・CPU・メモリ・ネットワークの状態、現在時刻が表示されています。それぞれの配置や並べるコンポーネントは GUI で簡単に設定できるようになっています(Preferences > Profiles > Session > Status bar enabled > Configure Status Bar から設定できます)。

スクリーンショット 2019-04-14 17.55.18.png

テキストの字体や色は自由に変更できますが、Auto-Rainbow をクリックすると、いい感じに色をつけてくれます。


tmux Integration と組み合わせると吉

iTerm2 には tmux Integration という機能がありまして、これは tmux の Control Mode を使って tmux の各ウィンドウを iTerm2 のタブに統合できるのです。

便利な機能なのですが、tmux のステータスバーが消えちゃうのが難点でした。これを iTerm2 のステータスバーで代替できるようになったのです。


コンポーネントを自作する

もちろん、このコンポーネントは自作も可能です。実は、最初のスクリーンショットに挙げている機能のうち、バッテリーの状態は自作したコンポーネントで表示しています。


(2019/5/11 追記)

バッテリー状態の表示は他の人にも便利そうだったので、提案したところ、作者によってネイティブのものが実装されました(20190511 nightly build)。とはいえ、コンポーネントの自作手法としては相変わらず有用だと思われますので、以下のソースは残しておきます。


iTerm2 には昔から AppleScript を使った API が用意されていたのですが、最近はこれが Python3 で書けるようになりました。


事前準備

Python Runtime はメニューからインストールする必要があります。Scripts > Manage > Install Python Runtime の順にクリックするとインストールされます。


  • インストールパスは ~/Library/ApplicationSupport/iTerm2 です。

  • すでにインストール済みの方は Check for Updated Runtime という表示になっているかもしれません。

ドキュメントやサンプルスクリプトはここにあります。

今回はこれを使ってバッテリー残量を表すコンポーネントを自作してみました。

実際には Objective-C のコードを叩いたりなど、いくらか複雑なことをしていますが、ここには簡略化したものを載せておきます。これを ~/Library/ApplicationSupport/iTerm2/Scripts/Autolaunch/battery.py というファイル名で保存すると GUI から選択できるようになります。

#!/usr/bin/env python3

from iterm2 import Connection, StatusBarComponent, StatusBarRPC, run_forever
from iterm2.statusbar import Knob
from math import floor
from subprocess import CalledProcessError, check_output
from typing import List
import re

chars = ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"]
thunder = "ϟ"
width = 5

async def main(connection: Connection) -> None:
component: StatusBarComponent = StatusBarComponent(
"Battery",
"Show battery remaining",
[],
"|███▎ | 66% 2:34",
30,
"cx.remora.battery",
)
plugged = "🔌"

@StatusBarRPC
async def battery_status(knobs: List[Knob]) -> str:
try:
out: str = check_output(args=["/usr/bin/pmset", "-g", "batt"]).decode(
"utf-8"
)
except CalledProcessError as err:
return "`pmset` cannot be executed"

matched1 = re.match(r".*; (.*);", out, flags=re.S)
if matched1:
status: str = matched1[1]
else:
return plugged

matched2 = re.match(r".*?(\d+)%", out, flags=re.S)
if matched2:
percent: int = int(matched2[1])
else:
return plugged

battery: str
if status == "charged":
battery = width * chars[-1]
elif status == "charging":
mid: int = floor(width / 2)
battery = mid * " " + thunder + (width - mid - 1) * " "
elif status == "discharging":
unit: int = len(chars)
total_char_len: int = len(chars) * width
char_len: int = floor(total_char_len * percent / 100)
full_len: int = floor(char_len / unit)
remained: int = char_len % unit
space_len: int = width - full_len - (0 if remained == 0 else 1)
battery = chars[-1] * full_len
if remained != 0:
battery += chars[remained - 1]
battery += " " * space_len
else:
battery = " " * width

matched = re.match(r".*?(\d+:\d+)", out, flags=re.S)
elapsed: str = matched[1] if matched and matched[1] != "0:00" else ""
last_status: str = "{0} |{1}| {2:d}% {3}".format("🔋", battery, percent, elapsed)
return last_status

await component.async_register(connection, battery_status, timeout=None)

run_forever(main)

スクリプトの状況はメニューアイテム Scripts > Manage > Console から閲覧可能です。

スクリーンショット 2019-04-14 18.02.46.png

表示イメージは Code-Hex/battery を参考にしました。コンポーネントを作る際は async/await のような結構新し目の機能を使ってコーディングするようです。上記のサンプルスクリプトでは Type Annotation も頑張ってつけていますが必須ではありません。battery_status という、文字列を返す関数だけが肝で、あとはコピペでいけると思います。


最後に

最初はゴリゴリインターフェイスが変わって大変だったのですが、beta になってだいぶ仕様が固まってきたようです。公式の Issues を随時確認して利用してください。