🌃

WezTermのタブに作業ディレクトリを表示させる

2024/09/26に公開

はじめに

ある日、はてブを見てたら以下の記事でWezTermというのを知りました。

https://motemen.hatenablog.com/entry/2024/09/wezterm

今まではiTerm2を使っており、大きな不満点はありませんでしたが、設定をVCSで管理することが難しい点は微妙だなと思っていました。設定をexportすることでVCSで管理することもできるみたいなのですが、なんだかんだでGUIで出力・管理するのは煩雑なためです。

その点WezTermはLuaで設定を書くことができ、VCSで設定を管理できるのでいいなと思いました。そこで本記事では、WezTermの設定をしていきます。

設定を加えたWezTerm

WezTermを記事や公式ドキュメントなどを参考にしつつ、以下のように設定しました。


設定後のWezTerm

このターミナルでは、「複数の異なるディレクトリを同時に開いて、並行で作業をする」ことを想定しています。例えば、$ docker compose upで複数コンテナを立ち上げつつ、同一のディレクトリで何かの作業をしたり、$ docker compose exec ...でコンテナ内に入って作業したりなどです。また、ディレクトリAとディレクトリBで、並列で作業をすることを想定しています。そのため、作業中のディレクトリのルート(=gitリポジトリのルート)をタブに表示しています。

以下に実際に利用するシーンを想定したターミナルを表示しています。左のnode [ zenn-contents ]タブではzennの記事のプレビューをしつつ、右のdocker [ zenn-symfony-docker ]タブではdockerを立ち上げています。真ん中のzsh [ gsy0911 ]タブではリポジトリでの何かしらの作業を想定しています。このように、リポジトリの名前がわかるだけで結構便利になります。


想定されるシーンでの利用画面

WezTermの設定

それでは、設定をしていきます。初期状態は以下のようになります。

~/.config/wezterm/wezterm.lua
local wezterm = require 'wezterm'
local config = wezterm.config_builder()

return config


初期状態

次に、ターミナル部分を透過させて、ぼかしを入れます。color_schemaここにサンプルが載っています。ちなみに、Nightlyを選ぶとiTerm2のデフォルトと同じ見た目になります。

~/.config/wezterm/wezterm.lua
config.color_scheme = 'Wombat'
-- 背景の非透過率(1なら完全に透過させない)
config.window_background_opacity = 0.70
-- 背景をぼかす
config.macos_window_background_blur = 20


ウィンドウの透過とぼかしを追加

ターミナルのフォントをJetBrains Monoに設定します。Intellij系を使っていることもありますが、見やすくて好きなフォントです。

~/.config/wezterm/wezterm.lua
config.font = wezterm.font('JetBrains Mono', { weight = 'Bold' })
config.font_size = 14.0


ターミナル内のフォント調整

同様に、タブの文字列のフォントも調整します。あまり変化はないように見えますが・・・。

~/.config/wezterm/wezterm.lua
config.window_frame = {
  font = wezterm.font('JetBrains Mono', { weight = 'Bold' }),
  font_size = 14,
}


タブのフォント調整

タイトルバーとタブの追加ボタンを削除します。タブの追加は⌘ + Tでできるため不要です。

~/.config/wezterm/wezterm.lua
-- タイトルバーを非表示
config.window_decorations = "RESIZE"
-- タブの追加ボタンを非表示
config.show_new_tab_button_in_tab_bar = false
-- タブが一つしかない時に非表示
config.hide_tab_bar_if_only_one_tab = true


タイトルバーとタブの追加ボタンを削除

わかりにくいですが、非アクティブのタブの境界線を削除します。2: zsh XXの隣にある線が消えているのがわかります。

~/.config/wezterm/wezterm.lua
config.colors = {
  tab_bar = {
    inactive_tab_edge = "none",
  },
}


境界線を削除

次に、各タブ内における作業ディレクトリを取得、保持する処理を記述します。local title_cachepane_idごとの作業ディレクトリを保持できるようにします。

私の環境のルールとして、$HOME/Development/Projects以下に各種Gitのリポジトリルートがあるようにしています。そのため、wezterm.on('update-status', function(...))内にてos.getenv 'HOME''/Development/Projects'の文字列を消すようにしています。ここは人によって異なると思うので修正してください。参考にした記事ではgitコマンドを利用していたのでそれでもいいかなと思います。

この設定を追加しただけでは、ターミナルの見た目に変化はありません。

~/.config/wezterm/wezterm.lua
function split(str, ts)
  -- 引数がないときは空tableを返す
  if ts == nil then return {} end

  local t = {} ;
  i=1
  for s in string.gmatch(str, "([^"..ts.."]+)") do
    t[i] = s
    i = i + 1
  end

  return t
