DEV Community

abidibo
abidibo

Posted on

wezterm-cmdpicker: A Command Palette for Your WezTerm Terminal

If you've ever used whichkey in Neovim, you know the feeling: you press a key, a popup appears, and suddenly all your bindings are right there — discoverable, searchable, no memorization required.

I wanted that same experience in WezTerm. So I built wezterm-cmdpicker.

In short:

  • Fuzzy-searchable command palette for all your WezTerm keybindings
  • Auto-discovers bindings from your config — no re-definition needed
  • Register action-only commands (SSH servers, Docker workflows, anything) without keybindings
  • Color-coded layers: your registered bindings, config bindings, and WezTerm defaults
  • Smart deduplication — overridden defaults are hidden automatically

The Problem

WezTerm is an incredibly powerful terminal emulator with a Lua-based configuration that lets you bind pretty much anything to a key combination. The downside? Once you have 20, 30, or 50+ keybindings, good luck remembering them all.

You end up in a loop:

  1. "What was the shortcut for splitting panes again?"
  2. Open your config file
  3. Scroll through a wall of keybindings
  4. Find it, go back to the terminal
  5. Forget it again next week

Sound familiar?

The Solution

wezterm-cmdpicker adds a command palette to WezTerm. Press one key combo (default: Leader + Space) and a fuzzy-searchable picker pops up showing all your keybindings — with descriptions, organized by source, and color-coded for clarity.

It works through a 3-layer discovery system:

  • Registered bindings (yellow) — keybindings you explicitly register with descriptions through the plugin
  • Config bindings (cyan) — keybindings from your config.keys table, auto-discovered without any extra work
  • Default bindings (grey) — WezTerm's built-in defaults, optionally included

The key idea: you don't have to re-define your existing keybindings. If they're already in config.keys, the plugin picks them up automatically. You only register explicitly when you want to add a human-readable description.

If you override a WezTerm default (say, rebinding Ctrl+Shift+T), only your version shows up in the picker. No duplicates, no confusion.

Getting Started

Here's a complete working example:

local wezterm = require('wezterm')
local act = wezterm.action
local config = wezterm.config_builder()

-- Load the plugin
local cmdpicker = wezterm.plugin.require(
  'https://github.com/abidibo/wezterm-cmdpicker'
)

-- Register keybindings with descriptions
cmdpicker.add_keys(config, {
  {
    key = 'n',
    mods = 'LEADER',
    action = act.SpawnTab('CurrentPaneDomain'),
    desc = 'New tab',
  },
  {
    key = 'x',
    mods = 'LEADER',
    action = act.CloseCurrentPane({ confirm = true }),
    desc = 'Close pane',
  },
  {
    key = 'z',
    mods = 'LEADER',
    action = act.TogglePaneZoomState,
    desc = 'Toggle zoom',
  },
})

-- Any binding added directly to config.keys is also discovered
table.insert(config.keys, {
  key = 'f',
  mods = 'LEADER',
  action = act.ToggleFullScreen,
})

-- Apply the picker (must be called LAST)
cmdpicker.apply_to_config(config, {
  title = 'Command Palette',
})

return config
Enter fullscreen mode Exit fullscreen mode

That's it. Press Leader + Space, start typing, and find any command instantly.

Real-World Use Cases

1. Separate Keybindings File

Many people keep keybindings in a separate file for organization. cmdpicker handles this cleanly:

-- keybindings.lua
local wezterm = require('wezterm')
local act = wezterm.action

return {
  {
    key = 'h',
    mods = 'LEADER',
    action = act.SplitHorizontal({ domain = 'CurrentPaneDomain' }),
    desc = 'Split horizontal',
  },
  {
    key = 'v',
    mods = 'LEADER',
    action = act.SplitVertical({ domain = 'CurrentPaneDomain' }),
    desc = 'Split vertical',
  },
}
Enter fullscreen mode Exit fullscreen mode
-- wezterm.lua
config.keys = require('keybindings')

-- Single-arg form: registers for the picker
-- without modifying config.keys
cmdpicker.add_keys(config.keys)

cmdpicker.apply_to_config(config)
Enter fullscreen mode Exit fullscreen mode

2. SSH Server Quick Access

This one is my favorite. You can register action-only commands — entries that appear in the picker without needing a keybinding:

local servers = {
  { name = 'Production', host = 'user@prod.example.com' },
  { name = 'Staging', host = 'user@staging.example.com' },
  { name = 'Dev', host = 'user@dev.example.com' },
}

for _, s in ipairs(servers) do
  cmdpicker.register({
    action = act.SpawnCommandInNewTab({
      args = { 'ssh', s.host },
    }),
    desc = 'SSH: ' .. s.name .. ' (' .. s.host .. ')',
  })
end
Enter fullscreen mode Exit fullscreen mode

Now open the picker, type "ssh", and all your servers are right there. No keybinding needed, no separate SSH manager, just your terminal.

3. Project-Specific Workflows

Build quick-access commands for your daily workflows:

cmdpicker.register({
  {
    action = act.SpawnCommandInNewTab({
      args = { 'docker', 'compose', 'up', '-d' },
    }),
    desc = 'Docker: Start services',
  },
  {
    action = act.SpawnCommandInNewTab({
      args = { 'docker', 'compose', 'logs', '-f' },
    }),
    desc = 'Docker: Follow logs',
  },
  {
    action = act.SpawnCommandInNewTab({
      args = { 'lazygit' },
    }),
    desc = 'Open lazygit',
  },
})
Enter fullscreen mode Exit fullscreen mode

Configuration Options

The apply_to_config function accepts several options to customize the picker:

cmdpicker.apply_to_config(config, {
  key = ' ',                          -- Trigger key (default: Space)
  mods = 'LEADER',                    -- Trigger modifiers (default: LEADER)
  title = 'Command Palette',          -- Picker window title
  include_defaults = true,            -- Include WezTerm defaults
  include_key_tables = false,         -- Include copy_mode, search_mode, etc.
  fuzzy = true,                       -- Enable fuzzy search
  fuzzy_description = 'Search: ',     -- Search prompt text
})
Enter fullscreen mode Exit fullscreen mode

Try It Out

If you're not on WezTerm yet — it's a GPU-accelerated, cross-platform terminal emulator configured entirely in Lua, with a built-in plugin system. With cmdpicker, it gets the kind of command palette you know from VS Code — right in your terminal.

The plugin is open source and takes one line to install:

GitHub: github.com/abidibo/wezterm-cmdpicker

If it saves you a trip to your config file, drop a star on the repo. And if you have ideas or find bugs, issues and PRs are welcome!

Top comments (0)