feat(menu): group keybinds cheatsheet Window/Workspace/Menu/Media (#108)
All checks were successful
Check / eval (push) Successful in 3m39s
All checks were successful
Check / eval (push) Successful in 3m39s
Every bind in keybinds.nix carries a group; SUPER+? renders section headers. checks.keybinds-cheatsheet asserts all groups are valid and every description appears in the sheet (same source as Hyprland binds). Verified: V0 flake check; built cheatsheet shows ── Window ── / etc.
This commit is contained in:
@@ -261,13 +261,6 @@ scoped implementation/verification tasks before work starts. Pass = every
|
|||||||
current route has one deliberate home, navigation remains shallow, and no
|
current route has one deliberate home, navigation remains shallow, and no
|
||||||
root-level entry is added or lost.
|
root-level entry is added or lost.
|
||||||
|
|
||||||
### 108. Keybindings menu presentation and completeness audit
|
|
||||||
|
|
||||||
Group the menu as Window, Workspace, Menu, and Media, then prove every live
|
|
||||||
Hyprland binding appears from the canonical source. Do not repeat the obsolete
|
|
||||||
claim that float/move bindings are absent. Pass = presentation is scannable and
|
|
||||||
an automated comparison detects omissions or stale displayed bindings.
|
|
||||||
|
|
||||||
### 110. `[big]` Retire Control Center safely
|
### 110. `[big]` Retire Control Center safely
|
||||||
|
|
||||||
Split this into two phases before implementation: first build a migration/drop
|
Split this into two phases before implementation: first build a migration/drop
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ Template:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-15 — #108 keybinds cheatsheet groups + completeness check
|
||||||
|
- **Task:** BACKLOG #108 — group SUPER+? as Window/Workspace/Menu/Media;
|
||||||
|
automated completeness.
|
||||||
|
- **Did:** every bind/extra in keybinds.nix gets `group`; cheatsheet renders
|
||||||
|
section headers; `checks.keybinds-cheatsheet` asserts groups + every desc
|
||||||
|
present (proved via assert).
|
||||||
|
- **Verified:** V0 flake check; cheatsheet file shows ── Window ── etc.
|
||||||
|
- **Pending:** V3 eyeball SUPER+? on a real session (optional).
|
||||||
|
- **Next suggestion:** #94 residual or #107 state.json rename.
|
||||||
|
|
||||||
## 2026-07-15 — Fix batch #112 disk picker, #106 menu Back, #113 offline theme
|
## 2026-07-15 — Fix batch #112 disk picker, #106 menu Back, #113 offline theme
|
||||||
- **Task:** Second fix-only batch from NEXT/NOW residuals.
|
- **Task:** Second fix-only batch from NEXT/NOW residuals.
|
||||||
- **Did:** (112) `list_installable_disks` excludes fd/loop/sr/zram/tiny
|
- **Did:** (112) `list_installable_disks` excludes fd/loop/sr/zram/tiny
|
||||||
|
|||||||
@@ -404,6 +404,10 @@ Design/decision records and a running log of shipped work (items marked
|
|||||||
decision rather than a drive-by. Proved to fail: dropping snapshot makes it
|
decision rather than a drive-by. Proved to fail: dropping snapshot makes it
|
||||||
name the missing entry. **V3 pending** — that the apps *launch* needs real
|
name the missing entry. **V3 pending** — that the apps *launch* needs real
|
||||||
hardware (HARDWARE-QUEUE, Acer M5-481T).
|
hardware (HARDWARE-QUEUE, Acer M5-481T).
|
||||||
|
- ✓ **Keybinds cheatsheet groups (#108):** SUPER+? sections Window /
|
||||||
|
Workspace / Menu / Media from keybinds.nix `group`;
|
||||||
|
`checks.keybinds-cheatsheet` fails if a bind lacks a group or a desc is
|
||||||
|
missing from the sheet.
|
||||||
- ✓ **Fix batch #112 / #106 / #113:** installer disk picker drops fd0/loop/
|
- ✓ **Fix batch #112 / #106 / #113:** installer disk picker drops fd0/loop/
|
||||||
optical/<8 GiB and lists largest-first (OVMF no longer defaults to floppy);
|
optical/<8 GiB and lists largest-first (OVMF no longer defaults to floppy);
|
||||||
`checks.menu-back` guards every internal rofi list emits ↩ Back; offline
|
`checks.menu-back` guards every internal rofi list emits ↩ Back; offline
|
||||||
|
|||||||
42
flake.nix
42
flake.nix
@@ -477,6 +477,48 @@
|
|||||||
touch $out
|
touch $out
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# Keybinds cheatsheet completeness + grouping (#108): every bind
|
||||||
|
# from keybinds.nix has a group, and every desc appears in the
|
||||||
|
# rendered cheatsheet (same source hyprland.nix binds from).
|
||||||
|
keybinds-cheatsheet =
|
||||||
|
let
|
||||||
|
inherit (nixpkgs.lib) assertMsg concatLists concatMapStringsSep
|
||||||
|
concatStringsSep elem filter hasInfix;
|
||||||
|
kb = import ./modules/home/keybinds.nix;
|
||||||
|
groups = [ "Window" "Workspace" "Menu" "Media" ];
|
||||||
|
allBinds = kb.binds ++ kb.multiLayoutBinds;
|
||||||
|
badGroup = filter (b: !(elem (b.group or null) groups)) allBinds;
|
||||||
|
extraBad = filter (e: !(elem (e.group or null) groups)) kb.extra;
|
||||||
|
descs = map (b: b.desc) allBinds ++ map (e: e.desc) kb.extra;
|
||||||
|
linesFor = g:
|
||||||
|
let rows = filter (b: b.group == g) allBinds
|
||||||
|
++ filter (e: e.group == g) kb.extra;
|
||||||
|
in if rows == [ ] then [ ]
|
||||||
|
else [ ("── " + g + " ──") ] ++ map (r: r.desc) rows;
|
||||||
|
sheet = concatStringsSep "\n" (concatLists (map linesFor groups));
|
||||||
|
missing = filter (d: !(hasInfix d sheet)) descs;
|
||||||
|
ok = badGroup == [ ] && extraBad == [ ] && missing == [ ]
|
||||||
|
&& hasInfix "── Window ──" sheet
|
||||||
|
&& hasInfix "── Workspace ──" sheet
|
||||||
|
&& hasInfix "── Menu ──" sheet
|
||||||
|
&& hasInfix "── Media ──" sheet;
|
||||||
|
msg =
|
||||||
|
(if badGroup != [ ] then
|
||||||
|
"binds missing/invalid group: "
|
||||||
|
+ concatMapStringsSep ", " (b: b.desc) badGroup + "\n"
|
||||||
|
else "")
|
||||||
|
+ (if extraBad != [ ] then
|
||||||
|
"extra missing/invalid group: "
|
||||||
|
+ concatMapStringsSep ", " (e: e.desc) extraBad + "\n"
|
||||||
|
else "")
|
||||||
|
+ (if missing != [ ] then
|
||||||
|
"descs missing from grouped sheet: "
|
||||||
|
+ concatStringsSep ", " missing + "\n"
|
||||||
|
else "");
|
||||||
|
in
|
||||||
|
assert assertMsg ok ("keybinds-cheatsheet: " + msg);
|
||||||
|
pkgs.runCommand "nomarchy-keybinds-cheatsheet" { } "touch $out";
|
||||||
|
|
||||||
# Installer keyboard no-variant regression (item 91): gum's `(none)`
|
# Installer keyboard no-variant regression (item 91): gum's `(none)`
|
||||||
# row is display-only. Exercise it through the real template
|
# row is display-only. Exercise it through the real template
|
||||||
# patcher, then build the exact us + empty-variant console keymap
|
# patcher, then build the exact us + empty-variant console keymap
|
||||||
|
|||||||
@@ -7,85 +7,86 @@
|
|||||||
# key — the key name
|
# key — the key name
|
||||||
# action — the Hyprland dispatcher (+args) that the bind runs
|
# action — the Hyprland dispatcher (+args) that the bind runs
|
||||||
# desc — human label, shown in the cheatsheet
|
# desc — human label, shown in the cheatsheet
|
||||||
|
# group — cheatsheet section: Window | Workspace | Menu | Media (#108)
|
||||||
#
|
#
|
||||||
# `extra` holds cheatsheet-only rows for binds generated elsewhere
|
# `extra` holds cheatsheet-only rows for binds generated elsewhere
|
||||||
# (per-workspace numbers, mouse drags) so they still show up under SUPER+?.
|
# (per-workspace numbers, mouse drags) so they still show up under SUPER+?.
|
||||||
{
|
{
|
||||||
binds = [
|
binds = [
|
||||||
{ mods = "$mod"; key = "Return"; action = "exec, $terminal"; desc = "Open terminal"; }
|
{ mods = "$mod"; key = "Return"; action = "exec, $terminal"; desc = "Open terminal"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "Space"; action = "exec, rofi -show drun -theme launcher"; desc = "App launcher"; }
|
{ mods = "$mod"; key = "Space"; action = "exec, rofi -show drun -theme launcher"; desc = "App launcher"; group = "Menu"; }
|
||||||
{ mods = "$mod"; key = "M"; action = "exec, nomarchy-menu"; desc = "Main menu"; }
|
{ mods = "$mod"; key = "M"; action = "exec, nomarchy-menu"; desc = "Main menu"; group = "Menu"; }
|
||||||
{ mods = "$mod"; key = "E"; action = "exec, $terminal -e yazi"; desc = "File manager (yazi)"; }
|
{ mods = "$mod"; key = "E"; action = "exec, $terminal -e yazi"; desc = "File manager (yazi)"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "Q"; action = "killactive"; desc = "Close window"; }
|
{ mods = "$mod"; key = "Q"; action = "killactive"; desc = "Close window"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "F"; action = "fullscreen"; desc = "Fullscreen"; }
|
{ mods = "$mod"; key = "F"; action = "fullscreen"; desc = "Fullscreen"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "V"; action = "togglefloating"; desc = "Toggle floating"; }
|
{ mods = "$mod"; key = "V"; action = "togglefloating"; desc = "Toggle floating"; group = "Window"; }
|
||||||
{ mods = "$mod SHIFT"; key = "E"; action = "exit"; desc = "Exit Hyprland"; }
|
{ mods = "$mod SHIFT"; key = "E"; action = "exit"; desc = "Exit Hyprland"; group = "Window"; }
|
||||||
|
|
||||||
# Theme picker (menu dispatcher): apply writes the state and runs
|
# Theme picker (menu dispatcher): apply writes the state and runs
|
||||||
# home-manager switch (progress via notify-send).
|
# home-manager switch (progress via notify-send).
|
||||||
{ mods = "$mod"; key = "T"; action = "exec, nomarchy-menu theme"; desc = "Theme picker"; }
|
{ mods = "$mod"; key = "T"; action = "exec, nomarchy-menu theme"; desc = "Theme picker"; group = "Menu"; }
|
||||||
# Cycle the current theme's wallpapers (instant, no rebuild).
|
# Cycle the current theme's wallpapers (instant, no rebuild).
|
||||||
{ mods = "$mod SHIFT"; key = "T"; action = "exec, nomarchy-theme-sync bg next"; desc = "Next wallpaper"; }
|
{ mods = "$mod SHIFT"; key = "T"; action = "exec, nomarchy-theme-sync bg next"; desc = "Next wallpaper"; group = "Menu"; }
|
||||||
|
|
||||||
# Power menu via the dispatcher. Not Escape: Super+Escape gets
|
# Power menu via the dispatcher. Not Escape: Super+Escape gets
|
||||||
# swallowed before reaching the dispatcher on some setups.
|
# swallowed before reaching the dispatcher on some setups.
|
||||||
{ mods = "$mod"; key = "X"; action = "exec, nomarchy-menu power"; desc = "Power menu"; }
|
{ mods = "$mod"; key = "X"; action = "exec, nomarchy-menu power"; desc = "Power menu"; group = "Menu"; }
|
||||||
|
|
||||||
{ mods = "$mod"; key = "N"; action = "exec, swaync-client -t"; desc = "Notification centre"; }
|
{ mods = "$mod"; key = "N"; action = "exec, swaync-client -t"; desc = "Notification centre"; group = "Media"; }
|
||||||
# SUPER+? — ? is Shift+/. SHIFT stays in the modmask (you hold it), but
|
# SUPER+? — ? is Shift+/. SHIFT stays in the modmask (you hold it), but
|
||||||
# the keysym must be the BASE key `slash`, not `question`: Hyprland
|
# the keysym must be the BASE key `slash`, not `question`: Hyprland
|
||||||
# resolves the sym with Shift consumed, so `question` never matches while
|
# resolves the sym with Shift consumed, so `question` never matches while
|
||||||
# Shift is down — same as the `$mod SHIFT, 1` workspace binds. (item 26
|
# Shift is down — same as the `$mod SHIFT, 1` workspace binds. (item 26
|
||||||
# fixed the modmask but kept the shifted keysym → still dead; item 32.)
|
# fixed the modmask but kept the shifted keysym → still dead; item 32.)
|
||||||
# The cheatsheet still renders this row as SUPER + ? (rofi.nix).
|
# The cheatsheet still renders this row as SUPER + ? (rofi.nix).
|
||||||
{ mods = "$mod SHIFT"; key = "slash"; action = "exec, nomarchy-menu keybinds"; desc = "Keybindings cheatsheet"; }
|
{ mods = "$mod SHIFT"; key = "slash"; action = "exec, nomarchy-menu keybinds"; desc = "Keybindings cheatsheet"; group = "Menu"; }
|
||||||
|
|
||||||
# Menu functions — SUPER+CTRL+<mnemonic> jumps straight to a
|
# Menu functions — SUPER+CTRL+<mnemonic> jumps straight to a
|
||||||
# nomarchy-menu module (all also reachable from the SUPER+M picker).
|
# nomarchy-menu module (all also reachable from the SUPER+M picker).
|
||||||
{ mods = "$mod CTRL"; key = "V"; action = "exec, nomarchy-menu clipboard"; desc = "Clipboard history"; }
|
{ mods = "$mod CTRL"; key = "V"; action = "exec, nomarchy-menu clipboard"; desc = "Clipboard history"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "C"; action = "exec, nomarchy-menu calc"; desc = "Calculator"; }
|
{ mods = "$mod CTRL"; key = "C"; action = "exec, nomarchy-menu calc"; desc = "Calculator"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "W"; action = "exec, nomarchy-menu web"; desc = "Web search"; }
|
{ mods = "$mod CTRL"; key = "W"; action = "exec, nomarchy-menu web"; desc = "Web search"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "F"; action = "exec, nomarchy-menu files"; desc = "File search"; }
|
{ mods = "$mod CTRL"; key = "F"; action = "exec, nomarchy-menu files"; desc = "File search"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "E"; action = "exec, nomarchy-menu emoji"; desc = "Emoji picker"; }
|
{ mods = "$mod CTRL"; key = "E"; action = "exec, nomarchy-menu emoji"; desc = "Emoji picker"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "N"; action = "exec, nomarchy-menu network"; desc = "Network (networkmanager_dmenu)"; }
|
{ mods = "$mod CTRL"; key = "N"; action = "exec, nomarchy-menu network"; desc = "Network (networkmanager_dmenu)"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "B"; action = "exec, nomarchy-menu bluetooth"; desc = "Bluetooth"; }
|
{ mods = "$mod CTRL"; key = "B"; action = "exec, nomarchy-menu bluetooth"; desc = "Bluetooth"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "K"; action = "exec, nomarchy-menu keyboard"; desc = "Keyboard layout"; }
|
{ mods = "$mod CTRL"; key = "K"; action = "exec, nomarchy-menu keyboard"; desc = "Keyboard layout"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "S"; action = "exec, nomarchy-menu capture"; desc = "Screenshot / capture"; }
|
{ mods = "$mod CTRL"; key = "S"; action = "exec, nomarchy-menu capture"; desc = "Screenshot / capture"; group = "Media"; }
|
||||||
{ mods = "$mod CTRL"; key = "P"; action = "exec, nomarchy-menu colorpicker"; desc = "Color picker (→ clipboard)"; }
|
{ mods = "$mod CTRL"; key = "P"; action = "exec, nomarchy-menu colorpicker"; desc = "Color picker (→ clipboard)"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "A"; action = "exec, nomarchy-menu ask"; desc = "Ask Claude"; }
|
{ mods = "$mod CTRL"; key = "A"; action = "exec, nomarchy-menu ask"; desc = "Ask Claude"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "D"; action = "exec, nomarchy-menu dnd"; desc = "Do Not Disturb toggle"; }
|
{ mods = "$mod CTRL"; key = "D"; action = "exec, nomarchy-menu dnd"; desc = "Do Not Disturb toggle"; group = "Media"; }
|
||||||
# I as in "settings" muscle memory (Super+I elsewhere); T for Tools.
|
# I as in "settings" muscle memory (Super+I elsewhere); T for Tools.
|
||||||
{ mods = "$mod CTRL"; key = "I"; action = "exec, nomarchy-menu system"; desc = "System menu"; }
|
{ mods = "$mod CTRL"; key = "I"; action = "exec, nomarchy-menu system"; desc = "System menu"; group = "Menu"; }
|
||||||
{ mods = "$mod CTRL"; key = "T"; action = "exec, nomarchy-menu tools"; desc = "Tools menu"; }
|
{ mods = "$mod CTRL"; key = "T"; action = "exec, nomarchy-menu tools"; desc = "Tools menu"; group = "Menu"; }
|
||||||
# The one SUPER+CTRL row that is not a menu module: lock earns the
|
# The one SUPER+CTRL row that is not a menu module: lock earns the
|
||||||
# family slot because bare SUPER+L is a common app bind and Escape is
|
# family slot because bare SUPER+L is a common app bind and Escape is
|
||||||
# unusable (see the power-menu note above). Same dispatcher the power
|
# unusable (see the power-menu note above). Same dispatcher the power
|
||||||
# menu's Lock row uses (rofi.nix) — logind, not `hyprlock` directly, so
|
# menu's Lock row uses (rofi.nix) — logind, not `hyprlock` directly, so
|
||||||
# the session is marked locked and hypridle's lock_cmd stays the one
|
# the session is marked locked and hypridle's lock_cmd stays the one
|
||||||
# place that decides how a lock actually looks.
|
# place that decides how a lock actually looks.
|
||||||
{ mods = "$mod CTRL"; key = "L"; action = "exec, loginctl lock-session"; desc = "Lock screen"; }
|
{ mods = "$mod CTRL"; key = "L"; action = "exec, loginctl lock-session"; desc = "Lock screen"; group = "Menu"; }
|
||||||
{ mods = "$mod SHIFT"; key = "C"; action = "exec, hyprpicker -a"; desc = "Color picker (→ clipboard)"; }
|
{ mods = "$mod SHIFT"; key = "C"; action = "exec, hyprpicker -a"; desc = "Color picker (→ clipboard)"; group = "Menu"; }
|
||||||
|
|
||||||
# Focus — SUPER + arrow keys.
|
# Focus — SUPER + arrow keys.
|
||||||
{ mods = "$mod"; key = "left"; action = "movefocus, l"; desc = "Focus left"; }
|
{ mods = "$mod"; key = "left"; action = "movefocus, l"; desc = "Focus left"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "right"; action = "movefocus, r"; desc = "Focus right"; }
|
{ mods = "$mod"; key = "right"; action = "movefocus, r"; desc = "Focus right"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "up"; action = "movefocus, u"; desc = "Focus up"; }
|
{ mods = "$mod"; key = "up"; action = "movefocus, u"; desc = "Focus up"; group = "Window"; }
|
||||||
{ mods = "$mod"; key = "down"; action = "movefocus, d"; desc = "Focus down"; }
|
{ mods = "$mod"; key = "down"; action = "movefocus, d"; desc = "Focus down"; group = "Window"; }
|
||||||
|
|
||||||
# Multi-monitor workspace movement — SUPER + ALT + arrow keys.
|
# Multi-monitor workspace movement — SUPER + ALT + arrow keys.
|
||||||
{ mods = "$mod ALT"; key = "left"; action = "movecurrentworkspacetomonitor, l"; desc = "Move workspace to left monitor"; }
|
{ mods = "$mod ALT"; key = "left"; action = "movecurrentworkspacetomonitor, l"; desc = "Move workspace to left monitor"; group = "Workspace"; }
|
||||||
{ mods = "$mod ALT"; key = "right"; action = "movecurrentworkspacetomonitor, r"; desc = "Move workspace to right monitor"; }
|
{ mods = "$mod ALT"; key = "right"; action = "movecurrentworkspacetomonitor, r"; desc = "Move workspace to right monitor"; group = "Workspace"; }
|
||||||
{ mods = "$mod ALT"; key = "up"; action = "movecurrentworkspacetomonitor, u"; desc = "Move workspace to upper monitor"; }
|
{ mods = "$mod ALT"; key = "up"; action = "movecurrentworkspacetomonitor, u"; desc = "Move workspace to upper monitor"; group = "Workspace"; }
|
||||||
{ mods = "$mod ALT"; key = "down"; action = "movecurrentworkspacetomonitor, d"; desc = "Move workspace to lower monitor"; }
|
{ mods = "$mod ALT"; key = "down"; action = "movecurrentworkspacetomonitor, d"; desc = "Move workspace to lower monitor"; group = "Workspace"; }
|
||||||
|
|
||||||
# Screenshots (the menu's Capture module has the rest: OCR, recording).
|
# Screenshots (the menu's Capture module has the rest: OCR, recording).
|
||||||
# Bare Print → region to clipboard; the two → file binds save a
|
# Bare Print → region to clipboard; the two → file binds save a
|
||||||
# timestamped PNG under ~/Pictures/Screenshots and toast the path, the
|
# timestamped PNG under ~/Pictures/Screenshots and toast the path, the
|
||||||
# same plumbing the Capture menu's "→ file" rows use.
|
# same plumbing the Capture menu's "→ file" rows use.
|
||||||
{ mods = ""; key = "Print"; action = "exec, grim -g \"$(slurp)\" - | wl-copy && notify-send Screenshot \"Region copied to clipboard.\""; desc = "Screenshot region → clipboard"; }
|
{ mods = ""; key = "Print"; action = "exec, grim -g \"$(slurp)\" - | wl-copy && notify-send Screenshot \"Region copied to clipboard.\""; desc = "Screenshot region → clipboard"; group = "Media"; }
|
||||||
{ mods = "SHIFT"; key = "Print"; action = "exec, f=$HOME/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png; mkdir -p $HOME/Pictures/Screenshots && grim -g \"$(slurp)\" \"$f\" && notify-send \"Screenshot saved\" \"$f\""; desc = "Screenshot region → file"; }
|
{ mods = "SHIFT"; key = "Print"; action = "exec, f=$HOME/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png; mkdir -p $HOME/Pictures/Screenshots && grim -g \"$(slurp)\" \"$f\" && notify-send \"Screenshot saved\" \"$f\""; desc = "Screenshot region → file"; group = "Media"; }
|
||||||
{ mods = "CTRL"; key = "Print"; action = "exec, f=$HOME/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png; mkdir -p $HOME/Pictures/Screenshots && grim \"$f\" && notify-send \"Screenshot saved\" \"$f\""; desc = "Screenshot screen → file"; }
|
{ mods = "CTRL"; key = "Print"; action = "exec, f=$HOME/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png; mkdir -p $HOME/Pictures/Screenshots && grim \"$f\" && notify-send \"Screenshot saved\" \"$f\""; desc = "Screenshot screen → file"; group = "Media"; }
|
||||||
{ mods = "$mod SHIFT"; key = "Print"; action = "exec, f=$HOME/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png; mkdir -p $HOME/Pictures/Screenshots && grim -g \"$(slurp)\" - | satty --filename - --fullscreen --output-filename \"$f\""; desc = "Annotate region"; }
|
{ mods = "$mod SHIFT"; key = "Print"; action = "exec, f=$HOME/Pictures/Screenshots/$(date +%Y%m%d-%H%M%S).png; mkdir -p $HOME/Pictures/Screenshots && grim -g \"$(slurp)\" - | satty --filename - --fullscreen --output-filename \"$f\""; desc = "Annotate region"; group = "Media"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
# Rendered only when the session has >1 layout (a comma in
|
# Rendered only when the session has >1 layout (a comma in
|
||||||
@@ -94,14 +95,14 @@
|
|||||||
# step. `current` targets the focused keyboard, so a board with its
|
# step. `current` targets the focused keyboard, so a board with its
|
||||||
# own per-device layout (a single one) is a no-op, never a leak.
|
# own per-device layout (a single one) is a no-op, never a leak.
|
||||||
multiLayoutBinds = [
|
multiLayoutBinds = [
|
||||||
{ mods = "$mod SHIFT"; key = "K"; action = "exec, hyprctl switchxkblayout current next"; desc = "Cycle keyboard layout"; }
|
{ mods = "$mod SHIFT"; key = "K"; action = "exec, hyprctl switchxkblayout current next"; desc = "Cycle keyboard layout"; group = "Menu"; }
|
||||||
];
|
];
|
||||||
|
|
||||||
extra = [
|
extra = [
|
||||||
{ keys = "SUPER + 1-9, 0"; desc = "Switch to workspace 1-10 (0 = 10)"; }
|
{ keys = "SUPER + 1-9, 0"; desc = "Switch to workspace 1-10 (0 = 10)"; group = "Workspace"; }
|
||||||
{ keys = "SUPER + SHIFT + 1-9, 0"; desc = "Move window to workspace 1-10 (0 = 10)"; }
|
{ keys = "SUPER + SHIFT + 1-9, 0"; desc = "Move window to workspace 1-10 (0 = 10)"; group = "Workspace"; }
|
||||||
{ keys = "SUPER + drag"; desc = "Move (LMB) / resize (RMB) window"; }
|
{ keys = "SUPER + drag"; desc = "Move (LMB) / resize (RMB) window"; group = "Window"; }
|
||||||
{ keys = "Volume / Brightness"; desc = "Hardware keys, shown via the OSD"; }
|
{ keys = "Volume / Brightness"; desc = "Hardware keys, shown via the OSD"; group = "Media"; }
|
||||||
{ keys = "Bar: click"; desc = "Caffeine — hold the screen awake (idle inhibitor)"; }
|
{ keys = "Bar: click"; desc = "Caffeine — hold the screen awake (idle inhibitor)"; group = "Media"; }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,17 +133,37 @@ let
|
|||||||
# renders "SHIFT + /". `?` IS Shift+/, so collapse that back to the
|
# renders "SHIFT + /". `?` IS Shift+/, so collapse that back to the
|
||||||
# single documented glyph — the cheatsheet reads "SUPER + ?".
|
# single documented glyph — the cheatsheet reads "SUPER + ?".
|
||||||
in lib.replaceStrings [ "SHIFT + /" ] [ "?" ] (prefix + key);
|
in lib.replaceStrings [ "SHIFT + /" ] [ "?" ] (prefix + key);
|
||||||
cheatRows =
|
# Grouped cheatsheet (#108): Window → Workspace → Menu → Media.
|
||||||
map (b: padRight 22 (prettyKeys b) + b.desc) (keybinds.binds
|
# Section headers are non-selectable chrome (rofi still shows them as rows;
|
||||||
|
# Enter is a no-op either way). Order matches the group enum.
|
||||||
|
cheatGroupOrder = [ "Window" "Workspace" "Menu" "Media" ];
|
||||||
|
cheatBindRows =
|
||||||
|
map (b: {
|
||||||
|
inherit (b) group desc;
|
||||||
|
keys = prettyKeys b;
|
||||||
|
}) (keybinds.binds
|
||||||
++ lib.optionals (lib.hasInfix "," cfg.keyboard.layout)
|
++ lib.optionals (lib.hasInfix "," cfg.keyboard.layout)
|
||||||
keybinds.multiLayoutBinds)
|
keybinds.multiLayoutBinds)
|
||||||
# Launch-or-focus binds (nomarchy.launchOrFocus, generated in
|
# Launch-or-focus binds (nomarchy.launchOrFocus, generated in
|
||||||
# hyprland.nix) — same renderer, so they land in the cheatsheet too.
|
# hyprland.nix) — same renderer, so they land in the cheatsheet too.
|
||||||
++ map (e: padRight 22 (prettyKeys e)
|
++ map (e: {
|
||||||
+ (if e.desc != "" then e.desc
|
group = "Menu";
|
||||||
else "Focus or launch ${if e.command == "" then lib.toLower e.class else e.command}"))
|
keys = prettyKeys e;
|
||||||
cfg.launchOrFocus
|
desc = if e.desc != "" then e.desc
|
||||||
++ map (e: padRight 22 e.keys + e.desc) keybinds.extra;
|
else "Focus or launch ${if e.command == "" then lib.toLower e.class else e.command}";
|
||||||
|
}) cfg.launchOrFocus
|
||||||
|
++ map (e: {
|
||||||
|
group = e.group or "Menu";
|
||||||
|
keys = e.keys;
|
||||||
|
inherit (e) desc;
|
||||||
|
}) keybinds.extra;
|
||||||
|
cheatRowsFor = g:
|
||||||
|
let rows = lib.filter (r: r.group == g) cheatBindRows;
|
||||||
|
in lib.optionals (rows != [ ]) (
|
||||||
|
[ ("── " + g + " ──") ]
|
||||||
|
++ map (r: padRight 22 r.keys + r.desc) rows
|
||||||
|
);
|
||||||
|
cheatRows = lib.concatLists (map cheatRowsFor cheatGroupOrder);
|
||||||
cheatsheetFile = pkgs.writeText "nomarchy-keybinds.txt"
|
cheatsheetFile = pkgs.writeText "nomarchy-keybinds.txt"
|
||||||
(lib.concatStringsSep "\n" cheatRows + "\n");
|
(lib.concatStringsSep "\n" cheatRows + "\n");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user