The old bash bin short-circuited with close_visible_quickshell_menu at
the top of open_quickshell_menu, so pressing any menu keybind while the
menu was open just closed it. The IPC path I introduced summoned every
time, so keyboard shortcuts couldn't dismiss \u2014 only outside clicks did
(which is why the bar icon appeared to toggle: clicking it while the
menu was open hit the menu's outer-click MouseArea, not the icon).
Add a menu.toggle IPC method:
- if root.opened: cancel() and return "closed"
- otherwise: behaves exactly like summon
Switch every Hyprland binding and the two bar-icon click handlers
(omarchy logo, battery right-click \u2192 power menu) to toggle. summon stays
as the always-open primitive for callers that want explicit summon
semantics (rare \u2014 right now nothing internal uses it).
With bin/omarchy-menu gone there's no caller that summons the menu by
writing a JSON tempfile and polling a done file. Drop everything that
existed only to support that handshake:
- menuJsonFile / menuJsonFileView / loadMenuJson / openMenu(json,...)
- pendingSelectionFile / pendingDoneFile / selectionFile / doneFile
- mergeProviderJson (the JSON-wrapper for provider output)
- applyProc / releaseProc / doneFilesToRelease / finishDoneFile /
releaseNextDoneFile / resetRequest / requestActive / closeMenu
- the menuBin property pointing at the deleted bin
applySelected is now four lines (close + execDetached); cancel is two
(close + clear filter). open() takes either {menu: id} or a bare initial
menu name, and hands off to openExistingMenu which uses the cached items
from the JSONC FileViews.
Net: 91 lines smaller, no perf change.
omarchy-menu used to spawn an 821-line bash bin on every keybind: 11 jq
invocations against omarchy-menu.jsonc, mktemp dance, summon, poll. The
shell waited ~235ms (keybind to visible) before painting the first row.
The bar plugin host is already a persistent process with the menu plugin
loaded (keepLoaded: true) — it just wasn't allowed to own the menu data.
Now it does:
- parseMenuJsonc / normalizeItem ports the bash bin's jq pipeline to
JS: strip // comments + trailing commas, infer parent from dotted
ids, dedupe keyword tokens across id/aliases/keywords, fill defaults.
- Two FileViews with watchChanges: true on the default and user
extension JSONCs. Edit either file and the in-memory item map
refreshes without a restart.
- IpcHandler exposes menu.summon(initialMenu) / refresh() / close() /
ping(). summon resolves aliases the way the old bash route_target
did, including the leaf-alias-is-an-action shortcut.
- Action dispatch is now direct: when summoned via IPC (no selection
or done file), Quickshell.execDetached(['bash','-lc', action]) runs
the action and the menu closes. The legacy tempfile dance is kept
only for the duration of the migration window.
- provider sub-menus (fonts, power-profiles) are inline: tab-delimited
bash one-liner per provider, parsed by mergeProviderRows.
- when:/checked: bash expressions are batched into one Process at
shell startup (and again whenever the JSONCs change). The menu
opens instantly; visibility/check marks settle within ~50ms.
Measured: keybind-to-visible via the new IPC path is ~30ms (was ~235ms).
The bash bin still works for now and is removed in the next commit.