4 ポイント 投稿者 GN⁺ 2024-08-13 | 1件のコメント | WhatsAppで共有
  • iTerm 2を長く使っていたユーザーが、テキストベースの設定とdotfiles共有のためにWezTermを再び試し、Lua設定APIで外観・キーバインド・マルチプレクシング・ワークスペースを細かくカスタマイズ
  • 設定はwezterm.luaに置き、保存すると即座にホットリロードされ、CTRL + SHIFT + LのデバッグオーバーレイでログとLua REPLをすぐ確認できる
  • Lua設定により、1,000種類以上の内蔵カラースキーム、システムのダーク/ライトモード連携、フォント、macOSのウィンドウ装飾、powerlineスタイルのステータスバーを動的に構成できる
  • デフォルトのキーバインドは維持も無効化もでき、Option + Arrowでの単語移動、CMD +,での設定を開く操作、leader keyとkey tableベースのpane操作を自分で定義する
  • 内蔵マルチプレクシングとworkspacesはtmuxセッションのようにプロジェクトごとのウィンドウ・pane・tab状態を保持し、Luaでプロジェクト選択UIや切り替えフローまで作れる

iTerm 2からWezTermへ移ってみた理由

  • iTerm 2をほぼ10年近く使ってきたが、設定をすべてテキストで管理してdotfilesに入れ、仕事用・個人用マシンで共有できるターミナルを求めていた
  • WezTermは強力なAPIとLua configが強みで、2回目の挑戦では見た目も良く機能的なターミナル構成を実現できた
  • 扱う範囲は外観、キーバインド、マルチプレクシング、ワークスペース移動、ステータスバー、動的テーマ設定
  • 今回の記事で扱わない機能もある
    • カスタムハイパーリンクのハイライトルール
    • 検索可能なscrollback
    • quick copy mode
    • 画像サポート
  • 例の構成はmacOSでの利用体験に合わせており、他のシステムでは試していないが、WezTerm自体はさまざまな環境で動作する
  • 最終的な設定例はgistで公開されている

インストールとLua設定の基本構造

brew install wezterm
  • 設定ファイルは$XDG_CONFIG_HOME/wezterm/wezterm.luaに置く構成を使っている
    • macOSを含むほとんどのシステムでは~/.config/wezterm/wezterm.luaとして解釈される
    • ~/.wezterm.luaひとつに置く代わりにディレクトリを使うと、設定を複数ファイルに分けて管理しやすい
local wezterm = require 'wezterm'
local config = wezterm.config_builder()

return config
  • WezTermの設定はLuaで書くため、YAMLやTOMLより複雑な動的設定を作りやすい
  • Luaはプログラミング言語なのでYAML/TOMLより学習は難しいが、Ruby・Python・JavaScriptのような動的言語の経験があればサンプルコードは読みやすい
  • Luaの学習資料としてGetting Started guideを参照できる

ホットリロードとデバッグオーバーレイ

  • WezTermは設定ファイルの変更を検知して自動リロードするため、ターミナルを再起動せずに設定の反映をすぐ確認できる
  • 関数名の間違いのようなエラーがある設定を保存すると、即座にランタイムエラーのポップアップが表示される
wezterm.config_builderZ()
  • ログはwezterm.log_info()で出力できる
wezterm.log_info("hello world! my name is " .. wezterm.hostname())
  • CTRL + SHIFT + Ldebug overlayを開くと、ログとLua REPLを確認できる
    • 1 + 1のようなLua式を実行できる
    • wezterm.home_dirのようなweztermモジュールの値も確認できる
  • ホットリロードとデバッグオーバーレイを組み合わせると、設定を変えて確認するフィードバックループが短くなる

外観設定: カラー、システムテーマ、フォント、ウィンドウスタイル

  • カラースキームと動的設定

    • WezTermは1,000種類以上の内蔵カラースキームを提供し、config.color_schemeで選択する
    config.color_scheme = 'Tokyo Night'
    
    • カラースキーム一覧はWezTerm colorschemesで確認できる
    • window-config-reloadedイベントとwezterm.color.get_builtin_schemes()を使えば、新しいウィンドウごとにランダムなカラースキームを適用する動的設定も可能
    • ウィンドウごとのconfig overrideを設定したあとで静的カラースキームに戻すと、ホットリロードがすぐ反映されない場合がある
    • デバッグターミナルでwindow:set_config_overrides({})を実行するか、ウィンドウを閉じて再度開くとoverrideを消せる
  • システムのダーク/ライトモード連携

    • 設定をappearance.luaモジュールに分離し、OSの外観に応じてカラースキームを切り替えられる
    • wezterm.gui.get_appearance()"Dark"文字列を探してダークモードかどうかを判定する
    • wezterm.guiがない環境では、デフォルトでダークモードとして扱う
    if appearance.is_dark() then
      config.color_scheme = 'Tokyo Night'
    else
      config.color_scheme = 'Tokyo Night Day'
    end
    
  • フォントとウィンドウ装飾

    • WezTermはデフォルトでJetBrains MonoとNerd Font Symbolsを含んでいる
    • 例の設定ではBerkeley Mono 13ptを使っている
    config.font = wezterm.font({ family = 'Berkeley Mono' })
    config.font_size = 13
    
    • macOSのウィンドウスタイル例には、半透明背景、blur、タイトルバーの削除、タブバーのフォント設定が含まれる
    config.window_background_opacity = 0.9
    config.macos_window_background_blur = 30
    config.window_decorations = 'RESIZE'
    

ステータスバーとWezTermイベントAPI

  • update-statusイベントのコールバックで、右側のステータスバーにpowerline形式のセグメントを追加する
  • 最初の例では、現在のカラースキームの背景色・前景色とwezterm.hostname()を使ってhostnameセグメントを表示する
  • wezterm.onはターミナルイベントにコールバックを接続する
    • update-statusはステータス更新の準備ができたときに定期的に発生する
    • WezTermは一度に1つの更新だけが実行されるよう管理し、コードに時間がかかりすぎるとハンドラを停止する
  • window:effective_config().resolved_paletteで、overrideが反映された現在のパレットを取得できる
  • wezterm.formatは文字列に色、太字、下線などのスタイルを適用するのに使う
  • 後半の例では、ステータスバーのセグメントをさらに増やしている
    • 現在のworkspace
    • 日付と時刻
    • hostname
  • wezterm.color.parsecolor:lightencolor:darkenwezterm.color.gradientで現在のテーマに基づくグラデーション色を計算する

キーバインド: macOSでの単語移動と設定を開く操作

  • WezTermはデフォルトのキーバインドを備えており、この例ではそれを維持している
  • デフォルトのキーバインドを無効にするにはconfig.disable_default_key_bindings = trueを使える
  • macOSでiTerm 2やTerminal.appのようにOption + LeftArrowOption + RightArrowで単語単位の移動をするため、ESC + bESC + fを送信する
{
  key = 'LeftArrow',
  mods = 'OPT',
  action = wezterm.action.SendString '\x1bb',
}
  • CMD + ,でWezTermの設定ファイルを新しいタブで開くように構成できる
    • 例ではnvimwezterm.config_fileを使っている
  • macOSのFinderからWezTermを起動した場合、PATHにエディタのバイナリがなく、コマンド実行に失敗することがある
  • config.set_environment_variablesでデフォルト環境変数を補えば、その後のspawnコマンドにも同じ環境が引き継がれる
config.set_environment_variables = {
  PATH = '/opt/homebrew/bin:' .. os.getenv('PATH')
}

内蔵マルチプレクシングとleader key

  • WezTermの内蔵マルチプレクシングはtmuxの代わりに使える機能
  • 内蔵機能はpaneごとのscrollback buffer、より良いマウス操作、より簡単な選択機能、全体的により高速な性能を提供する
  • CTRL + SHIFT + Pでcommand paletteを開き、“Shell: Split Horizontally”、“Shell: Split Vertically”のようなコマンドを実行できる
  • デフォルトの分割ショートカットは衝突を避けるため複雑なので、leader keyでよりシンプルな組み合わせを作れる
