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:
@@ -7,85 +7,86 @@
|
||||
# key — the key name
|
||||
# action — the Hyprland dispatcher (+args) that the bind runs
|
||||
# desc — human label, shown in the cheatsheet
|
||||
# group — cheatsheet section: Window | Workspace | Menu | Media (#108)
|
||||
#
|
||||
# `extra` holds cheatsheet-only rows for binds generated elsewhere
|
||||
# (per-workspace numbers, mouse drags) so they still show up under SUPER+?.
|
||||
{
|
||||
binds = [
|
||||
{ mods = "$mod"; key = "Return"; action = "exec, $terminal"; desc = "Open terminal"; }
|
||||
{ mods = "$mod"; key = "Space"; action = "exec, rofi -show drun -theme launcher"; desc = "App launcher"; }
|
||||
{ mods = "$mod"; key = "M"; action = "exec, nomarchy-menu"; desc = "Main menu"; }
|
||||
{ mods = "$mod"; key = "E"; action = "exec, $terminal -e yazi"; desc = "File manager (yazi)"; }
|
||||
{ mods = "$mod"; key = "Q"; action = "killactive"; desc = "Close window"; }
|
||||
{ mods = "$mod"; key = "F"; action = "fullscreen"; desc = "Fullscreen"; }
|
||||
{ mods = "$mod"; key = "V"; action = "togglefloating"; desc = "Toggle floating"; }
|
||||
{ mods = "$mod SHIFT"; key = "E"; action = "exit"; desc = "Exit Hyprland"; }
|
||||
{ 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"; group = "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)"; group = "Window"; }
|
||||
{ mods = "$mod"; key = "Q"; action = "killactive"; desc = "Close window"; group = "Window"; }
|
||||
{ mods = "$mod"; key = "F"; action = "fullscreen"; desc = "Fullscreen"; group = "Window"; }
|
||||
{ mods = "$mod"; key = "V"; action = "togglefloating"; desc = "Toggle floating"; group = "Window"; }
|
||||
{ mods = "$mod SHIFT"; key = "E"; action = "exit"; desc = "Exit Hyprland"; group = "Window"; }
|
||||
|
||||
# Theme picker (menu dispatcher): apply writes the state and runs
|
||||
# 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).
|
||||
{ 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
|
||||
# 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
|
||||
# the keysym must be the BASE key `slash`, not `question`: Hyprland
|
||||
# resolves the sym with Shift consumed, so `question` never matches while
|
||||
# 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.)
|
||||
# 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
|
||||
# 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 = "C"; action = "exec, nomarchy-menu calc"; desc = "Calculator"; }
|
||||
{ mods = "$mod CTRL"; key = "W"; action = "exec, nomarchy-menu web"; desc = "Web search"; }
|
||||
{ mods = "$mod CTRL"; key = "F"; action = "exec, nomarchy-menu files"; desc = "File search"; }
|
||||
{ mods = "$mod CTRL"; key = "E"; action = "exec, nomarchy-menu emoji"; desc = "Emoji picker"; }
|
||||
{ mods = "$mod CTRL"; key = "N"; action = "exec, nomarchy-menu network"; desc = "Network (networkmanager_dmenu)"; }
|
||||
{ mods = "$mod CTRL"; key = "B"; action = "exec, nomarchy-menu bluetooth"; desc = "Bluetooth"; }
|
||||
{ mods = "$mod CTRL"; key = "K"; action = "exec, nomarchy-menu keyboard"; desc = "Keyboard layout"; }
|
||||
{ mods = "$mod CTRL"; key = "S"; action = "exec, nomarchy-menu capture"; desc = "Screenshot / capture"; }
|
||||
{ mods = "$mod CTRL"; key = "P"; action = "exec, nomarchy-menu colorpicker"; desc = "Color picker (→ clipboard)"; }
|
||||
{ mods = "$mod CTRL"; key = "A"; action = "exec, nomarchy-menu ask"; desc = "Ask Claude"; }
|
||||
{ mods = "$mod CTRL"; key = "D"; action = "exec, nomarchy-menu dnd"; desc = "Do Not Disturb toggle"; }
|
||||
{ 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"; group = "Menu"; }
|
||||
{ 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"; group = "Menu"; }
|
||||
{ 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)"; group = "Menu"; }
|
||||
{ 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"; group = "Menu"; }
|
||||
{ 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)"; group = "Menu"; }
|
||||
{ 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"; group = "Media"; }
|
||||
# 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 = "T"; action = "exec, nomarchy-menu tools"; desc = "Tools 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"; group = "Menu"; }
|
||||
# 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
|
||||
# unusable (see the power-menu note above). Same dispatcher the power
|
||||
# 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
|
||||
# place that decides how a lock actually looks.
|
||||
{ mods = "$mod CTRL"; key = "L"; action = "exec, loginctl lock-session"; desc = "Lock screen"; }
|
||||
{ mods = "$mod SHIFT"; key = "C"; action = "exec, hyprpicker -a"; desc = "Color picker (→ clipboard)"; }
|
||||
{ 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)"; group = "Menu"; }
|
||||
|
||||
# Focus — SUPER + arrow keys.
|
||||
{ mods = "$mod"; key = "left"; action = "movefocus, l"; desc = "Focus left"; }
|
||||
{ mods = "$mod"; key = "right"; action = "movefocus, r"; desc = "Focus right"; }
|
||||
{ mods = "$mod"; key = "up"; action = "movefocus, u"; desc = "Focus up"; }
|
||||
{ mods = "$mod"; key = "down"; action = "movefocus, d"; desc = "Focus down"; }
|
||||
{ mods = "$mod"; key = "left"; action = "movefocus, l"; desc = "Focus left"; group = "Window"; }
|
||||
{ mods = "$mod"; key = "right"; action = "movefocus, r"; desc = "Focus right"; group = "Window"; }
|
||||
{ mods = "$mod"; key = "up"; action = "movefocus, u"; desc = "Focus up"; group = "Window"; }
|
||||
{ mods = "$mod"; key = "down"; action = "movefocus, d"; desc = "Focus down"; group = "Window"; }
|
||||
|
||||
# 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 = "right"; action = "movecurrentworkspacetomonitor, r"; desc = "Move workspace to right monitor"; }
|
||||
{ mods = "$mod ALT"; key = "up"; action = "movecurrentworkspacetomonitor, u"; desc = "Move workspace to upper monitor"; }
|
||||
{ mods = "$mod ALT"; key = "down"; action = "movecurrentworkspacetomonitor, d"; desc = "Move workspace to lower 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"; group = "Workspace"; }
|
||||
{ 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"; group = "Workspace"; }
|
||||
|
||||
# Screenshots (the menu's Capture module has the rest: OCR, recording).
|
||||
# Bare Print → region to clipboard; the two → file binds save a
|
||||
# timestamped PNG under ~/Pictures/Screenshots and toast the path, the
|
||||
# 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 = "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 = "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 = "$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 = ""; 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"; 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"; 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"; group = "Media"; }
|
||||
];
|
||||
|
||||
# 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
|
||||
# own per-device layout (a single one) is a no-op, never a leak.
|
||||
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 = [
|
||||
{ keys = "SUPER + 1-9, 0"; desc = "Switch to workspace 1-10 (0 = 10)"; }
|
||||
{ keys = "SUPER + SHIFT + 1-9, 0"; desc = "Move window to workspace 1-10 (0 = 10)"; }
|
||||
{ keys = "SUPER + drag"; desc = "Move (LMB) / resize (RMB) window"; }
|
||||
{ keys = "Volume / Brightness"; desc = "Hardware keys, shown via the OSD"; }
|
||||
{ keys = "Bar: click"; desc = "Caffeine — hold the screen awake (idle inhibitor)"; }
|
||||
{ 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)"; group = "Workspace"; }
|
||||
{ keys = "SUPER + drag"; desc = "Move (LMB) / resize (RMB) window"; group = "Window"; }
|
||||
{ keys = "Volume / Brightness"; desc = "Hardware keys, shown via the OSD"; group = "Media"; }
|
||||
{ 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
|
||||
# single documented glyph — the cheatsheet reads "SUPER + ?".
|
||||
in lib.replaceStrings [ "SHIFT + /" ] [ "?" ] (prefix + key);
|
||||
cheatRows =
|
||||
map (b: padRight 22 (prettyKeys b) + b.desc) (keybinds.binds
|
||||
# Grouped cheatsheet (#108): Window → Workspace → Menu → Media.
|
||||
# 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)
|
||||
keybinds.multiLayoutBinds)
|
||||
# Launch-or-focus binds (nomarchy.launchOrFocus, generated in
|
||||
# hyprland.nix) — same renderer, so they land in the cheatsheet too.
|
||||
++ map (e: padRight 22 (prettyKeys e)
|
||||
+ (if e.desc != "" then e.desc
|
||||
else "Focus or launch ${if e.command == "" then lib.toLower e.class else e.command}"))
|
||||
cfg.launchOrFocus
|
||||
++ map (e: padRight 22 e.keys + e.desc) keybinds.extra;
|
||||
++ map (e: {
|
||||
group = "Menu";
|
||||
keys = prettyKeys e;
|
||||
desc = if e.desc != "" then e.desc
|
||||
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"
|
||||
(lib.concatStringsSep "\n" cheatRows + "\n");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user