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


α版の頃から追っかけてましたが、ついに 3.3.0 正式版がリリースされましたね! 合わせて以下の記事も続編として公開しております。


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

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

tmux Integration と組み合わせると吉

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

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

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

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


(2019/8/13 追記)

以下のコードは初めて自作コンポーネントに挑戦する人には複雑すぎるので、続編として簡単なコンポーネントの作り方をまとめました。Python 使わなくても自作が可能ですので参考にしてください。


(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 から閲覧可能です。

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

最後に

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