config.leader = { key = 'a', mods = 'CTRL', timeout_milliseconds = 1000 }
  • 例ではtmux風に、leaderのあと"で水平分割、%で垂直分割を実行する
{
  key = '"',
  mods = 'LEADER',
  action = wezterm.action.SplitHorizontal { domain = 'CurrentPaneDomain' },
}
  • CTRL + A自体をターミナルに送りたいときは、LEADER|CTRLの組み合わせで再びCTRL + Aを送るようにマッピングする

pane移動、リサイズ、key table

  • pane移動はvim方向キー風のhjklをleader組み合わせにマッピングする
  • ActivatePaneDirectionDownUpLeftRightへの移動を実行する
  • 繰り返し出てくるLuaテーブルは関数で簡潔にできる
local function move_pane(key, direction)
  return {
    key = key,
    mods = 'LEADER',
    action = wezterm.action.ActivatePaneDirection(direction),
  }
end
  • paneのリサイズはマウスでも可能だが、この例ではキーボード中心の操作フローのためにkey tableを使う
  • key tableは特定モードに入り、そのモード専用のキーバインドを使う仕組み
    • leader keyに似ているが、1回動作したあとすぐ無効化されないようにできる
    • リサイズのように同じキーを繰り返し入力する作業に向いている
  • 例ではLEADER + rresize_panes key tableを有効化し、h/j/k/lでpaneサイズを3セルずつ調整する
  • timeout_milliseconds = 1000で1秒後にリサイズモードを抜けるよう設定する
  • Neovimユーザーは、WezTerm paneとvim paneの間の移動を助けるsmart-splits.nvimを参照できる

プロジェクトごとのworkspace構成

  • 複数のプロジェクトを同時に扱うときは、プロジェクトごとに別々のマルチプレクサインスタンス、ウィンドウ、pane、tab状態を保持したくなる
  • tmuxのsessionに近い目的を、WezTermではworkspacesで扱う
  • projects.luaを作り、プロジェクト選択関数をメイン設定から読み込む構成を使う
  • 初期の例ではプロジェクトパスを直接列挙し、InputSelectorで選択UIを表示する
    • fuzzy = trueであいまい検索を有効にする
    • 選択結果は最初はdebug overlayにログとして出力するだけ
  • LEADER + pはプロジェクト選択UIを開き、LEADER + fは既存workspace一覧をあいまい検索で表示するよう設定する
action = wezterm.action.ShowLauncherArgs { flags = 'FUZZY|WORKSPACES' }
  • プロジェクトパスを手動管理する不便さは、wezterm.glob()でプロジェクトフォルダ配下のサブディレクトリを自動収集して軽減できる
  • 例では~/Projects配下のサブディレクトリをプロジェクトとして使い、ホームディレクトリもプロジェクト一覧に含める
  • プロジェクトを選ぶとSwitchToWorkspaceを実行する
    • workspaceがあれば切り替える
    • なければ新しく作成する
    • workspace名にはパスの最後のセグメントを使う
    • 新しいターミナルのカレントワーキングディレクトリは、選んだプロジェクトパスに設定する

さらに試せること

  • WezTermには機能一覧にあるように、さらに多くの機能がある
  • Lua設定の可能性はWezTerm API docsでさらに確認できる
  • 段階的に作った設定は、実際に使う項目だけ残し、自分のスタイルに合わせて書き直したうえで必要な機能を足していく進め方がよい
  • WezTermが気に入ったなら、オープンソース開発を続けるWezを支援することもできる