end

-- 各タブの「ディレクトリ名」を記憶しておくテーブル
local title_cache = {}

wezterm.on('update-status', function(window, pane)
  local pane_id = pane:pane_id()
  title_cache[pane_id] = "-"
  local process_info = pane:get_foreground_process_info()
  if process_info then
    local cwd = process_info.cwd
    -- 文字列を削除している
    -- 環境に応じて変えること
    local rm_home = string.gsub(cwd, os.getenv 'HOME', '')
    local prj = string.gsub(rm_home, '/Development/Projects', '')
    local dirs = split(prj, '/')
    local root_dir = dirs[1]
    title_cache[pane_id] = root_dir
  end
end)

次に、上で定義した関数を利用してタブの見た目とテキストを変更します。タブがアクティブと非アクティブの状態で色が分かれるようになっています。加えて、非アクティブのタブでもどのディレクトリにいるのかがわかります。そのため、タブを選択するにしてもすぐに移動できます。

~/.config/wezterm/wezterm.lua
-- タブの形をカスタマイズ
-- タブの左側の装飾
local SOLID_LEFT_ARROW = wezterm.nerdfonts.ple_lower_right_triangle
-- タブの右側の装飾
local SOLID_RIGHT_ARROW = wezterm.nerdfonts.ple_upper_left_triangle

wezterm.on("format-tab-title", function(tab, tabs, panes, config, hover, max_width)
  local background = "#5c6d74"
  local foreground = "#FFFFFF"
  local edge_background = "none"
  if tab.is_active then
    background = "#ae8b2d"
    foreground = "#FFFFFF"
  end
  local edge_foreground = background
  local pane = tab.active_pane
  local pane_id = pane.pane_id

  local cwd = "none"
  if title_cache[pane_id] then
    cwd = title_cache[pane_id]
  else
    cwd = "-"
  end

  local title = " " .. wezterm.truncate_right(tab.active_pane.title, max_width - 1) .. " [ " .. cwd .. " ] "
  return {
    { Background = { Color = edge_background } },
    { Foreground = { Color = edge_foreground } },
    { Text = SOLID_LEFT_ARROW },
    { Background = { Color = background } },
    { Foreground = { Color = foreground } },
    { Text = title },
    { Background = { Color = edge_background } },
    { Foreground = { Color = edge_foreground } },
    { Text = SOLID_RIGHT_ARROW },
  }
end)


タブの見た目を変更

