WezTermでターミナルを自分なりのデザインにしよう![Mac向け]

みなさん、ターミナル何を使っていますか？

今までは[`warp`](https://www.warp.dev/)を使っていたのですが、日本語入力した場合に確定するまで文字が表示されないのでとても不便に思っていました。

今回weztermのセットアップと以下のようなweztermのデザインにしたので、それをご紹介したいと思います。

![スクリーンショット 2024-10-12 7.14.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/6f45a2f7-73e2-e294-ba6b-119dc6e45ef4.png)


# weztermとは

`Wezterm`は、Rust 製のターミナルエミュレータです。

クロスプラットフォームで、Linux, MacOS, Windows OSのすべての環境で動作して、luaという言語で設定を共有することが可能なのが魅力なターミナルです。

https://wezfurlong.org/wezterm/index.html

# weztermをインストール

今回は`nightly build`を使用します。

```
brew install --cask wezterm@nightly
```

:::note
nightly buildはソフトウェアの最新版を指します。
:::

# weztermの設定ファイルを作成する

weztermはluaという言語で設定を行うことができます。

ホームディレクトリの`.config/wezterm`ディレクトリを作成して、そこに`wezterm.lua`を作成しましょう.


## 設定ファイルを書く

`wezterm.lua`で下のように設定ファイルを書いてみました。

>長いので折りたたんでいます。

<details><summary>wezterm.lua</summary>

```wezterm.lua
local wezterm = require("wezterm")
local config = wezterm.config_builder()
local act = wezterm.action
local mux = wezterm.mux

-- カラー設定
local purple = '#9c7af2'
local blue = '#6EADD8'
local light_green = "#7dcd5d"
local orange = "#e19500"
local red = "#E50000"
local yellow = "#D7650C"

-- 基本設定
config.automatically_reload_config = true
config.window_close_confirmation = "NeverPrompt"
config.default_cursor_style = "BlinkingBar"

-- フォント設定
config.font = wezterm.font("JetBrains Mono", { weight = "Bold" })
config.font_size = 15

-- ウィンドウ設定
config.window_decorations = "RESIZE"
config.window_background_opacity = 0.75
config.macos_window_background_blur = 10
config.window_background_gradient = {
    colors = { "#000000" },
}

-- タブバー設定
config.show_new_tab_button_in_tab_bar = false
config.tab_bar_at_bottom = true
config.tab_max_width = 5
config.show_close_tab_button_in_tabs = false

-- ウィンドウフレーム設定
config.window_frame = {
    inactive_titlebar_bg = "none",
    active_titlebar_bg = "none",
}

-- カラー設定
config.colors = {
    foreground = 'silver',
    selection_fg = 'red',
    cursor_bg = blue,
    cursor_fg = "white",
    cursor_border = purple,
    tab_bar = {         
        inactive_tab_edge = "none",
    },
    ansi = {
        'black', red, purple, light_green, blue, yellow, 'teal', 'silver',
    },
    brights = {
        'grey', 'red', 'lime', 'yellow', 'blue', 'fuchsia', 'aqua', 'white',
    },
}

-- ショートカットキー設定

config.keys = {
	-- カーソルを一単語後ろに移動
  {
    key = "LeftArrow",
    mods = "CMD",
    action = act.SendKey {
      key = "b",
      mods = "META",
    },
  },
  -- カーソルを一単語前に移動
  {
    key = "RightArrow",
    mods = "CMD",
    action = act.SendKey {
      key = "f",
      mods = "META",
    },
  },
-- カーソルを一単語削除
  {
    key = "Backspace",
    mods = "CMD",--mac用
    action = act.SendKey {
      key = "w",
      mods = "CTRL",
    },
  },
}


-- イベントハンドラ
-- 起動時に画面を最大化
wezterm.on("gui-startup", function()
    local _, _, window = mux.spawn_window({})
    window:gui_window():maximize()
end)

-- タブタイトルのフォーマット
local SOLID_LEFT_ARROW = wezterm.nerdfonts.pl_right_hard_divider
local SOLID_RIGHT_ARROW = wezterm.nerdfonts.pl_left_hard_divider

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 = "#9c7af2"
	  foreground = "#FFFFFF"
	end
	
	local edge_foreground = background
	local title = tab.active_pane.title

	-- タイトルが長い場合は省略
	local function get_last_n_chars(str, n)
        if #str <= n then
            return str
        else
            return "…" .. string.sub(str, -n + 1)
        end
    end

	-- プロセス名に基づいてタイトルを取得する関数(nodeとかmakeとか表示)
    local function get_process_name(pane)
        local process_name = pane.foreground_process_name
	
    	return process_name:match("([^/]+)$") or ""

    end
	
    -- カスタムタイトルを取得する関数
    local function get_custom_title(pane)
        local process_name = get_process_name(pane)
		
    	-- if process_name == "make" then
		-- wezterm.log_info(process_name)
    	--    return "make"
	 	-- elseif process_name == "node" then
		-- 	return "node"
		if process_name ~= "zsh" then
			return process_name
        else
             return get_last_n_chars(title, 23)
         end

		return process_name
    end

    -- カスタムタイトルを取得
    local custom_title = get_custom_title(tab.active_pane)
	
	return {
		{ Background = { Color = edge_background } },
		{ Foreground = { Color = edge_foreground } },
		{ Text = SOLID_LEFT_ARROW },
	  { Background = { Color = background } },
	  { Foreground = { Color = foreground } },
	  { Text = " " .. (tab.tab_index + 1) .. ": " .. custom_title .. " " },
	  { Background = { Color = edge_background } },
	  { Foreground = { Color = edge_foreground } },
	  { Text = SOLID_RIGHT_ARROW },
	}
end)

return config

```

</details>

## 設定について詳しく解説

### カラー設定
カラー設定は以下のように設定しています。

```lua:wezterm.lua
local purple = '#9c7af2'
local blue = '#6EADD8'
local light_green = "#7dcd5d"
local orange = "#e19500"
local red = "#E50000"
local yellow = "#D7650C"

-- カラー設定
config.colors = {
    foreground = 'silver',
    selection_fg = 'red',
    cursor_bg = blue,
    cursor_fg = "white",
    cursor_border = purple,
    tab_bar = {         
        inactive_tab_edge = "none",
    },
    ansi = {
        'black', red, purple, light_green, blue, yellow, 'teal', 'silver',
    },
    brights = {
        'grey', 'red', 'lime', 'yellow', 'blue', 'fuchsia', 'aqua', 'white',
    },
}
```

カラースキーマは自分で設定しなくても、以下のドキュメントのようにかなりの数が用意されています。

https://wezfurlong.org/wezterm/colorschemes/index.html

### 基本設定
カテゴリとして分けづらい設定をしているものを基本設定としています。

```lua:wezterm.lua
-- 基本設定
config.automatically_reload_config = true 
config.window_close_confirmation = "NeverPrompt"
config.default_cursor_style = "BlinkingBar"
```

|設定|機能|
|---|---|
|config.automatically_reload_config|設定の自動ロード|
|config.window_close_confirmation|ウィンドウを閉じる際に確認をするかどうか|
|config.default_cursor_style|カーソルのスタイルを変更、"BlinkingBar"でカーソルを点滅|

https://wezfurlong.org/wezterm/config/lua/config/default_cursor_style.html

### フォント設定
フォントを設定しています。

```lua:wezterm.lua
-- フォント設定
config.font = wezterm.font("JetBrains Mono", { weight = "Bold" })
config.font_size = 15
```

|設定|機能|
|---|---|
|config.font = wezterm.font("JetBrains Mono", { weight = "Bold" })| フォントの種類とスタイルを設定|
|config.font_size = 15|フォントの大きさを設定|


### ウィンドウ設定

ウィンドウの設定を集めて設定しています。

```lua:wezterm.lua
-- ウィンドウ設定
config.window_decorations = "RESIZE"
config.window_background_opacity = 0.75
config.macos_window_background_blur = 10
config.window_background_gradient = {
    colors = { "#000000" },
}
```

|設定|機能|
|---|---|
|config.window_decorations|ウィンドウの装飾を変更、"RESIZE"はサイズを変更可能に|
|config.window_background_opacity|ウィンドウの背景の透明度|
|config.macos_window_background_blur|ウィンドウの背景のぼかし度合い|
|config.window_background_gradient|ウィンドウのグラデーション効果を設定しています。|

また下の方にイベントハンドラとして、起動時に画面を最大にするように設定しています。

```lua:wezterm.lua
-- イベントハンドラ
-- 起動時に画面を最大化
wezterm.on("gui-startup", function()
    local _, _, window = mux.spawn_window({})
    window:gui_window():maximize()
end)
```

### タブバー設定

タブバーに関する設定を行っています。

```lua:wezterm.lua
-- タブバー設定
config.show_new_tab_button_in_tab_bar = false
config.tab_bar_at_bottom = true
config.tab_max_width = 5
config.show_close_tab_button_in_tabs = false
```

|設定|機能|
|---|---|
|config.show_new_tab_button_in_tab_bar|新しいタブを開くボタンを表示するかどうか|
|config.tab_bar_at_bottom|タブを下に表示するかどうか|
|config.tab_max_width|1つのタブの最大幅|
|config.show_close_tab_button_in_tabs|新しいタブを開くボタンを表示するかどうか|

また下の方にイベントハンドラを設定しています。
これでタブの形を設定しています。

```lua:wezterm.lua
-- タブタイトルのフォーマット
local SOLID_LEFT_ARROW = wezterm.nerdfonts.pl_right_hard_divider
local SOLID_RIGHT_ARROW = wezterm.nerdfonts.pl_left_hard_divider

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 = "#9c7af2"
	  foreground = "#FFFFFF"
	end
	
	local edge_foreground = background
	local title = tab.active_pane.title

	-- タイトルが長い場合は省略
	local function get_last_n_chars(str, n)
        if #str <= n then
            return str
        else
            return "…" .. string.sub(str, -n + 1)
        end
    end

	-- プロセス名に基づいてタイトルを取得する関数(nodeとかmakeとか表示)
    local function get_process_name(pane)
        local process_name = pane.foreground_process_name
	
    	return process_name:match("([^/]+)$") or ""

    end
	
    -- カスタムタイトルを取得する関数
    local function get_custom_title(pane)
        local process_name = get_process_name(pane)
		
		if process_name ~= "zsh" then
			return process_name
        else
             return get_last_n_chars(title, 23)
         end

		return process_name
    end

    -- カスタムタイトルを取得
    local custom_title = get_custom_title(tab.active_pane)
	
	return {
		{ Background = { Color = edge_background } },
		{ Foreground = { Color = edge_foreground } },
		{ Text = SOLID_LEFT_ARROW },
	  { Background = { Color = background } },
	  { Foreground = { Color = foreground } },
	  { Text = " " .. (tab.tab_index + 1) .. ": " .. custom_title .. " " },
	  { Background = { Color = edge_background } },
	  { Foreground = { Color = edge_foreground } },
	  { Text = SOLID_RIGHT_ARROW },
	}
end)
```

### ウィンドウフレーム設定
こちらではウィンドウのフレームを設定しています。

今回は、タブの後ろを透明にするために設定しています。

```lua:wezterm.lua
-- ウィンドウフレーム設定
config.window_frame = {
    inactive_titlebar_bg = "none",
    active_titlebar_bg = "none",
}
```


|設定|機能|
|---|---|
|inactive_titlebar_bg|ウィンドウが非アクティブの時のウィンドウの状態を指定|
|active_titlebar_bg|ウィンドウがアクティブの時のウィンドウの状態を指定|



### ショートカットキー設定

標準のキー設定は下のコマンドで確認できます。
```zsh:zsh
wezterm show-keys
```

自分が主に使う標準ショートカットは以下の感じです。

|キー|機能|
|---|---|
|cmd+T|タブを複製|
|cmd+W|タブを消す|
|cmd+[number]|タブ移動|

そこからさらに指定をしています。

```lua:wezterm.lua
-- ショートカットキー設定

config.keys = {
	-- カーソルを一単語後ろに移動
  {
    key = "LeftArrow",
    mods = "CMD",
    action = act.SendKey {
      key = "b",
      mods = "META",
    },
  },
  -- カーソルを一単語前に移動
  {
    key = "RightArrow",
    mods = "CMD",
    action = act.SendKey {
      key = "f",
      mods = "META",
    },
  },
-- カーソルを一単語削除
  {
    key = "Backspace",
    mods = "CMD",--mac用
    action = act.SendKey {
      key = "w",
      mods = "CTRL",
    },
  },
}

```

設定は以下のようになっています。
|キー|機能|
|---|---|
|CMD+←|一単語後ろに|
|CMD+→|一単語前に|
|CMD+backspace|一単語削除|

# starshipを設定する

starshipとは、下のようにターミナルをおしゃれにできるツールです。

gitのブランチマークやdockerのマークなど色々設定できます。

![スクリーンショット 2024-09-28 13.56.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/b586abc3-eca8-d32a-c3d4-0b746ec5d19e.png)

https://starship.rs/ja-JP/

## starshipのセットアップ

```zsh:zsh
brew install starship
```

~/.zshrcに下記を記述します
```zsh:zsh
eval "$(starship init zsh)"
```

## starship.tomlを記述する。

`~/.config/starship`ディレクトリを作成して、`starship.toml`を作成します。

.zshrcに以下の文を追加します
```.zshrc
export STARSHIP_CONFIG="$HOME/.config/starship/starship.toml"
```

`starship.toml`を下のように設定します。

こちらも下のように折りたたんでいます。

<details><summary>starship.toml</summary>

```starship.toml
format = """
$directory\
$git_branch\
$git_status\
$fill\
$python\
$lua\
$nodejs\
$golang\
$haskell\
$rust\
$ruby\
$aws\
$docker_context\
$jobs\
$cmd_duration\
$line_break\
$character"""

add_newline = true
palette = "nord"

[directory]
style = 'bold fg:dark_blue'
format = '[$path ]($style)'
truncation_length = 3
truncation_symbol = '…/'
truncate_to_repo = false

[directory.substitutions]
'Documents' = '󰈙'
'Downloads' = ' '
'Music' = ' '
'Pictures' = ' '

[git_branch]
style = 'fg:green'
symbol = ' '
format = '[on](white) [$symbol$branch ]($style)'

[git_status]
style = 'fg:red'
format = '([$all_status$ahead_behind]($style) )'

[fill]
symbol = ' '

[python]
style = 'teal'
symbol = ' '
format = '[${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'
pyenv_version_name = true
pyenv_prefix = ''

[lua]
format = '[$symbol($version )]($style)'
symbol = ' '

[nodejs]
style = 'blue'
symbol = ' '

[golang]
style = 'blue'
symbol = ' '

[haskell]
style = 'blue'
symbol = ' '

[rust]
style = 'orange'
symbol = ' '

[ruby]
style = 'blue'
symbol = ' '

[package]
symbol = '󰏗 '

[aws]
symbol = ' '
style = 'yellow'
format = '[$symbol($profile )(\[$duration\] )]($style)'

[docker_context]
symbol = ' '
style = 'fg:#06969A'
format = '[$symbol]($style) $path'
detect_files = ['docker-compose.yml', 'docker-compose.yaml', 'Dockerfile']
detect_extensions = ['Dockerfile']

[jobs]
symbol = ' '
style = 'red'
number_threshold = 1
format = '[$symbol]($style)'

[cmd_duration]
min_time = 500
style = 'fg:gray'
format = '[$duration]($style)'

[palettes.nord]
dark_blue = '#5E81AC'
blue = '#81A1C1'
teal = '#88C0D0'
red = '#BF616A'
orange = '#D08770'
green = '#A3BE8C'
yellow = '#EBCB8B'
purple = '#B48EAD'
gray = '#434C5E'
black = '#2E3440'
white='#D8DEE9'

[palettes.onedark]
dark_blue='#61afef'
blue='#56b6c2'
red='#e06c75'
green='#98c379'
purple='#c678dd'
cyan='#56b6c2'
orange='#be5046'
yellow='#e5c07b'
gray='#828997'
white ='#abb2bf'
black='#2c323c'
```
</details>


# .gitconfigをいじる

`.gitconfig`で、gitdiff等の色を変更します。

```.gitconfig
[color "status"]
	added = red
	changed = yellow blink
	untracked = yellow reverse
	deleted = magenta
```

こちらの記事で本当に少し詳しめに紹介しています。

https://qiita.com/maooz4426/items/056f7949801cad223a80

:::note

### .gitconfigの色の設定における注意点
色の設定は、weztermのカラースキーマに対応しています。

以下のコードのコメントアウトを参考にしてください。

```lua
 ansi = {
        'black',          -- 0: Black
        custom.red,      -- 1: Custom Red
        custom.purple,   -- 2: Custom Purple
        custom.light_green, -- 3: Custom Light Green
        custom.blue,     -- 4: Custom Blue
        custom.yellow,   -- 5: Custom Yellow
        'teal',           -- 6: Custom Cyan
        'silver',         -- 7: Custom White
      },
      brights = {
        'grey',     -- 8: Custom Bright Black
        'red',      -- 9: Bright Red
        'lime',     -- 10: Custom Bright Green
        'yellow',   -- 11: Bright Yellow
        'blue',     -- 12: Bright Blue
        'fuchsia',  -- 13: Custom Bright Magenta
        'aqua',     -- 14: Custom Bright Cyan
        'white',    -- 15: Bright White
      },
```
:::

# zsh-autosuggestionsとzsh-syntax-highlightingをインストール

ターミナルの機能を便利にするプラグインを二つ入れようと思います。

|プラグイン|機能|
|---|---|
|zsh-autosuggestions|コマンド入力のhistoryから提案を出してくれる|
|zsh-syntax-highlighting|コマンドにシンタックスハイライトがいい感じに|

インストールは下記で行います。
```zsh:zsh
brew install zsh-autosuggestions
```

```zsh:zsh
brew install zsh-syntax-highlighting
```

そして`.zshrc`に以下の設定を記述します。

```.zshrc
source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh

source $(brew --prefix)/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
```

# カレントディレクトリをタブに表示する

今のままだとタブが`zsh`になっているので、その設定を変更します。

`.zshrc`に下のコードを設定しましょう。

```.zshrc
precmd() {
  print -Pn "\e]0;%~\a"
}
```

`print`はzshの組み込み関数で、Pオプションでプロンプトの表示が使えて、nオプションで最後の改行を消している。機能としてはechoと似ています。

それに対して、"\e]0;%~\a"を表示させてエスケープシーケンスを使用してタブの名前を変更させています。

>やり方がいまいちわからなくて、gptあたりに聞いたらわかったやつなので詳しい説明できる人いたら教えて欲しいです。

:::note
### もし設定が反映されない場合

.zshrcの設定が反映できていないかもしれません。下のコマンドを打ちましょう。

```.zshrc
source ~/.zshrc
```
:::

# 現在の設定

自分が使っているweztermのdotfileは以下リポジトリにあります。
よければ参考にしてください。

https://github.com/maooz4426/wezterm-dotfiles