wezterm.lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
-- https://wezfurlong.org/wezterm/config/files.html
-- https://alexplescan.com/posts/2024/08/10/wezterm/
-- https://github.com/wez/wezterm/issues/6112
-- https://github.com/wez/wezterm/issues/5754
local wezterm = require "wezterm"
local config = wezterm.config_builder() local action = wezterm.action
local mux = wezterm.mux
config.audible_bell = "Disabled"
config.check_for_updates = false -- managed by brew
config.set_environment_variables = {
PATH = '/opt/homebrew/bin:/usr/local/bin/:' .. os.getenv('PATH')
}
local function scheme_for_appearance(a)
return a:find("Dark") and "Catppuccin Macchiato" or "Catppuccin Latte"
end
config.font = wezterm.font { family = 'JetBrains Mono', weight = 'Medium', harfbuzz_features = { 'calt=0', 'clig=0', 'liga=0' } } config.font_size = 15.0
config.line_height = 1.0
config.bold_brightens_ansi_colors = true
config.color_scheme = scheme_for_appearance(wezterm.gui.get_appearance()) config.macos_window_background_blur = 20
config.window_background_opacity = 0.96
config.window_decorations = 'RESIZE|INTEGRATED_BUTTONS'
config.window_padding = { left = '0.5cell', right = '0.5cell', top = '1.5cell', bottom = '0.5cell' } config.enable_tab_bar = true
config.use_fancy_tab_bar = false
config.tab_bar_at_bottom = true
config.tab_max_width = 32
config.show_new_tab_button_in_tab_bar = false
-- config.hide_tab_bar_if_only_one_tab = true -- sometimes procude wrong window size on maximize config.default_cursor_style = 'BlinkingBar'
config.animation_fps = 1
config.cursor_blink_rate = 500
config.prefer_egl = true
config.max_fps = 60
config.enable_scroll_bar = true
config.scrollback_lines = 10000
-- makes wezterm to work like tmux; see also: https://bower.sh/zmx-session-persistence
config.default_gui_startup_args = { 'connect', 'unix' }
config.window_close_confirmation = 'NeverPrompt'
local function maximize_window(window)
if not window.gui_window then return end
local screen = wezterm.gui.screens().active
local guiwin = window:gui_window()
if not screen or not guiwin then return end
-- window:gui_window():maximize() -- have long animation
guiwin:set_position(screen.x, screen.y)
guiwin:set_inner_size(screen.width, screen.height)
end
-- https://github.com/wez/wezterm/issues/3299#issuecomment-2145712082
wezterm.on("gui-startup", function(cmd)
local tab, pane, window = mux.spawn_window(cmd or {})
maximize_window(window)
end)
wezterm.on("gui-attached", function(window)
local workspace = mux.get_active_workspace()
for _, window in ipairs(mux.all_windows()) do
if window:get_workspace() == workspace then
maximize_window(window)
end
end
end)
wezterm.on("window-resized", function(window, pane)
maximize_window(window)
end)
-- see also https://wezterm.org/config/lua/wezterm/battery_info.html
wezterm.on("format-tab-title", function(tab, tabs, panes, config, hover, max_width) local title = (tab.tab_title ~= "" and tab.tab_title) or tab.active_pane.title
title = title:lower()
local prefix = tostring(tab.tab_index + 1) .. ":"
local width = math.max(1, max_width - (#prefix + 2))
title = wezterm.truncate_right(title, width)
return " " .. prefix .. title .. " "
end)
-- https://github.com/wezterm/wezterm/issues/1988#issuecomment-2462216249
local function search_cmd(window, pane)
window:perform_action(action.Search 'CurrentSelectionOrEmptyString', pane)
window:perform_action(action.Multiple {
action.CopyMode 'ClearPattern',
action.CopyMode 'ClearSelectionMode',
action.CopyMode 'MoveToScrollbackBottom'
}, pane)
end
config.keys = {
{ key = 'q', mods = 'CMD', action = wezterm.action.Nop }, -- prevent accidental quit
{ key = 't', mods = 'CMD', action = action.SpawnTab 'CurrentPaneDomain' },
{ key = 'd', mods = 'CMD', action = action.SplitHorizontal { domain = 'CurrentPaneDomain' } },
{ key = 'd', mods = 'CMD|SHIFT', action = action.SplitVertical { domain = 'CurrentPaneDomain' } },
{ key = 'k', mods = 'CMD', action = action.ClearScrollback 'ScrollbackAndViewport' },
{ key = 'w', mods = 'CMD', action = action.CloseCurrentPane { confirm = false } },
{ key = 'w', mods = 'CMD|SHIFT', action = action.CloseCurrentTab { confirm = false } },
{ key = 'a', mods = 'CMD', action = action.SelectTextAtMouseCursor 'SemanticZone', },
{ key = 'LeftArrow', mods = 'CMD', action = action.SendKey { key = 'Home' } },
{ key = 'RightArrow', mods = 'CMD', action = action.SendKey { key = 'End' } },
{ key = 'Backspace', mods = 'CMD', action = action.SendKey({ mods = "CTRL", key = "u" }) },
{ key = 'Backspace', mods = 'OPT', action = action.SendKey({ mods = "CTRL", key = "w" }) },
{ key = 'P', mods = 'CMD|SHIFT', action = action.ActivateCommandPalette },
{ key = 'f', mods = 'CMD', action = wezterm.action_callback(search_cmd) },
{ key = ',', mods = 'CMD', action = action.SpawnCommandInNewTab { cwd = wezterm.home_dir, args = { 'code', wezterm.config_file } } },
{ key = 'E', mods = 'CMD|SHIFT', action = action.PromptInputLine {
description = 'Enter tab title (empty to unset):',
action = wezterm.action_callback(function(window, _, line)
window:active_tab():set_title(line)
end),
}},
}
config.mouse_bindings = {
{ event = { Up = { streak = 1, button = "Left" } }, mods = "NONE", action = action.Nop },
{ event = { Up = { streak = 1, button = "Left" } }, mods = "CMD", action = action.OpenLinkAtMouseCursor },
-- Disable CMD + LeftClick window drag (make it behave like normal select)
-- { event = { Drag = { streak = 1, button = 'Left' } }, mods = "CMD", action = action.Nop },
{ event = { Drag = { streak = 1, button = "Left" } }, mods = "CMD", action = action.ExtendSelectionToMouseCursor("Cell") },
}
-- https://code.visualstudio.com/docs/configure/command-line#_opening-vs-code-with-urls
-- path-symbols: [\w@\.\/\-\[\]\(\)]
local function path_exists(path)
local ok, _, _ = wezterm.run_child_process { "test", "-e", path }
return ok
end
config.hyperlink_rules = wezterm.default_hyperlink_rules()
-- config.hyperlink_rules = {}
table.insert(config.hyperlink_rules, {
regex = [[((?:[\w@\.\/\-\[\]\(\)]+\/)+[\w@\.\/\-\[\]\(\)]+\.\w+)\b]],
format = "vscode://file/$PWD/$1",
highlight = 1,
})
table.insert(config.hyperlink_rules, {
regex = [[((?:[\w@\.\/\-\[\]\(\)]+\/)+[\w@\.\/\-\[\]\(\)]+\.\w+):(\d+):(\d+)]],
format = "vscode://file/$PWD/$1:$2:$3",
highlight = 1,
})
wezterm.on("open-uri", function(window, pane, uri)
if uri:find("$PWD") then
local cwd_uri = pane:get_current_working_dir()
local before, after = uri:match("^(.-)$PWD/(.+)$")
wezterm.log_info(before, after, path_exists(after))
if path_exists(after) then
uri = before .. after
else
uri = uri:gsub("$PWD", cwd_uri.file_path)
end
wezterm.log_info(uri)
wezterm.open_with(uri)
return false
end
return true end)
return config