1件のコメント

 
GN⁺ 2024-08-13
Hacker News の意見
  • 最近 WezTerm に乗り換えて、とても満足している
    以前は kitty を使っていて、iTerm2 から移行したときは設定とシンプルさが気に入っていたが、標準機能の面では WezTerm のほうがずっと優れている。ターミナル設定もエディタの1画面に収まるほど短く、その後はターミナルがただ邪魔にならないので気にすることがない
    kitty を諦める決定打になったのは、問題に出くわしたり iTerm2 の機能を再現しようとしたりするたびに、メンテナーの短く突き放すような返答を目にしたことだった
    例えば「kitty で tmux をどう設定すればいいか?」という質問に、「やるな、tmux はバカげている」のように答えて閉じていたと記憶していて、結局諦めた

    • 私もメンテナーのそうした返答が理由で Kitty から WezTerm に乗り換えた
      もちろん本人のプロジェクトだし優れたプログラマーだが、もう少し謙虚さがあっても悪くないと思う
    • WezTerm が iTerm の hotkey window に相当する機能をサポートしているのか気になる
      なじみのない人向けに説明すると、特定のショートカットで表示/非表示を切り替えられ、表示時にはすべてのウィンドウの上に浮かんで、どこからでもすぐにターミナルを使えるようにするウィンドウのこと。なくても生きてはいけるが、わざわざ手放したくはない機能なので、WezTerm の他の機能が良くても、これがなければ私にとっては最初から候補外になる
    • 年を取るほど、過度に独善的で人を見下すメンテナーは避けるべきプロジェクトの最大の警告サインのように感じる
      表面的には最高の製品に見えることが多いが、いったん深く使い始めると、その人の選択に閉じ込められて戻る場所がなくなる
    • Kitty のメンテナーが少しとげとげしいこと以外に、特別深刻だとは思わないが、メンテナーにユーザーの友人になる義務はない
      ただ、今年初めに WezTerm を使い始めたときは本当に驚いた。Wez の文章をたくさん読んだが、毎回トーンが完璧で、本当に素晴らしいと感じた
    • kitty の開発者は、ターミナルをどう使うべきかを自分が誰よりもよく知っていて、他人の見解は根本的に間違っていると考えるタイプに近いように見える
      Linux の古い make menuconfig UI すら正しくレンダリングできず、設定で直すこともできないのに、それは本人が設定というものを信じていないからだ、という点が象徴的だ。Issue トラッカーの投稿を読んでいると、侮辱的なだけでなく、ランダムなターミナルの使い方を自分も同じように激しく「防御」しなければならないような感情まで湧いてきて、健全ではない
      はっきりとは分からないが、仮にターミナルに関するあらゆる点で彼と意見が同じだったとしても、彼のターミナルを使うくらいなら自分でターミナルを作る、という気持ちは変わらないと思う
  • 私の経験では、Wez は GitHub Issue に驚くほど素早く反応し、実際に間違っている部分ならたいてい1〜2日で直してくれる
    SSH 越しの modifier キーに関する小さな不満が1つ2つある以外は、機能はほぼ自分のニーズに完全に合っていて、しかも速い。以前は Alacritty を熱心に使っていたが、リモート Emacs でより良い modifier サポートが必要だった

    • 私も Issue を開いたが(https://github.com/wez/wezterm/issues/4917)、回答だけでなく脇道の質問にも答えてくれ、私が作った修正 PR 2件も本当に素早くマージしてくれた
    • 私の経験はそこまでポジティブではなかった
      すでに閉じられた Issue にコメントしたのは確かだが、いずれにせよ「won’t do」として閉じられていて、私のコメントは無視された。すでに却下された同じ内容で新しい Issue を開きたいとは思わなかった
      https://github.com/wez/wezterm/issues/4706
    • リモート Emacs に関しては、WezTerm はキーの組み合わせを完全に横取りして再定義できる
      C-S-" のような組み合わせはターミナルプロトコルがサポートしていないため、送る良い方法がない。そこで WezTerm に代わりに " c s '" を送らせ、Emacs に追加のバインディングを入れた。この F12 トリックのおかげで、ターミナルプロトコルがサポートできないかなり複雑な組み合わせも送れた
  • もともと WezTerm は、Kubuntu から Ubuntu に移行したときに Konsole をインストールしなくても Konsole の一部機能、たとえば 無限スクロールバック やスクロールバック検索を使いたくてインストールしたものだった。
    Gnome でも Konsole をインストールできるのは知っていたが、何かしっくりこない感じがあった。WezTerm はすぐに気に入ったが、この記事を読んで、設定できることについてはまだ表面をなぞった程度だと分かった。
    唯一の不満は、多くの機能が見つけにくいことだ。ドキュメントは本当に良く、作者も積極的で親切だが、たとえばキーボードだけで大きなテキストブロックを選択する方法を見つけて一度試し、「これは覚えておこう!」と思ったのにすぐ忘れてしまい、今ではまた完全な初心者のようにマウスで選択している。そもそも頻繁にやる作業ではないので、そのドキュメントページをまたググるより、そのほうが速いからだ。
    ちなみに、言っているページは https://wezfurlong.org/wezterm/copymode.html で、名前だけ見ると探していたもののように見えるが、まったく別機能の https://wezfurlong.org/wezterm/quickselect.html ではない。これも非常に便利で良いアイデアだが、私が探していたものではなかった。

    • WezTerm の設定を dotfiles リポジトリに入れておき、あとで簡単に見つけられるように、こういうメモを README に書いておいた。
      https://github.com/bbkane/dotfiles/tree/master/wezterm
    • QuickSelect モードは本当にすごい。
      デフォルトの状態でも便利だが、本当の強みは、マッチさせる正規表現をカスタマイズできる点にある。eza --icons の出力にあるファイル名をすべて見つける正規表現を1つ追加したところ、\p{Co} がアイコンにマッチする。なので lseza にエイリアス設定しておけば、そのまま shift+QuickSelect の文字で任意のファイル名を入力できる。
    • WezTerm で 無限スクロールバックとリアルタイムのスクロールバック検索を Konsole のようにできる方法がある、という意味なのか気になっている。
      まだその方法を見つけられておらず、そのためよく Konsole セッションも一緒に立ち上げている。リアルタイムログを tail するとき、この2つの機能は本当に強力だ。
    • なぜ Kubuntu から移行したのか気になる。インストールを考えているので聞いてみた。
  • Mac Terminal、iTerm2、Kitty、Warp などを試した末、結局 WezTerm に落ち着いた。
    設定が簡単で速く、見た目も良い。テーマも1つ作った。
    https://tiniri.vlad.studio/

    • 私もこうしたターミナルを試してきたが、結局 WezTerm にとどまり、今では一番好きなターミナルの1つになっている。
      複数のターミナルを比較しようとして、このサイトを偶然見つけた: https://terminaltrove.com/terminals/
      ターミナルを比較したい人にはかなり役立ちそうだ。
    • このテーマはとても良い。JetBrains のエディタでも使う方法があるのか気になる。
    • 明るい Vlad テーマが気に入ったのでインストールした。
    • カラーテーマが本当に良い。Konsole と Sublime Text 用もあるといいな。
  • WezTerm を1年ほど使っていて GitHub で Wez をスポンサーしているが、素晴らしいターミナルだし、彼は良い開発者だ。
    この記事では扱わないと言っていたが、私のお気に入り機能の1つは Quick Copy と他のコピーモードだ。本当にいつも使っている。C-S-Space を押して、コピーしたい項目の横に表示された文字を入力すればよい。
    大きなユースケースは、macOS ノートPCから会社の Linux マシンへ mosh+tmux のような機能を使うことだ。常にセッションを立ち上げておき、Mac から会社のマシンで作業できる。再接続可能なセッションに pane と tab まで提供してくれるので、席を離れていても作業でき、品質も非常に高い。

    • Quick Copy モードの本当にクールな機能の1つは、文字を大文字版で入力すると、その値が自動的にターミナルプロンプトへ貼り戻される点だ。
    • QuickSelect を今知った。これからかなり使うことになりそうだ。
  • WezTermで気に入らない点なんてあるのか、と思う
    私がいちばん気に入っているのに、よく見過ごされがちな機能は完全なクロスOSサポート。Linux、macOS、Windowsを全部使う私のような環境なら、WezTermひとつを覚えればそれで済む。ターミナル設定のかなりの部分もOS間で共有している

    • WezTermで気に入らなかった唯一の点であり、使用をやめた理由は、折り返された行をクリップボードにコピーする挙動に関係している
      私だけの問題か、tmuxの使い方のせいかもしれないが、行がwrapされた状態でコピーすると、コピーされたテキストに改行が含まれるように見えた。非常に気になったし、WezTermとtmuxの相互作用が原因だと思う
      良いバグレポートを作れるほど証拠が十分ではないし、WezTermには独自のターミナル多重化サーバーである「ssh domains」があるので、修正するほど重要ではないのかもしれない。とはいえWezTermの多重化サーバーをあちこちにインストールしたいわけではなく、SSHで入る先にはだいたいtmuxがすでにある
      それ以外はWezTermは素晴らしい
    • 会社のMacBookと個人のLinuxマシンを行き来するときの最大の苦痛はショートカットキー
      macOSの設定オプションは限られていて、いろいろな回避策が必要になる。LinuxをmacOSに合わせることもできるが、そもそもmacOSのショートカット自体があまり好きではない。結果として妙な混在状態になり、切り替えるたびに間違ったキーを押し続けることになる
      うまく合う設定を見つけた人がいるのか気になる
    • 私の環境では性能が良くなく、時間がたつとタブ切り替え時に数秒ずつ固まる傾向があった
      理由も分からないし、診断方法も分からない。大きなスクロールバックが唯一の推測だが、それは諦められない。結局Kittyに移行した。Kittyにもそれなりに問題はあるが、少なくとも動作はする
    • ここでは言語選択が本当に重要だと思う
      Lua設定言語は環境ごとの変更をかなり簡単にできるので真価を発揮する。Rustの過小評価されている副次効果もあると思う。現代のRustツールは、言語とOSの間の抽象化レイヤーが優れているからか、クロスプラットフォーム対応が優秀な場合が多い
    • 3つのOSすべてでよくテストされている点も大きい
      2019年ごろ、GitHub Actions、issue、ドキュメント化の面でwezリポジトリと他のものを一度比較してみただけで十分に納得し、それ以来戻っていない。標準でtab機能までサポートしている
      サポートと速度の面でurxvtを本当に置き換えた最初のターミナル。以前はtermiteを使いつつ、termiteが妙な状況でバグる場合に備えてurxvtをバックアップとして残していた
  • 私がiTerm2に残っている理由はEdit->Selection Respects Soft Boundariesのため
    「有効にすると、パイプ文字|の縦線をvimやemacsのpane区切り線のように解釈し、選択範囲がその地点でwrapされる」という機能
    私の場合はIRCでテキストを選択するときに必要になる
    https://github.com/wez/wezterm/issues/596

    • これは実質的にMicrosoft Word的な肥大化問題
      すべての機能を必要とする人はいないが、各自が欲しいニッチ機能が10個あり、その10個は互いに同じではない。だからニッチ機能10個を得るために肥大化を受け入れることになる
    • この機能はものすごく良さそう。Linuxでサポートしているターミナルがあるのか気になる
    • zellijは、ターミナルが適切なOSC機能をサポートしていれば標準でこれをサポートする。このスレッドにあるターミナルならサポートするはず
      追記: 乱暴な言い方だった、申し訳ない。IRCで使うという部分を見落としていた
    • 実際に見ると素晴らしいUI/UX機能だという点に100%同意する
    • iTermを何年も使っていたのに、この設定をまったく知らなかった。私のEmacs利用には決定的な機能だ
  • ほぼ10年前にmacOSを初めて使い始めて以来、iTerm2ユーザーだった
    ところが最近、本当に遅くなったと感じていて、cmd-tabで切り替えたときにターミナルが表示されるまで1秒以上待つようになり、限界に達した
    いくつか代替を見てみたが、ぴったり合うものはなかった。あるターミナルは動作するのにアカウント/ログインが必要で大きな欠点だったし、別のターミナルは{Java,Type}Scriptで書かれていて、Node.jsストリームの非同期性のせいでyesのような単純なコマンドすら壊していた
    今のところWezTermはとても気に入っている。かなり速く、非常に設定しやすく、iTerm2で設定していたテーマであるOneDark(base16)が標準で入っている
    最初に感じた唯一の不便は、Lua設定にcmd-leftcmd-rightの構成を自分で追加する必要があった点で、標準値に入っていたらよかったと思う

    • アカウント/ログインが必要なのはWarpで、{Java,Type}Script製なのはTabbyかextratermのどちらかということ?
  • WezはRustシステムプログラミングの本も出している
    https://leanpub.com/sysprog

  • 良い記事なのでWezTermを一度試してみるかもしれないが、最近ちょうどKittyに移ったばかりなので、あまり頻繁に乗り換えたくはない
    ただしKittyについては訂正が必要。KittyはYAMLやTOMLを使わず、独自のシンプルな設定DSLを使い、それ以外はPythonで完全にスクリプト可能

    • 私も似たような感じなので、とりあえずブックマークだけしておいた