#!/usr/bin/env bash # scripts/gen-keybinds.sh — generate the niri keybinding cheat sheet (markdown) # from a keybinds.kdl file. # # Usage: # gen-keybinds.sh [keybinds.kdl] # markdown to stdout # gen-keybinds.sh [keybinds.kdl] --write OUT # markdown to OUT # # Default input: ~/.config/niri/cfg/keybinds.kdl # Recognized: section comments `// ─── Name ───`, bind lines with optional # hotkey-overlay-title="..."; the action inside { } is used when there is no title. set -euo pipefail usage() { sed -n '2,11p' "$0" | sed 's/^# \{0,1\}//'; } KBD="" OUT="" while [ $# -gt 0 ]; do case "$1" in -h|--help) usage; exit 0 ;; --write) OUT="${2:?--write needs an output path}"; shift 2 ;; *) KBD="$1"; shift ;; esac done KBD="${KBD:-$HOME/.config/niri/cfg/keybinds.kdl}" [ -f "$KBD" ] || { echo "error: no such file: $KBD" >&2; exit 1; } gen() { echo "---" echo "type: reference" echo "title: Niri Keybindings" echo "description: Live keybinding cheat sheet generated from $(basename "$KBD") — do not edit by hand." echo "tags:" echo " - niri" echo " - keybindings" echo "generated: { by: scripts/gen-keybinds.sh }" echo "---" echo echo "# Niri Keybindings" echo echo "> GENERATED by \`scripts/gen-keybinds.sh\` from \`$(basename "$KBD")\` — do not edit by hand." echo awk ' # Section marker: a comment decorated with box-drawing dashes on both sides, # `// ─── Name ───`. The dash is matched as a LITERAL and removed with gsub — never # with a quantifier on the multibyte character. Under LC_ALL=C (cron, systemd units, # agent shells) gawk works byte-wise, `─+` then means "the last byte of ─, repeated", # and every header vanishes while the script still exits 0. Plain comments stay # comments: only a dash-decorated one opens a section. /^[[:space:]]*\/\/[[:space:]]*─/ { s = $0 sub(/^[[:space:]]*\/\/[[:space:]]*/, "", s) sub(/[[:space:]]+$/, "", s) if (s ~ /─ .*─/) { gsub(/─/, "", s) gsub(/[[:space:]]+/, " ", s) sub(/^ /, "", s); sub(/ $/, "", s) if (in_table) print "" print "## " s print "" print "| Key | Action |" print "|-----|--------|" in_table = 1 } next } # bind line: KEY [flags] [hotkey-overlay-title="..."] { action; } /^[[:space:]]*[A-Z][A-Za-z0-9+]*( |$)/ && /\{/ { key = $1 title = "" if (match($0, /hotkey-overlay-title="[^"]*"/)) { title = substr($0, RSTART + 22, RLENGTH - 23) } act = "" if (match($0, /\{[^}]*\}/)) { act = substr($0, RSTART + 1, RLENGTH - 2) sub(/;[[:space:]]*$/, "", act) gsub(/[[:space:]]+/, " ", act) sub(/^ /, "", act); sub(/ $/, "", act) } out = (title != "") ? title : act gsub(/\|/, "\\|", out) print "| `" key "` | " out " |" n++ next } END { if (in_table) print "" printf("\n", n) > "/dev/stderr" } ' "$KBD" } if [ -n "$OUT" ]; then mkdir -p "$(dirname "$OUT")" gen > "$OUT" echo "wrote $OUT" >&2 else gen fi