Skip to content

Instantly share code, notes, and snippets.

@Broderick-Westrope
Last active March 4, 2024 08:26
Show Gist options
  • Save Broderick-Westrope/8030cff3c605924ee249ca780ed091d9 to your computer and use it in GitHub Desktop.
Save Broderick-Westrope/8030cff3c605924ee249ca780ed091d9 to your computer and use it in GitHub Desktop.
wezterm config
local wezterm = require("wezterm")
local session_manager = {}
--- Helper function to safely perform file operations and capture errors.
local function safe_file_operation(func, ...)
local success, result_or_error = pcall(func, ...)
if not success then
wezterm.log_info("File operation error: " .. tostring(result_or_error))
return false, result_or_error
end
return true, result_or_error
end
--- Helper function to construct the file path for saving and loading session states.
local function construct_file_path(workspace_name)
return wezterm.home_dir .. "/.config/wezterm/wezterm-session-manager/wezterm_state_" .. workspace_name .. ".json"
end
--- Retrieves the current workspace data from the active window.
local function retrieve_workspace_data(window)
local workspace_name = window:active_workspace()
local workspace_data = {
name = workspace_name,
tabs = {}
}
for _, tab in ipairs(window:mux_window():tabs()) do
local tab_data = {
tab_id = tostring(tab:tab_id()),
panes = {}
}
for _, pane_info in ipairs(tab:panes_with_info()) do
table.insert(tab_data.panes, {
pane_id = tostring(pane_info.pane:pane_id()),
index = pane_info.index,
is_active = pane_info.is_active,
is_zoomed = pane_info.is_zoomed,
left = pane_info.left,
top = pane_info.top,
width = pane_info.width,
height = pane_info.height,
pixel_width = pane_info.pixel_width,
pixel_height = pane_info.pixel_height,
cwd = tostring(pane_info.pane:get_current_working_dir()),
tty = tostring(pane_info.pane:get_foreground_process_name())
})
end
table.insert(workspace_data.tabs, tab_data)
end
return workspace_data
end
--- Saves data to a JSON file.
local function save_to_json_file(data, file_path)
-- Attempt to open the file for writing and check for success
local success, file_or_error = safe_file_operation(io.open, file_path, "w")
if not success then
wezterm.log_info("Failed to open file for writing: " .. tostring(file_or_error))
return false
end
-- If successful, 'file_or_error' will be the file handle
local file = file_or_error
-- Now attempt to write the data to the file
success, file_or_error = safe_file_operation(file.write, file, wezterm.json_encode(data))
if not success then
wezterm.log_info("Failed to write to file: " .. tostring(file_or_error))
-- Ensure the file is closed even if writing fails
file:close()
return false
end
-- Close the file after writing is successful
file:close()
return true
end
--- Loads data from a JSON file.
local function load_from_json_file(file_path)
local file, err = safe_file_operation(io.open, file_path, "r")
if not file then
wezterm.log_info("Failed to open file: " .. tostring(err))
return nil
end
local content, err = safe_file_operation(file.read, file, "*a")
if not content then
wezterm.log_info("Failed to read file: " .. tostring(err))
return nil
end
file:close()
local data, err = safe_file_operation(wezterm.json_parse, content)
if not data then
wezterm.log_info("Failed to parse JSON: " .. tostring(err))
return nil
end
return data
end
--- Recreates the workspace based on the provided data.
local function recreate_workspace(window, workspace_data)
-- Detailed implementation as previously discussed...
end
--- Orchestrator function to save the current workspace state.
function session_manager.save_state(window)
local data = retrieve_workspace_data(window)
local file_path = construct_file_path(data.name)
if save_to_json_file(data, file_path) then
window:toast_notification('WezTerm Session Manager', 'Workspace state saved successfully', nil, 4000)
else
window:toast_notification('WezTerm Session Manager', 'Failed to save workspace state', nil, 4000)
end
end
--- Allows selecting which workspace to load.
function session_manager.load_state(window)
local sessions_dir = wezterm.home_dir .. "/.config/wezterm/wezterm-session-manager/"
local entries, err = wezterm.read_dir(sessions_dir)
if not entries then
wezterm.log_info("Error reading sessions directory: " .. tostring(err))
return
end
local items = {}
for _, entry in ipairs(entries) do
if not entry then
wezterm.log_error("Encountered an invalid entry in sessions directory")
goto continue
end
-- Extract the filename from the entry path
local filename = entry:match("^.+[/\\](.+)$")
if not filename then
wezterm.log_error("Could not extract filename from entry: " .. entry)
goto continue
end
-- Now use 'filename' for matching and manipulation
if filename:match("^wezterm_state_.*%.json$") then
table.insert(items, {
label = filename:gsub("^wezterm_state_(.*)%.json$", "%1"),
file_path = sessions_dir .. filename,
})
else
-- Log skipping files that do not match the session file pattern
wezterm.log_info("Skipping non-session file: " .. filename)
end
::continue::
end
if #items == 0 then
window:toast_notification("WezTerm Session Manager", "No saved sessions found.", nil, 4000)
return
end
window:show_overlay(wezterm.gui.overlay.new_selection_window({
items = items,
on_select = function(item)
if not item then
wezterm.log_error("Item is nil in on_select")
return
end
if not item.file_path or not item.label then
wezterm.log_error("Item missing expected fields in on_select: " .. wezterm.json_encode(item))
return
end
local workspace_data = load_from_json_file(item.file_path)
if workspace_data then
recreate_workspace(window, workspace_data)
window:toast_notification("WezTerm Session Manager", "Session " .. item.label .. " loaded successfully.", nil,
4000)
else
window:toast_notification("WezTerm Session Manager", "Failed to load session " .. item.label, nil, 4000)
end
end,
}))
end
return session_manager
-- This script depends on:
-- - WezTerm Session Manager (https://github.com/danielcopper/wezterm-session-manager)
local wezterm = require("wezterm")
local session_manager = require("wezterm-session-manager")
local config = wezterm.config_builder()
local bgColor = "#050014"
-- Color Scheme
local scheme = wezterm.color.get_builtin_schemes()["Tokyo Night Moon"]
scheme.background = bgColor
config.color_schemes = {
["My Custom Scheme"] = scheme
}
config.color_scheme = "My Custom Scheme"
-- Font
config.font_size = 18
config.font = wezterm.font("FiraCode Nerd Font Mono")
-- Tab Appearance
config.use_fancy_tab_bar = false
config.hide_tab_bar_if_only_one_tab = true
config.colors = {
tab_bar = {
background = bgColor,
active_tab = {
bg_color = bgColor,
fg_color = scheme.ansi[6]
},
inactive_tab = {
bg_color = bgColor,
fg_color = scheme.brights[8]
},
inactive_tab_hover = {
bg_color = bgColor,
fg_color = scheme.ansi[6]
},
new_tab = {
bg_color = bgColor,
fg_color = scheme.ansi[8]
},
new_tab_hover = {
bg_color = bgColor,
fg_color = scheme.ansi[6]
}
}
}
config.window_decorations = "RESIZE"
local process_icons = {
['docker'] = wezterm.nerdfonts.linux_docker,
['docker-compose'] = wezterm.nerdfonts.linux_docker,
['psql'] = '󱤢',
['usql'] = '󱤢',
['kuberlr'] = wezterm.nerdfonts.linux_docker,
['ssh'] = wezterm.nerdfonts.fa_exchange,
['ssh-add'] = wezterm.nerdfonts.fa_exchange,
['kubectl'] = wezterm.nerdfonts.linux_docker,
['stern'] = wezterm.nerdfonts.linux_docker,
['nvim'] = wezterm.nerdfonts.custom_vim,
['make'] = wezterm.nerdfonts.seti_makefile,
['vim'] = wezterm.nerdfonts.dev_vim,
['node'] = wezterm.nerdfonts.mdi_hexagon,
['go'] = wezterm.nerdfonts.seti_go,
['zsh'] = wezterm.nerdfonts.dev_terminal,
['bash'] = wezterm.nerdfonts.cod_terminal_bash,
['btm'] = wezterm.nerdfonts.mdi_chart_donut_variant,
['htop'] = wezterm.nerdfonts.mdi_chart_donut_variant,
['cargo'] = wezterm.nerdfonts.dev_rust,
['sudo'] = wezterm.nerdfonts.fa_hashtag,
['lazydocker'] = wezterm.nerdfonts.linux_docker,
['lazygit'] = wezterm.nerdfonts.dev_git,
['git'] = wezterm.nerdfonts.dev_git,
['lua'] = wezterm.nerdfonts.seti_lua,
['wget'] = wezterm.nerdfonts.mdi_arrow_down_box,
['curl'] = wezterm.nerdfonts.mdi_flattr,
['gh'] = wezterm.nerdfonts.dev_github_badge,
['ruby'] = wezterm.nerdfonts.cod_ruby,
}
local function get_current_working_dir(tab)
local current_dir = tab.active_pane and tab.active_pane.current_working_dir or {
file_path = ''
}
local HOME_DIR = string.format('file://%s', os.getenv('HOME'))
return current_dir == HOME_DIR and '.' or string.gsub(current_dir.file_path, '(.*[/\\])(.*)', '%2')
end
local function get_process(tab)
if not tab.active_pane or tab.active_pane.foreground_process_name == '' then
return '[?]'
end
local process_name = string.gsub(tab.active_pane.foreground_process_name, '(.*[/\\])(.*)', '%2')
if string.find(process_name, 'kubectl') then
process_name = 'kubectl'
end
return process_icons[process_name] or string.format('[%s]', process_name)
end
wezterm.on('format-tab-title', function(tab, tabs, panes, config, hover, max_width)
local has_unseen_output = false
if not tab.is_active then
for _, pane in ipairs(tab.panes) do
if pane.has_unseen_output then
has_unseen_output = true
break
end
end
end
local cwd = wezterm.format({ {
Attribute = {
Intensity = 'Bold'
}
}, {
Text = get_current_working_dir(tab)
} })
local title = string.format(' %s ~ %s ', get_process(tab), cwd)
if has_unseen_output then
return {
{
Foreground = {
Color = scheme.ansi[5]
}
},
{
Text = title
} }
end
return { {
Text = title
} }
end)
config.tab_max_width = 60
config.default_cursor_style = 'SteadyUnderline'
config.command_palette_font_size = 18
config.command_palette_bg_color = bgColor
wezterm.on("save_session", function(window) session_manager.save_state(window) end)
wezterm.on("load_session", function(window) session_manager.load_state(window) end)
wezterm.on("restore_session", function(window) session_manager.restore_state(window) end)
config.leader = { key = 'a', mods = 'CTRL', timeout_milliseconds = 3000 }
config.keys = {
-- Send "CTRL-A" to the terminal when pressing CTRL-A, CTRL-A
{
key = 'a',
mods = 'LEADER|CTRL',
action = wezterm.action.SendKey { key = 'a', mods = 'CTRL' },
},
{ key = "S", mods = "LEADER", action = wezterm.action { EmitEvent = "save_session" } },
{ key = "L", mods = "LEADER", action = wezterm.action { EmitEvent = "load_session" } },
{ key = "R", mods = "LEADER", action = wezterm.action { EmitEvent = "restore_session" } },
-- Make Option-Left equivalent to Alt-b which many line editors interpret as backward-word
{ key = "LeftArrow", mods = "OPT", action = wezterm.action { SendString = "\x1bb" } },
-- Make Option-Right equivalent to Alt-f; forward-word
{ key = "RightArrow", mods = "OPT", action = wezterm.action { SendString = "\x1bf" } }
}
-- and finally, return the configuration to wezterm
return config
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment