aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-25 19:01:49 +0200
committerDanilo M. <danix@danix.xyz>2026-09-25 19:01:49 +0200
commit3ba00d86ab05bc1b01294d2db684c2eee37e8164 (patch)
treed85f6a7f93507181849adfe0e9564452ce2b47f3 /docs
parent30bebb6f36cc32fdeac03d4848635a1911ebcdd8 (diff)
downloadquickshell-3ba00d86ab05bc1b01294d2db684c2eee37e8164.tar.gz
quickshell-3ba00d86ab05bc1b01294d2db684c2eee37e8164.zip
docs(keybinds): design for a live keybind reminder
The list comes from hyprctl binds -j on every opening, so it is always what Hyprland has loaded, loop-generated binds included. Labels come from each bind's description option, since hyprctl reports Lua actions as an opaque __lua handle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/specs/2026-09-25-keybinds-design.md64
1 files changed, 64 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-09-25-keybinds-design.md b/docs/superpowers/specs/2026-09-25-keybinds-design.md
new file mode 100644
index 0000000..e516c77
--- /dev/null
+++ b/docs/superpowers/specs/2026-09-25-keybinds-design.md
@@ -0,0 +1,64 @@
+# Keybind reminder design
+
+A full-screen overlay listing every Hyprland keybind with what it does, opened
+with `SUPER + k`. It exists to recall shortcuts, so it must never show a bind
+that is not live or miss one that is.
+
+## Source of truth
+
+`hyprctl binds -j`, run on every opening. This is what Hyprland has loaded,
+including binds generated in Lua loops, and it stays correct when
+`keybindings.lua` has been edited but not reloaded. Parsing the Lua file was
+rejected for exactly those two cases. No cache: the call is cheap and a cache
+is the only way the list could go stale.
+
+`hyprctl` reports every Lua action as `dispatcher: "__lua"` with an opaque
+numeric `arg`, so the action text comes from the bind's `description`, a
+documented `HL.BindOptions` field (`/usr/share/hypr/stubs/hl.meta.lua`).
+
+## Hypr side (`hypr-theme` repo)
+
+- Every `hl.bind` gains `{ description = "Group: Label" }`, merged into any
+ options it already has (`locked`, `repeating`, `mouse`). Loop-generated
+ binds build theirs in the loop, e.g. `"Workspaces: Go to 3"`.
+- The text before the first `": "` is the group heading in the overlay.
+- New bind: `SUPER + k` → `qs -p <repo>/keybinds ipc call keybinds toggle`,
+ description `"Help: Keybind reminder"`.
+- `autostart.lua` starts `qs -p <repo>/keybinds`.
+- `decorations.lua` gains a `blur-keybinds` layer rule matching namespace
+ `^(quickshell-keybinds)$`, copied from `blur-window-switcher`.
+- `SUPER + s` is defined in `dashboard.lua`, a symlink into the
+ `conky-theme-udt` repo; its description is a commit there.
+
+## Quickshell side: `keybinds/`
+
+- `shell.qml`: `ShellRoot` with the overlay and an `IpcHandler` target
+ `keybinds` exposing `toggle`, `show`, `close`.
+- `Keybinds.qml`: `Scope` holding the 1x1 click-through keepalive
+ `PanelWindow` and a `LazyLoader` overlay on `root.open`. Overlay layer,
+ namespace `quickshell-keybinds`, `ExclusionMode.Ignore`, exclusive keyboard.
+ A focused `Item` handles Esc; a click anywhere closes.
+- Opening sets `running = false` then `true` on a `Process` running
+ `hyprctl binds -j`; `StdioCollector` output is parsed on exit.
+- `Binds.js` (pure, `.pragma library`): `mods(mask)` decodes SHIFT=1,
+ CTRL=4, ALT=8, SUPER=64 in the order SUPER, CTRL, ALT, SHIFT;
+ `group(binds)` returns `[{ name, rows: [{ keys, label }] }]`, groups in
+ first-seen order. A bind with no description goes to group `Undescribed`
+ with its raw key as label, so gaps stay visible. Mouse binds show as
+ written (`mouse:272`).
+- Layout: groups flow in a `Flow` of columns, each a heading plus
+ `keys label` rows. Theme from the `Theme.qml` symlink to
+ `../shared/Theme.qml`; glyph-free.
+- While loading or on `hyprctl` failure, the overlay says so rather than
+ drawing empty.
+- `README.md`, GPLv2 headers on every file.
+
+## Testing
+
+`keybinds/test_binds.js`, runnable with `node` (it strips the `.pragma` line and evaluates `Binds.js`), asserts `mods` and `group`
+against a fixture shaped like `hyprctl binds -j`. Visual check by the user.
+
+## Out of scope
+
+Search box (add if the list outgrows a screen, ~80 binds today). Submaps (none
+in use).