#!/bin/bash source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh" require_command lua require_command xkbcli tmpdir=$(mktemp -d) && [[ -n $tmpdir && -d $tmpdir ]] || fail "the test gets a temporary directory to stub Hyprland in" trap 'rm -rf "$tmpdir"' EXIT home="$tmpdir/home" stub_bin="$tmpdir/bin" mkdir -p "$home/.config" "$stub_bin" cp -r "$ROOT/config/hypr" "$home/.config/hypr" # No platform package: neither its key names nor its binds. menu="$tmpdir/omarchy-menu-keybindings" platform_root_copy "$ROOT/bin/omarchy-menu-keybindings" "$menu" "$tmpdir/no-platform" # The menu reads binds from Hyprland, which is not running here, so stand in for # it. A Lua bind reports dispatcher __lua and no arg, and the menu recovers both # from the Lua source; an exec bind carries its own command. Both shapes matter: # what two chords dispatch is what decides whether they share a row. lua_bind() { printf 'bind\n\tmodmask: %s\n\tsubmap: \n\tkey: %s\n\tkeycode: 0\n\tcatchall: false\n\tdescription: %s\n\tdispatcher: __lua\n\targ: \n' "$1" "$2" "$3" } exec_bind() { printf 'bind\n\tmodmask: %s\n\tsubmap: \n\tkey: %s\n\tkeycode: 0\n\tcatchall: false\n\tdescription: %s\n\tdispatcher: exec\n\targ: %s\n' "$1" "$2" "$3" "$4" } stub_hyprctl() { { echo '#!/bin/bash' echo 'case "$1" in' echo ' binds) cat <<'"'"'BINDS'"'"'' cat echo 'BINDS' echo ' ;;' echo ' devices) echo "active keymap: English (US)" ;;' echo 'esac' } >"$stub_bin/hyprctl" chmod +x "$stub_bin/hyprctl" } keybindings() { env -i PATH="$stub_bin:$ROOT/bin:$PATH" HOME="$home" \ XDG_CACHE_HOME="$tmpdir/cache" OMARCHY_PATH="$ROOT" \ bash "$menu" --print } # Closing a window and toggling the scratchpad are two of the actions Omarchy # binds twice on purpose. The last bind carries the longest description Omarchy # ships, which is what puts a row closest to the width the menu allows. stub_hyprctl <"$tmpdir/init.lua" LUA_INIT="@$tmpdir/init.lua" lua -e '' && [[ -e $tmpdir/init-ran ]] || fail "the LUA_INIT probe runs in a plain lua" rm -f "$tmpdir/init-ran" env -i PATH="$stub_bin:$ROOT/bin:$PATH" HOME="$home" XDG_CACHE_HOME="$tmpdir/cache-init" OMARCHY_PATH="$ROOT" \ LUA_INIT="@$tmpdir/init.lua" LUA_INIT_5_5="@$tmpdir/init.lua" LUA_INIT_5_4="@$tmpdir/init.lua" LUA_PATH="$tmpdir/?.lua" \ bash "$ROOT/bin/omarchy-menu-keybindings" --print >/dev/null [[ ! -e $tmpdir/init-ran ]] || fail "the menu's config scan ignores LUA_INIT from the environment" pass "the menu's config scan ignores LUA_INIT and LUA_PATH from the environment" (( $(grep -c '→ Close window$' <<<"$rendered") == 1 )) || fail "an alternative chord joins the row of the first one" "$rendered" grep -q 'SUPER + W / SUPER + Q *→ Close window' <<<"$rendered" || fail "a shared row names both chords" "$rendered" pass "an alternative chord joins the row of the first one" # Which chord leads is the whole point of keeping Hyprland's order: SUPER + W is # the documented default and SUPER + Q the alternative bound after it. grep -q '^SUPER + W / SUPER + Q' <<<"$rendered" || fail "the chord declared first leads a shared row" "$rendered" pass "the chord declared first leads a shared row" # Hyprland calls the key left of 1 "grave". Nobody reads their keyboard that way. grep -q 'SUPER + S / SUPER + ~ *→ Toggle scratchpad' <<<"$rendered" || fail "the grave key reads as the symbol printed on it" "$rendered" ! grep -q 'grave' <<<"$rendered" || fail "no entry still says grave" "$rendered" pass "the grave key reads as the symbol printed on it" # Monospace menu: every arrow sits in one column, and nothing is allowed past # it. A row that overruns pushes its own arrow out of line. [[ $(awk -F '→' '{ print length($1) }' <<<"$rendered" | sort -u) == "36" ]] || fail "every entry pads its chords to the same column" "$rendered" pass "every entry pads its chords to the same column" # The menu elides a row that outgrows its card: 754px of label, 78 monospace # characters at the heading size. The longest entry Omarchy ships sits at 74, so # a row has four characters of room and no more. (( $(awk '{ print length($0) }' <<<"$rendered" | sort -rn | head -1) <= 78 )) || fail "no entry outgrows the width the menu gives it" "$rendered" pass "no entry outgrows the width the menu gives it" # Priority ordering reads the row, and the chord sharing it must not reclassify # the entry: XF86Calculator alone belongs in the tail the menu keeps for media # keys, while the calculator itself sits in the body of the list. stub_hyprctl <= 2 )) || fail "every action named as having an alternative is bound twice" "$action" done pass "every action named as having an alternative is bound twice" # The terminal bind is a Lua function Hyprland reports only as __lua, so picking # it from the menu has to run the command the function stands for. stub_hyprctl </dev/null grep -qP '→ Terminal\texec\tomarchy-launch-terminal$' "$tmpdir"/cache/omarchy/keybindings-*.records || fail "picking the terminal bind from the menu launches a terminal" "$(cat "$tmpdir"/cache/omarchy/keybindings-*.records)" pass "picking the terminal bind from the menu launches a terminal"