Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions bin/omarchy-menu-herdr-keybindings
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ function key_text(key, count, parts, i, text) {
text = ""

for (i = 1; i <= count; i++) {
text = text (text == "" ? "" : " + ") toupper(parts[i])
part = toupper(parts[i])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: part is not in the parameter list, so awk makes it a global. The rest of this file declares locals as trailing parameters (key_text(key, count, parts, i, text)), so part belongs there too.

if (part == "SUPER") part = "⌘"
else if (part == "ALT") part = "⌥"
else if (part == "CTRL" || part == "CONTROL") part = "⌃"
else if (part == "SHIFT") part = "⇧"

text = text (text == "" ? "" : " + ") part
}

return text
Expand Down Expand Up @@ -134,6 +140,14 @@ function describe(action, text) {
return text
}

function padded(text, width, measured) {
measured = text
gsub(/⌘|⌥|⌃|⇧/, "x", measured)
if (length(measured) >= width) return text

return text sprintf("%*s", width - length(measured), "")
}

function remember(action) {
if (action in seen) return
seen[action] = 1
Expand Down Expand Up @@ -200,15 +214,15 @@ FNR == NR {

END {
if ("prefix" in combos) {
printf "%-32s → %s\n", "PREFIX", combos["prefix"]
printf "%s → %s\n", padded("PREFIX", 32), combos["prefix"]
}

for (i = 1; i <= count; i++) {
action = order[i]
if (action == "prefix") continue
if (!(action in combos)) continue

printf "%-32s → %s\n", combos[action], describe(action)
printf "%s → %s\n", padded(combos[action], 32), describe(action)
}
}
' - "$config_file"
Expand Down
35 changes: 33 additions & 2 deletions bin/omarchy-menu-keybindings
Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,39 @@ output_binding_records() {
fi
}

format_display_records() {
awk -F '\t' '
BEGIN { OFS = "\t" }
{
delimiter = index($1, "→")
display = substr($1, 1, delimiter - 1)
sub(/[[:space:]]+$/, "", display)

count = split(display, parts, /[[:space:]]+/)
display = ""
for (i = 1; i <= count; i++) {
if (parts[i] == "SUPER") parts[i] = "⌘"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bug: this runs for everyone. Please wrap the symbol mapping so it only applies when omarchy-hw-apple-silicon (from #331) succeeds; otherwise upstream x86 users see ⌘ for their Windows key.

else if (parts[i] == "ALT") parts[i] = "⌥"
else if (parts[i] == "CTRL" || parts[i] == "CONTROL") parts[i] = "⌃"
else if (parts[i] == "SHIFT") parts[i] = "⇧"

display = display (display == "" ? "" : " ") parts[i]
}

action = substr($1, delimiter + length("→"))
sub(/^[[:space:]]+/, "", action)
measured = display
gsub(/⌘|⌥|⌃|⇧/, "x", measured)
padding = 35 - length(measured)
if (padding > 0) display = display sprintf("%*s", padding, "")

$1 = display " → " action
print
}'
}

output_keybindings() {
output_binding_records | cut -f1
output_binding_records | format_display_records | cut -f1
}

trim() {
Expand Down Expand Up @@ -661,7 +692,7 @@ dispatch_binding() {
if [[ $1 == "--print" || $1 == "-p" ]]; then
output_keybindings
else
records=$(output_binding_records)
records=$(output_binding_records | format_display_records)
selection=$(cut -f1 <<<"$records" |
omarchy-menu-select 'Keybindings' -- --width 800 --height 500)

Expand Down
20 changes: 14 additions & 6 deletions bin/omarchy-menu-tmux-keybindings
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ output_keybindings() (
function key_part_text(part, is_modifier, part_count) {
gsub(/^\\/, "", part)

if (is_modifier && part == "C") return "CTRL"
if (is_modifier && part == "M") return "ALT"
if (is_modifier && part == "S") return "SHIFT"
if (is_modifier && part == "C") return ""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same gate needed here: the tmux menu should only switch to ⌃/⌥/⇧ on Apple hardware.

if (is_modifier && part == "M") return ""
if (is_modifier && part == "S") return ""
if (part == "Space") return "SPACE"
if (part == "BSpace") return "BACKSPACE"
if (part == "BTab") return "SHIFT + TAB"
if (part == "BTab") return " + TAB"
if (part == "PPage") return "PAGE UP"
if (part == "NPage") return "PAGE DOWN"
if (part == "DC") return "DELETE"
Expand Down Expand Up @@ -90,6 +90,14 @@ function table_text(table) {
return toupper(table)
}

function padded(text, width, measured) {
measured = text
gsub(/⌘|⌥|⌃|⇧/, "x", measured)
if (length(measured) >= width) return text

return text sprintf("%*s", width - length(measured), "")
}

$1 == "prefix" && NF == 2 { prefix = $2; next }
$1 == "prefix2" && NF == 2 { prefix2 = $2; next }

Expand All @@ -101,7 +109,7 @@ $1 == "prefix2" && NF == 2 { prefix2 = $2; next }
prefix_description = prefix_description " / " key_text(prefix2)
}

printf "%-32s → %s\n", "PREFIX", prefix_description
printf "%s → %s\n", padded("PREFIX", 32), prefix_description
header_printed = 1
}

Expand All @@ -116,7 +124,7 @@ $1 == "prefix2" && NF == 2 { prefix2 = $2; next }
combo = table_text(table) " + " key_text(key)
}

printf "%-32s → %s\n", combo, note
printf "%s → %s\n", padded(combo, 32), note
}'
)

Expand Down
36 changes: 28 additions & 8 deletions test/shell.d/keybindings-menu-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,39 +61,39 @@ BINDS
rendered=$(keybindings)
[[ -n $rendered ]] || fail "the keybindings menu renders with a stubbed Hyprland"

grep -q 'SUPER + F *→ Full screen' <<<"$rendered" ||
grep -q ' + F *→ Full screen' <<<"$rendered" ||
fail "a chord with no alternative renders on its own" "$rendered"
pass "the keybindings menu renders its entries"

(( $(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" ||
grep -q ' + W / + 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" ||
grep -q '^ + W / + 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" ||
grep -q ' + S / + ~ *→ 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" ]] ||
[[ $(sed 's/⌘/x/g; s/⌥/x/g; s/⌃/x/g; s/⇧/x/g' <<<"$rendered" | awk -F '→' '{ print length($1) }' | 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 )) ||
(( $(sed 's/⌘/x/g; s/⌥/x/g; s/⌃/x/g; s/⇧/x/g' <<<"$rendered" | awk '{ print length($0) }' | 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"

Expand Down Expand Up @@ -127,7 +127,7 @@ bind
BINDS

rendered=$(keybindings)
grep -q 'SUPER + ~ *→ Toggle scratchpad' <<<"$rendered" ||
grep -q ' + ~ *→ Toggle scratchpad' <<<"$rendered" ||
fail "a keycode resolves to the symbol printed on the key too" "$rendered"
pass "a keycode resolves to the symbol printed on the key too"

Expand Down Expand Up @@ -167,7 +167,7 @@ BINDS
rendered=$(keybindings)
(( $(grep -c '→ Calculator$' <<<"$rendered") == 2 )) ||
fail "chords too wide to share a row stay on their own" "$rendered"
[[ $(awk -F '→' '{ print length($1) }' <<<"$rendered" | sort -u) == "36" ]] ||
[[ $(sed 's/⌘/x/g; s/⌥/x/g; s/⌃/x/g; s/⇧/x/g' <<<"$rendered" | awk -F '→' '{ print length($1) }' | sort -u) == "36" ]] ||
fail "chords too wide to share a row leave the column alone" "$rendered"
pass "chords too wide to share a row stay on their own"

Expand Down Expand Up @@ -220,3 +220,23 @@ for action in "${expected_alternatives[@]}"; do
fail "every action named as having an alternative is bound twice" "$action"
done
pass "every action named as having an alternative is bound twice"

# A user-defined chord can exceed the standard display column. It must remain
# intact without backwards padding, and an arrow in its description belongs to
# the description rather than changing where the display formatter splits the
# record. The dispatcher fields remain attached after the display field.
stub_hyprctl <<BINDS
$(exec_bind 77 "SUPER SHIFT CTRL ALT + EXTRAORDINARILY_LONG_KEY_NAME" "Explain → advanced behavior" "printf dispatch-metadata-survives")
BINDS

rendered=$(keybindings)
grep -qF '⌘ ⇧ ⌃ ⌥ + EXTRAORDINARILY_LONG_KEY_NAME → Explain → advanced behavior' <<<"$rendered" ||
fail "an overlong chord and arrow-bearing description render intact" "$rendered"
pass "overlong chords and arrow-bearing descriptions render intact"

formatter_functions=$(sed -n '/^format_display_records()/,/^}/p' "$ROOT/bin/omarchy-menu-keybindings")
eval "$formatter_functions"
formatted_record=$(printf '%s\n' $'SUPER + K → Explain → advanced behavior\texec\tprintf dispatch-metadata-survives' | format_display_records)
[[ $(cut -f2- <<<"$formatted_record") == $'exec\tprintf dispatch-metadata-survives' ]] ||
fail "display formatting preserves dispatcher metadata" "$formatted_record"
pass "display formatting preserves dispatcher metadata"
62 changes: 62 additions & 0 deletions test/shell.d/mac-keybinding-labels-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash

source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh"

tmpdir=$(mktemp -d) && [[ -n $tmpdir && -d $tmpdir ]] ||
fail "the test gets a temporary directory for keybinding command stubs"
trap 'rm -rf "$tmpdir"' EXIT

stub_bin="$tmpdir/bin"
mkdir -p "$stub_bin"

cat >"$stub_bin/tmux" <<'TMUX'
#!/bin/bash
cat <<'OUTPUT'
prefix C-a
prefix2 M-b
prefix C-S-x Example binding
root M-y Root binding
copy-mode-vi C-z Copy binding
copy-mode-vi BTab Reverse selection
OUTPUT
TMUX
chmod +x "$stub_bin/tmux"

touch "$tmpdir/tmux.conf"
tmux_output=$(PATH="$stub_bin:$PATH" OMARCHY_PATH="$ROOT" \
"$ROOT/bin/omarchy-menu-tmux-keybindings" --print --config "$tmpdir/tmux.conf")

grep -q '^PREFIX *→ ⌃ + A / ⌥ + B$' <<<"$tmux_output" ||
fail "Tmux prefix modifiers use Apple symbols" "$tmux_output"
grep -qF 'PREFIX + ⌃ + ⇧ + X' <<<"$tmux_output" ||
fail "Tmux binding modifiers use Apple symbols" "$tmux_output"
grep -qF '⌥ + Y' <<<"$tmux_output" ||
fail "Tmux root modifiers use Apple symbols" "$tmux_output"
grep -qF 'COPY MODE + ⇧ + TAB' <<<"$tmux_output" ||
fail "Tmux BTab uses the Apple Shift symbol" "$tmux_output"
pass "Tmux keybindings use Apple modifier symbols"

cat >"$stub_bin/herdr" <<'HERDR'
#!/bin/bash
cat <<'OUTPUT'
#[keys]
# prefix = "control+a"
# navigate_left = "super+alt+shift+h"
# close = "ctrl+w"
# toggle = ["super+control+shift+alt+a", "super+control+shift+alt+b", "super+control+shift+alt+c", "super+control+shift+alt+d"]
OUTPUT
HERDR
chmod +x "$stub_bin/herdr"

herdr_output=$(PATH="$stub_bin:$PATH" \
"$ROOT/bin/omarchy-menu-herdr-keybindings" --print --config /dev/null)

grep -q '^PREFIX *→ ⌃ + A$' <<<"$herdr_output" ||
fail "Herdr prefix modifiers use Apple symbols" "$herdr_output"
grep -qF 'NAVIGATE + ⌘ + ⌥ + ⇧ + H' <<<"$herdr_output" ||
fail "Herdr navigation modifiers use Apple symbols" "$herdr_output"
grep -qF '⌃ + W' <<<"$herdr_output" ||
fail "Herdr CTRL aliases use the Control symbol" "$herdr_output"
grep -qF '⌘ + ⌃ + ⇧ + ⌥ + A / ⌘ + ⌃ + ⇧ + ⌥ + B / ⌘ + ⌃ + ⇧ + ⌥ + C / ⌘ + ⌃ + ⇧ + ⌥ + D → Toggle' <<<"$herdr_output" ||
fail "Herdr chords longer than the display column are not padded backwards" "$herdr_output"
pass "Herdr keybindings use Apple modifier symbols"
16 changes: 8 additions & 8 deletions test/shell.d/menu-keybindings-fkeys-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,19 @@ EOF

output=$(PATH="$mock_bin:$PATH" XDG_CACHE_HOME="$cache_dir" "$ROOT/bin/omarchy-menu-keybindings" --print)

tr -s ' ' <<<"$output" | grep -qF 'SHIFT + F2 → Keyboard brightness up' || \
fail "SHIFT + XF86MonBrightnessUp renders as SHIFT + F2 with its description" "$output"
tr -s ' ' <<<"$output" | grep -qF ' + F2 → Keyboard brightness up' || \
fail "SHIFT + XF86MonBrightnessUp renders as + F2 with its description" "$output"

tr -s ' ' <<<"$output" | grep -qF 'SHIFT + F1 → Keyboard brightness down' || \
fail "SHIFT + XF86MonBrightnessDown renders as SHIFT + F1 with its description" "$output"
tr -s ' ' <<<"$output" | grep -qF ' + F1 → Keyboard brightness down' || \
fail "SHIFT + XF86MonBrightnessDown renders as + F1 with its description" "$output"

tr -s ' ' <<<"$output" | grep -qF 'ALT + F2 → Brightness up precise' || \
fail "modifier combos keep the F-key name (ALT + F2)" "$output"
tr -s ' ' <<<"$output" | grep -qF ' + F2 → Brightness up precise' || \
fail "modifier combos keep the F-key name ( + F2)" "$output"

grep -qF 'XF86MonBrightness' <<<"$output" && \
fail "raw XF86MonBrightness symbols no longer leak into the menu" "$output"

tr -s ' ' <<<"$output" | grep -qF 'SUPER + Q → Close window' || \
fail "unrelated bindings render unchanged (SUPER + Q)" "$output"
tr -s ' ' <<<"$output" | grep -qF ' + Q → Close window' || \
fail "unrelated bindings use the Apple Command symbol (⌘ + Q)" "$output"

pass "keybindings menu shows Mac physical key names (F1/F2), stale caches ignored"
Loading