最後に、タブの位置を下側に変更します。(後になって、macだとMission Controlが被ってきて操作しづらくなるので、このオプションはオフにしました。

~/.config/wezterm/wezterm.lua
-- タブを下に表示
config.tab_bar_at_bottom = true


タブの位置を変更

タブの移動に関しても以下の設定を加えます。デフォルトでは⌘ + Shift + [で左方向、⌘ + Shift + ]で右方向に移動できます。ただ、「ShiftとCtrlとどっちだっけ・・?」と悩むことが多々あったので、⌘ + Ctrl + [⌘ + Ctrl + ]でタブの移動ができるように修正しています。

local act = wezterm.action

config.keys = {
    -- ⌘ Ctrl [] でタブの移動
    -- defaultは⌘ Shift []
    {
        key = '[',
        mods = 'CMD|CTRL',
        action = act.ActivateTabRelative(-1)
    },
    {
        key = ']',
        mods = 'CMD|CTRL',
        action = act.ActivateTabRelative(1)
    }
}

これにて、WezTermの設定はひとまず完了です。タブごとに起動してるディレクトリもわかりやすいので、使い勝手は良いです。見た目などは参考にした記事をほぼコピーした内容になっていますが・・・。誰かの参考になれば幸いです。

最後に、現時点でのファイル全体を置いておきます。これからも設定を追記していって使いやすいようにしていきたいです。

~/.config/wezter/wezterm.luaの全体
~/.config/wezter/wezterm.lua
-- Pull in the wezterm API
local wezterm = require 'wezterm'

-- This table will hold the configuration.
local config = wezterm.config_builder()


----------------------------------------------------
-- Window
----------------------------------------------------

config.color_scheme = 'Wombat'

-- 背景の非透過率(1なら完全に透過させない)
config.window_background_opacity = 0.70
config.macos_window_background_blur = 20

config.default_cursor_style = 'BlinkingBar'
config.cursor_blink_rate = 1000
config.cursor_blink_ease_in = "Linear"
config.cursor_blink_ease_out = "Linear"

config.enable_scroll_bar = true

config.font = wezterm.font('JetBrains Mono', { weight = 'Bold' })
config.font_size = 14.0
config.command_palette_font_size = 14.0
config.command_palette_bg_color = '#4D07FF'

config.window_frame = {
	font = wezterm.font('JetBrains Mono', { weight = 'Bold' }),
	font_size = 14,
}


----------------------------------------------------
-- Tab
----------------------------------------------------
-- タイトルバーを非表示
config.window_decorations = "RESIZE"
-- タブの追加ボタンを非表示
config.show_new_tab_button_in_tab_bar = false
-- タブが一つしかない時に非表示
config.hide_tab_bar_if_only_one_tab = true
-- nightlyのみ使用可能
-- タブの閉じるボタンを非表示
-- config.show_close_tab_button_in_tabs = false

-- タブ同士の境界線を非表示
config.colors = {
  tab_bar = {
    inactive_tab_edge = "none",
  },
}


function split(str, ts)
  -- 引数がないときは空tableを返す
  if ts == nil then return {} end

  local t = {} ;
  i=1
  for s in string.gmatch(str, "([^"..ts.."]+)") do
    t[i] = s
    i = i + 1
  end

  return t
end

-- 各タブの「ディレクトリ名」を記憶しておくテーブル
local title_cache = {}

wezterm.on('update-status', function(window, pane)
  local pane_id = pane:pane_id()
  title_cache[pane_id] = "-"
  local process_info = pane:get_foreground_process_info()

  if process_info then
    local cwd = process_info.cwd
    local rm_home = string.gsub(cwd, os.getenv 'HOME', '')
    local prj = string.gsub(rm_home, '/Development/Projects', '')
    local dirs = split(prj, '/')
    local root_dir = dirs[1]
    title_cache[pane_id] = root_dir
  end
end)


-- タブの形をカスタマイズ
-- タブの左側の装飾
local SOLID_LEFT_ARROW = wezterm.nerdfonts.ple_lower_right_triangle
-- タブの右側の装飾
local SOLID_RIGHT_ARROW = wezterm.nerdfonts.ple_upper_left_triangle

wezterm.on("format-tab-title", function(tab, tabs, panes, config, hover, max_width)
  local background = "#5c6d74"
  local foreground = "#FFFFFF"
  local edge_background = "none"
  if tab.is_active then
    background = "#ae8b2d"
    foreground = "#FFFFFF"
  end
  local edge_foreground = background
  local pane = tab.active_pane
  local pane_id = pane.pane_id

  local cwd = "none"
  if title_cache[pane_id] then
    cwd = title_cache[pane_id]
  else
    cwd = "-"
  end

  local title = " " .. wezterm.truncate_right(tab.active_pane.title, max_width - 1) .. " [ " .. cwd .. " ] "
  return {
    { Background = { Color = edge_background } },
    { Foreground = { Color = edge_foreground } },
    { Text = SOLID_LEFT_ARROW },
    { Background = { Color = background } },
    { Foreground = { Color = foreground } },
    { Text = title },
    { Background = { Color = edge_background } },
    { Foreground = { Color = edge_foreground } },
    { Text = SOLID_RIGHT_ARROW },
  }
end)

----------------------------------------------------
-- Key Bindings
----------------------------------------------------

local act = wezterm.action

config.keys = {
    -- ⌘ w でペインを閉じる(デフォルトではタブが閉じる)
    {
        key = "w",
        mods = "CMD",
        action = wezterm.action.CloseCurrentPane { confirm = true },
    },
    -- ⌘ Ctrl oでペインの中身を入れ替える
    {
        key = "o",
        mods = "CMD|CTRL",
        action = wezterm.action.RotatePanes 'Clockwise'
    },
    -- ⌘ Enterで最大化・縮小化のトグル
    {
        key = 'Enter',
        mods = 'CMD',
        action = act.ToggleFullScreen
    },
    -- ⌘ Ctrl [] でタブの移動
    -- defaultは⌘ Shift []
    {
        key = '[',
        mods = 'CMD|CTRL',
        action = act.ActivateTabRelative(-1)
    },
    {
        key = ']',
        mods = 'CMD|CTRL',
        action = act.ActivateTabRelative(1)
    }
}

-- 最初からフルスクリーンで起動
local mux = wezterm.mux
wezterm.on("gui-startup", function(cmd)
    local tab, pane, window = mux.spawn_window(cmd or {})
    window:gui_window():toggle_fullscreen()
end)

-- タブを下に表示(デフォルトでは上にある)
config.tab_bar_at_bottom = true

return config

参考

https://zenn.dev/mozumasu/articles/mozumasu-wezterm-customization
https://qiita.com/showchan33/items/c91bb7f6f2b89e9ed57d
https://qiita.com/gp333/items/c472f7a7d9fcca1b5cb7

GitHubで編集を提案

Discussion