Your Shortcuts YAML is Always Outdated (Parse Config Files Instead)

You add a new tmux binding. A week later you're hunting through .tmux.conf because you can't remember what you mapped to prefix + g. The shortcuts.yaml you maintain? Three months out of date.
The problem isn't discipline. It's architecture. Any system requiring manual sync between source of truth (config files) and documentation (shortcuts file) will drift.
Parse your config files directly. For workflows that don't map to a single keybinding, use tealdeer custom pages. One popup, two modes, zero maintenance.
The Architecture
Two types of "help" information exist:
Config-derived - patterns living in actual config files:
- tmux bindings in
.tmux.conf - zsh bindkeys in
.zshrc - aliases in
.zsh_aliases - abbreviations in
.zsh_abbreviations
Workflow-derived - multi-step processes and reference material:
- "How do I copy in tmux?" (5 steps, not one keybinding)
- "What's the taskwarrior syntax?" (cheatsheet)
For config-derived, parse the files. For workflow-derived, use tealdeer custom pages.
confhelp
I built confhelp to solve this. Define regex patterns in TOML, point at your config files:
pip install confhelp
confhelp --init # creates ~/.config/confhelp/config.toml
# ~/.config/confhelp/config.toml
[tmux]
paths = [".tmux.conf"]
match_line = "^bind"
regex = 'bind(?:-key)?\s+(?:-n\s+)?(\S+)(.*)'
key_group = 1
desc_group = 2
type = "tmux"
truncate = 100
[alias]
paths = [".zsh_aliases", ".zsh_claude"]
regex = "alias\\s+(?:-[gs]\\s+)?([^=]+)=(.*)"
key_group = 1
desc_group = 2
type = "alias"
strip_quotes = true
[abbrev]
paths = [".zsh_abbreviations"]
mode = "abbrev_block"
type = "abbrev"
Run it:
confhelp -b ~/dotfiles # list all entries
confhelp -b ~/dotfiles --select # fzf selection, outputs file:line
confhelp -b ~/dotfiles --edit # fzf selection, opens $EDITOR at line
confhelp -b ~/dotfiles --conflicts # find keys bound multiple times
confhelp -b ~/dotfiles --check # find patterns your regex missed
Output is pipe-delimited: [type]|key|description|file:line
Each entry includes the exact file and line number. The --edit flag gives you jump-to-definition out of the box.
Set base_dirs in your config.toml and you can just run confhelp without the -b flag.
fzf Integration
For advanced workflows (like combining with tealdeer), a wrapper script spawns a centered popup with mode switching:
selection=$(confhelp -b "$DOTFILES" | column -t -s'|' | fzf \
--header='Enter=jump | Ctrl+G=tealdeer' \
--bind='ctrl-g:become(echo SWITCH_TLDR)' \
--height=100% \
--layout=reverse)
if [[ -n "$selection" ]]; then
file_line=$(echo "$selection" | awk '{print $NF}')
file=$(echo "$file_line" | cut -d: -f1)
line=$(echo "$file_line" | cut -d: -f2)
nvim "+$line" "${DOTFILES}/${file}"
fi
The become() action replaces fzf with a new command without closing the terminal. Critical for smooth mode switching between bindings and tealdeer.
Tealdeer Custom Pages
Tealdeer reads custom pages from a configured directory:
# ~/.config/tealdeer/config.toml
[directories]
custom_pages_dir = "/home/decoder/.local/share/tealdeer/pages"
Custom pages need .page.md extension:
# tmux-copy-mode
> Tmux copy mode with vi keybindings
- Enter copy mode:
`prefix + [`
- Start selection:
`v` or `V` for line
- Copy selection:
`y`
Ctrl+G in the bindings popup switches to tealdeer browser. Custom pages appear with [custom] marker.
Result
| Aspect | Before | After |
|---|---|---|
| Source of truth | shortcuts.yaml (manual) | Config files (parsed) |
| Maintenance | Constant drift | Zero |
| Jump to definition | Search manually | Enter → nvim at line |
| Workflow docs | Scattered notes | tealdeer pages |
Add a binding to .tmux.conf, it appears in the popup immediately. No yaml to update.
Gotchas
-
Tealdeer file extension - Custom pages must end in
.page.md, not.md. -
fzf become() vs execute() -
execute()runs a command and returns to fzf.become()replaces fzf entirely. For mode switching, you needbecome(). -
Column alignment - The parser outputs pipe-separated values.
column -t -s'|'aligns them.
Resources: