WezTerm Configuration 1: Projects Selector
In this post I’ll add my configuration for WezTerm. At the end, it will look like this:

Setting up keybindings
The first step is to add a key binding. In our case, it will be LEADER + p where LEADER will be mapped to
CTRL + a.
In your .wezterm.lua file add:
1local wezterm = require("wezterm")
2local config = wezterm.config_builder()
3
4config.leader = { key = "a", mods = "CTRL", timeout_milliseconds = 2000 }
5config.keys = {
6 {
7 mods = "LEADER",
8 key = "p",
9 action = wezterm.action_callback(function(window, pane)
10 end),
11 },
12}
With this configuration, now you’ll be able to type CTRL + a then p and it will… not do nothing.
In order for this configuration to actually do something, we need more code. Add a new file in the same
folder where your .wezterm.lua file is located called utils.lua. In this file, add the following code:
1local M = {}
2
3M.get_directories = function(path, level)
4 local directories = {}
5 level = level or 0
6 if level > 1 then
7 return directories
8 end
9
10 -- Use safer path handling
11 local sanitized_path = string.gsub(path, '"', '\\"')
12 local p = io.popen('find "' .. sanitized_path .. '" -maxdepth 1 -mindepth 1 \\( -type d -o -type l \\)')
13
14 if not p then
15 wezterm.log_warn("Failed to open directory: " .. path)
16 return directories
17 end
18
19 for file in p:lines() do
20 local dir_name = file:match("([^/]+)$")
21 if dir_name then
22 table.insert(directories, {
23 label = file,
24 id = dir_name,
25 })
26
27 -- Recursively get subdirectories
28 local subdirs = M.get_directories(file, level + 1)
29 for _, subdir in ipairs(subdirs) do
30 table.insert(directories, subdir)
31 end
32 end
33 end
34
35 p:close()
36 return directories
37end
38
39M.open_project = function(window, _, id, label)
40 local mux = wezterm.mux
41
42 if not label then
43 wezterm.log_info("Project selection cancelled")
44 return
45 end
46
47 wezterm.emit("tab-changed", window)
48
49 local workspace = label:match("([^/]+)/[^/]+$")
50
51 -- Find existing window for workspace
52 local target_window = nil
53 for _, win in ipairs(mux.all_windows()) do
54 if win:get_workspace() == workspace then
55 target_window = win
56 break
57 end
58 end
59
60 -- Create new window if needed
61 if not target_window then
62 local _, _, new_window = mux.spawn_window({
63 cwd = label,
64 workspace = workspace,
65 })
66 target_window = new_window
67 target_window:set_title(workspace)
68
69 -- Set title for initial tab
70 local tabs = target_window:tabs()
71 for _, tab in ipairs(tabs) do
72 tab:set_title(id)
73 wezterm.log_info("Created new tab:", tab:get_title())
74 end
75 end
76
77 -- Find existing tab or create new one
78 local target_tab = nil
79 for _, tab in ipairs(target_window:tabs()) do
80 if tab:get_title() == id then
81 target_tab = tab
82 wezterm.log_info("Found existing tab")
83 break
84 end
85 end
86
87 if not target_tab then
88 target_tab = target_window:spawn_tab({ cwd = label })
89 target_tab:set_title(id)
90 end
91
92 target_tab:activate()
93 mux.set_active_workspace(workspace)
94end
95
96M.show_projects = function(window, pane)
97 local choices_work = M.get_directories("/Users/username/work", 0)
98 local choices_personal = M.get_directories("/Users/username/personal", 0)
99
100 local choices = {}
101
102 for _, v in ipairs(choices_work) do
103 table.insert(choices, v)
104 end
105
106 for _, v in ipairs(choices_personal) do
107 table.insert(choices, v)
108 end
109
110 window:perform_action(
111 wezterm.action.InputSelector({
112 action = wezterm.action_callback(M.open_project),
113 choices = choices,
114 fuzzy = true,
115 title = "💡 Choose a project",
116 }),
117 pane
118 )
119end
120
121return M
And update the keys to:
1local wezterm = require("wezterm")
2local config = wezterm.config_builder()
3local utils = require("utils")
4
5config.leader = { key = "a", mods = "CTRL", timeout_milliseconds = 2000 }
6config.keys = {
7 {
8 mods = "LEADER",
9 key = "p",
10 action = wezterm.action_callback(utils.show_projects),
11 },
12}
Now you’ll be able to automatically open your projects in different tabs in different windows separated by workspaces.
However, how to go back to the one you already opened? This code will automatically move you to the one you had opened if it exists. But, if you want to see which tabs you have open, that’ll be done in the next entry.