最強のターミナル環境を求めた結果、WezTermに落ち着きそうな話
WezTermはいいぞ。
Zellijもいいぞ。
最強のターミナル環境を作りたい
Hyperを使っていましたが、タブ/ペイン周りがもうちょっと操作しやすいといいなあ & Ctrl-Cでコピーしたいなあということで色々あさり始めた。
どんなターミナルがほしいのか
- タブ/ペインが操作しやすい
- Ctrl-Cでコピーできる
- それなりにデザインがいい
- 背景透過できる
- 高速
Alacrittyを試してみる
- Rust製のモダンなターミナル
- 設定はtomlで記述
- タブ等はない
タブの代わりにtmuxなどのターミナルマルチプレクサを組み合わせて使うらしい。
ターミナルマルチプレクサについてもいろいろ調べてみたところ、Zellijというのが初心者フレンドリーで良さそう。
さっそくZellijとAlacrittyを組み合わせて使ってみたところ、Zellijの使い心地が思った以上に良かった。Alacrittyも高速動作でいい感じだった。ただ、Ctrl-CでコピーするためにZellij側の設定でcopy_on_select
をオフにしてCtrl-Cでコピーするようなキーバインドを設定してみたところ、こんどは強制終了のCtrl-Cが使えなくなることになってしまった。
WezTermを試してみる
- Rust製のモダンなターミナル
- 設定はLuaで記述
Alacrittyの情報を調べていたらWezTermというのが良いという話も見かけたので、試してみることにした。環境変数にLANG=ja_JP.UTF-8
を設定することで日本語のインライン入力ができた。設定がLuaなので柔軟に設定できるのも強い。
Ctrl-Cでコピーする機能も標準では無いものの
{
key = 'c',
mods = 'CTRL',
action = wezterm.action_callback(function(window, pane)
selection_text = window:get_selection_text_for_pane(pane)
is_selection_active = string.len(selection_text) ~= 0
if is_selection_active then
window:perform_action(wezterm.action.CopyTo('ClipboardAndPrimarySelection'), pane)
else
window:perform_action(wezterm.action.SendKey{ key='c', mods='CTRL' }, pane)
end
end),
}
引用: wez/wezterm#606
のように、「選択文字列の文字数が0なら普通にCtrl-Cを送信、そうでなければコピー」という処理を書くことで解決できた。良すぎる。
ただ、不満な点もあった。タブのデザインを変えたいと思ったのだが、これは設定でいじれる部分にも限界があった。
そこで、いっそWezTermのタブ/ペイン機能をすべて切り、Zellijと組み合わせて使うことにした。
しかし、ここでも問題が発生した。WezTermとZellijを組み合わせて使うと、さっきのCtrl-C設定のwindow:get_selection_text_for_pane(pane)
が正常に動かないらしく、常に空文字列が返ってくるようになっていた。これによって、常に選択文字列がないと判定され、コピーができなくなってしまった。
悩んだ結果、Zellij側でコピーのコマンドにAlt-C
を設定し、WezTerm側で
c.keys = {
{
key = 'c',
mods = 'CTRL',
action = wezterm.action_callback(function(window, pane)
window:perform_action(wezterm.action.SendKey{ key='c', mods='ALT' }, pane)
window:perform_action(wezterm.action.SendKey{ key='c', mods='CTRL' }, pane)
end),
}
}
とすることで「Ctrl-Cを押したらCtrl-CとAlt-Cを同時に押したことにする」という脳筋名案を思いついた。こうすることで、文字列のコピーもプロセスの強制終了も両方可能になる。もちろん、プロセスの実行中にコピーしようとするとコピーと強制終了が同時に起こってしまうが、その時だけAlt-Cを使えばいいということで妥協した。
作った設定ファイル全体
local wezterm = require('wezterm')
local c = wezterm.config_builder()
c.font = wezterm.font_with_fallback({
{family="Roboto Mono", weight="Regular"},
{family="Noto Sans JP", weight="Regular"},
})
c.font_size = 10.5
c.color_scheme = "OneHalfDark"
c.adjust_window_size_when_changing_font_size = false
c.default_cursor_style = "SteadyBar"
c.window_background_opacity = 0.9
c.window_close_confirmation = 'NeverPrompt'
c.use_fancy_tab_bar = false
c.show_tab_index_in_tab_bar = false
c.enable_tab_bar = false
c.window_padding = {
left = 0,
right = 0,
top = 0,
bottom = 0,
}
c.disable_default_key_bindings = true
c.default_prog = {"fish", "-l", "-c", "zellij attach --index 0 --create"}
c.keys = {
{
key = 'c',
mods = 'CTRL',
action = wezterm.action_callback(function(window, pane)
window:perform_action(wezterm.action.SendKey{ key='c', mods='ALT' }, pane)
window:perform_action(wezterm.action.SendKey{ key='c', mods='CTRL' }, pane)
end),
}
}
wezterm.on('format-window-title', function(tab, pane, tabs, panes, config)
return "WezTerm"
end)
return c
追記
上記の設定で妥協したつもりだったが、やはりWezTermとZellijは相性が悪いらしく、何かと競合してしまい使い勝手が悪くなってしまった。
今はZellijを使わずWezTermだけで運用している
タブのデザインについてはLuaでゴリ押すことでもそれなりに解決できることがわかった。
タブ関連の設定
local wezterm = require('wezterm')
local act = wezterm.action
local c = wezterm.config_builder()
local ARROW = wezterm.nerdfonts.pl_left_hard_divider
local FILLED_BLOCK = '█'
local GREEN = "#98c379"
local GRAY = "#abb2bf"
local BLACK = "#1e222a"
local BG = "#282c34"
c.use_fancy_tab_bar = false
c.show_tab_index_in_tab_bar = false
c.show_new_tab_button_in_tab_bar = false
c.colors = {
tab_bar = {
background = BG,
active_tab = {
bg_color = GREEN,
fg_color = BLACK,
intensity = "Normal",
underline = "None",
italic = false,
strikethrough = false,
},
inactive_tab = {
bg_color = GRAY,
fg_color = BLACK,
intensity = "Normal",
underline = "None",
italic = false,
strikethrough = false,
},
inactive_tab_hover = {
bg_color = GRAY,
fg_color = BLACK,
intensity = "Normal",
underline = "None",
italic = false,
strikethrough = false,
},
}
}
wezterm.on('format-tab-title', function(tab, tabs, panes, config, hover, max_width)
local edge_background = BG
local edge_foreground = GRAY
local background = GRAY
local foreground = BLACK
if tab.is_active then
background = GREEN
edge_foreground = GREEN
end
title = 'Tab #' .. tab.tab_index
return {
{ Background = { Color = edge_foreground } },
{ Foreground = { Color = edge_background } },
{ Text = ARROW },
{ Background = { Color = edge_background } },
{ Foreground = { Color = edge_foreground } },
{ Text = FILLED_BLOCK },
{ Background = { Color = background } },
{ Foreground = { Color = foreground } },
{ Text = title },
{ Background = { Color = edge_background } },
{ Foreground = { Color = edge_foreground } },
{ Text = FILLED_BLOCK },
{ Background = { Color = edge_background } },
{ Foreground = { Color = edge_foreground } },
{ Text = ARROW },
}
end)
おまけ
ウィンドウを最前面に表示したい
Alt-Spaceを押したときのメニューで「最前面に維持する」を選ぶと最前面に維持できる。
コマンドでやるにはwmctrlというツールを使ってwmctrl -r :ACTIVE: -b toggle,above
とかやってやればいい......はずなのだがなぜかこれでは動かず、
実際にはbash -c 'wmctrl -r :ACTIVE: -b $([[ $(xprop -id $(xprop -root -f _NET_ACTIVE_WINDOW 0x " \$0\\n" _NET_ACTIVE_WINDOW | awk "{print \$2}") _NET_WM_STATE) =~ "ABOVE" ]] && echo "remove" || echo "add"),above'
(https://askubuntu.com/questions/1008199/wmctrl-ubuntu-17-10-toggle-above-not-toggling-down から引用)とか書いてやる必要があるらしい。無情。
とにかく、このコマンドをOSのショートカットキー機能などにぶちこんでやると好きなショートカットでこのコマンドを呼べるようになり便利。
ターミナルを任意のショートカットキーで呼び出したい
WezTerm側の設定で
wezterm.on('format-window-title', function(tab, pane, tabs, panes, config)
return "WezTerm"
end)
としてウィンドウのタイトルを"WezTerm"に固定したうえで
OSのショートカットキー機能にwmctrl -F -a WezTerm
Discussion