* Decode webp in the shell The background and the lock screen are drawn by Quickshell, so they decode through Qt, which ships handlers for png, jpeg and gif but not webp. QImageReader answers "Unsupported image format" and the layer comes up blank. Any third-party theme shipping a .webp background hits this today, even though every path that goes looking for a background already globs the extension. qt6-imageformats supplies the missing plugin for 71 KB downloaded. Its one new dependency of substance, libwebp, is already on every machine by way of libvips. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Store theme backgrounds as webp WebP codes both of the things these backgrounds are made of better than the formats they were in: the photographs, where its lossy mode is worth a third or more over JPEG at matched quality, and the flat art and dot patterns, where its lossless mode undercuts an oxipng-packed PNG. 28 of them become lossless webp and decode bit-for-bit identically (AE=0), so the dot patterns and flat-shaded pieces carry no quality question at all. That includes 0-launch, whose alpha channel comes through intact. The other 51 are photographs held to the same 38 dB PSNR floor as the JPEG pass, landing between 38.0 and 54.6 dB. Every image keeps its exact pixel dimensions, for 29.8 MB. Each one is encoded from the original as it stands in quattro rather than from the file the earlier commits produced, so nothing picks up a second generation of loss on the way here. 13 stay JPEG. WebP is plainly larger for most of them, and three are grainy enough that its filter smooths the grain instead of coding it: PSNR plateaus near 34 dB however high the quality goes, well under the floor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
810 lines
40 KiB
Bash
Executable File
810 lines
40 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
|
CLI="$ROOT/bin/omarchy"
|
|
TMPDIRS=()
|
|
|
|
export PATH="$ROOT/bin:$PATH"
|
|
|
|
# Assigns a fresh temporary directory to the named variable and registers it for
|
|
# removal on exit, so every scratch directory this suite makes is cleaned up.
|
|
make_tmpdir() {
|
|
local -n dir_ref="$1"
|
|
|
|
dir_ref=$(mktemp -d)
|
|
TMPDIRS+=("$dir_ref")
|
|
}
|
|
|
|
pass() {
|
|
printf 'ok - %s\n' "$1"
|
|
}
|
|
|
|
fail() {
|
|
printf 'not ok - %s\n' "$1" >&2
|
|
exit 1
|
|
}
|
|
|
|
assert_output_contains() {
|
|
local description="$1"
|
|
local output="$2"
|
|
local expected="$3"
|
|
|
|
if [[ $output != *"$expected"* ]]; then
|
|
printf 'Expected output to contain: %s\n' "$expected" >&2
|
|
printf 'Actual output:\n%s\n' "$output" >&2
|
|
fail "$description"
|
|
fi
|
|
|
|
pass "$description"
|
|
}
|
|
|
|
cleanup() {
|
|
local dir
|
|
|
|
for dir in ${TMPDIRS[@]+"${TMPDIRS[@]}"}; do
|
|
[[ -d $dir ]] && rm -rf "$dir"
|
|
done
|
|
|
|
return 0
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
output=$("$CLI" --help)
|
|
assert_output_contains "main help renders" "$output" "Omarchy command center"
|
|
assert_output_contains "main help includes hardware group" "$output" "hw"
|
|
assert_output_contains "main help includes package group" "$output" "pkg"
|
|
if grep -Eq '^ [a-z0-9-]+[[:space:]].*\([0-9]+\)$' <<<"$output"; then
|
|
fail "main help does not show group counts"
|
|
fi
|
|
pass "main help does not show group counts"
|
|
|
|
output=$("$CLI" commands)
|
|
assert_output_contains "commands lists documented commands" "$output" "omarchy theme set <theme-name>"
|
|
|
|
"$CLI" commands --json | jq -e '.ok == true and (.commands | length >= 200)' >/dev/null
|
|
pass "commands --json is valid JSON with full bin coverage"
|
|
|
|
"$CLI" commands --json | jq -e 'all(.commands[]; .summary != "undocumented")' >/dev/null
|
|
pass "all included commands have summaries"
|
|
|
|
"$CLI" commands --json | jq -e 'all(.commands[]; has("binary") and has("filename_route") and has("routes") and (has("legacy") | not) and (has("usage") | not) and (has("visibility") | not) and (has("mutates") | not) and (has("interactive") | not))' >/dev/null
|
|
pass "JSON uses binary/routes and omits legacy/usage/extra metadata"
|
|
|
|
"$CLI" commands --check >/dev/null
|
|
pass "commands --check passes"
|
|
|
|
"$CLI" commands --all >/dev/null
|
|
pass "commands --all does not crash"
|
|
|
|
"$CLI" commands --all --json | jq -e '.commands[] | select(.route == "omarchy hyprland window gaps toggle" and .summary != "undocumented")' >/dev/null
|
|
pass "fallback commands are inferred and documented"
|
|
|
|
"$CLI" commands --all --json | jq -e '.commands[] | select(.route == "omarchy dev benchmark cli")' >/dev/null
|
|
pass "benchmark command is discoverable in all commands"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-pkg-add" and .route == "omarchy pkg add" and .filename_route == "omarchy pkg add" and (.routes | index("omarchy pkg add")))' >/dev/null
|
|
pass "JSON exposes direct pkg add route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-install-gaming-xbox-cloud" and .route == "omarchy install gaming xbox-cloud" and .filename_route == "omarchy install gaming xbox cloud" and (.routes | index("omarchy install gaming xbox cloud")))' >/dev/null
|
|
pass "Xbox Cloud installer keeps hyphenated canonical route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-install-gaming-xbox-controllers" and .route == "omarchy install gaming xbox-controllers" and .filename_route == "omarchy install gaming xbox controllers" and (.routes | index("omarchy install gaming xbox controllers")))' >/dev/null
|
|
pass "Xbox controller installer keeps hyphenated canonical route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-remove-gaming-xbox-controllers" and .route == "omarchy remove gaming xbox-controllers" and .filename_route == "omarchy remove gaming xbox controllers" and (.routes | index("omarchy remove gaming xbox controllers")))' >/dev/null
|
|
pass "Xbox controller remover keeps hyphenated canonical route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-install-gaming-geforce-now" and .route == "omarchy install gaming geforce-now" and .filename_route == "omarchy install gaming geforce now" and (.routes | index("omarchy install gaming geforce now")))' >/dev/null
|
|
pass "GeForce NOW installer keeps hyphenated canonical route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-remove-gaming-geforce-now" and .route == "omarchy remove gaming geforce-now" and .filename_route == "omarchy remove gaming geforce now" and (.routes | index("omarchy remove gaming geforce now")))' >/dev/null
|
|
pass "GeForce NOW remover keeps hyphenated canonical route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-install-gaming-gpu-lib32" and .route == "omarchy install gaming gpu-lib32" and .filename_route == "omarchy install gaming gpu lib32" and (.routes | index("omarchy install gaming gpu lib32")))' >/dev/null
|
|
pass "GPU lib32 installer keeps hyphenated canonical route"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-refresh-pacman" and .requires_sudo == true)' >/dev/null
|
|
pass "sudo metadata marks sudo commands"
|
|
|
|
output=$("$CLI" theme --help)
|
|
assert_output_contains "group help renders" "$output" "Theme commands"
|
|
|
|
output=$("$CLI" install --help)
|
|
assert_output_contains "install group help renders" "$output" "Install commands"
|
|
assert_output_contains "install group includes browser route" "$output" "omarchy install browser"
|
|
|
|
output=$("$CLI" install)
|
|
assert_output_contains "bare group renders help instead of picker" "$output" "Install commands"
|
|
assert_output_contains "bare group includes browser route" "$output" "omarchy install browser"
|
|
|
|
output=$("$CLI" toggle)
|
|
assert_output_contains "bare root command with children renders help" "$output" "Toggle commands"
|
|
assert_output_contains "bare toggle help includes child route" "$output" "omarchy toggle nightlight"
|
|
|
|
output=$("$CLI" pkg --help)
|
|
assert_output_contains "package group includes pkg add fallback route" "$output" "omarchy pkg add <packages...>"
|
|
|
|
output=$("$CLI" restart --help)
|
|
assert_output_contains "restart group includes inferred commands" "$output" "omarchy restart btop"
|
|
assert_output_contains "restart group includes all restart commands" "$output" "omarchy restart wifi"
|
|
|
|
output=$("$CLI" hw --help)
|
|
assert_output_contains "hardware group help renders" "$output" "omarchy hw asus rog"
|
|
assert_output_contains "hardware group includes touchpad" "$output" "omarchy hw touchpad"
|
|
|
|
output=$("$CLI" hw asus)
|
|
assert_output_contains "partial hardware prefix renders matching commands" "$output" "omarchy hw asus rog"
|
|
assert_output_contains "partial hardware prefix includes nested match" "$output" "omarchy hw asus zenbook ux5406aa"
|
|
|
|
output=$("$CLI" menu --help)
|
|
assert_output_contains "menu group includes share fallback route" "$output" "omarchy menu share"
|
|
|
|
output=$("$CLI" share)
|
|
assert_output_contains "bare required-arg alias renders CLI help" "$output" "Usage:"
|
|
assert_output_contains "bare share help uses canonical route" "$output" "omarchy share <clipboard|file|folder> [path...]"
|
|
|
|
output=$("$CLI" menu share)
|
|
assert_output_contains "bare required-arg filename route renders CLI help" "$output" "omarchy share <clipboard|file|folder> [path...]"
|
|
|
|
CLI="$CLI" python3 <<'PY'
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
cli = os.environ['CLI']
|
|
commands = json.loads(subprocess.check_output([cli, 'commands', '--json'], text=True))['commands']
|
|
by_group = {}
|
|
for command in commands:
|
|
binary = command['binary']
|
|
stem = binary.removeprefix('omarchy-')
|
|
group = stem.split('-', 1)[0]
|
|
filename_route = 'omarchy ' + stem.replace('-', ' ')
|
|
by_group.setdefault(group, []).append((binary, filename_route, command['route']))
|
|
|
|
missing = []
|
|
for group, rows in sorted(by_group.items()):
|
|
proc = subprocess.run([cli, group, '--help'], text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
output = proc.stdout + proc.stderr
|
|
if proc.returncode != 0:
|
|
missing.append((group, '<group-help-failed>', f'exit {proc.returncode}'))
|
|
continue
|
|
for binary, filename_route, canonical_route in rows:
|
|
if filename_route not in output and canonical_route not in output and binary not in output:
|
|
missing.append((group, binary, filename_route))
|
|
|
|
if missing:
|
|
for row in missing:
|
|
print('\t'.join(row), file=sys.stderr)
|
|
sys.exit(1)
|
|
PY
|
|
pass "every filename-derived group help represents its bins"
|
|
|
|
output=$(timeout 5 "$CLI" theme set --help)
|
|
assert_output_contains "command help renders without executing" "$output" "Binary:"
|
|
assert_output_contains "theme set help names binary" "$output" "omarchy-theme-set"
|
|
|
|
output=$(timeout 5 "$CLI" update --help)
|
|
assert_output_contains "mutating command help does not execute target" "$output" "omarchy-update"
|
|
if [[ $output == *"omarchy update perform"* ]]; then
|
|
fail "hidden update perform compatibility wrapper is not shown"
|
|
fi
|
|
pass "hidden update perform compatibility wrapper is not shown"
|
|
|
|
# These three are install-time plumbing the ISO and install leaves call, so
|
|
# they stay out of the listing a user browses -- while still routing, because
|
|
# those callers use the CLI. A GROUP_DESCRIPTIONS entry would put the group
|
|
# back in the top-level listing even with every command in it hidden, which is
|
|
# why apply has none.
|
|
output=$(timeout 5 "$CLI")
|
|
if [[ $output == *"apply"* ]]; then
|
|
fail "a group whose commands are all hidden stays out of the top-level listing"
|
|
fi
|
|
pass "a group whose commands are all hidden stays out of the top-level listing"
|
|
|
|
for internal in omarchy-apply-system omarchy-apply-hardware omarchy-apply-lock; do
|
|
if "$CLI" commands --json | jq -e --arg binary "$internal" \
|
|
'.commands[] | select(.binary == $binary)' >/dev/null; then
|
|
fail "$internal stays out of the default command listing"
|
|
fi
|
|
|
|
"$CLI" commands --all --json | jq -e --arg binary "$internal" \
|
|
'.commands[] | select(.binary == $binary) | select(.hidden)' >/dev/null ||
|
|
fail "$internal is still listed by commands --all"
|
|
done
|
|
pass "install-time setup plumbing is hidden from the setup wizards"
|
|
|
|
output=$(timeout 5 "$CLI" apply hardware --help)
|
|
assert_output_contains "hidden setup plumbing still routes" "$output" "omarchy-apply-hardware"
|
|
|
|
output=$("$CLI" screenshot --help)
|
|
assert_output_contains "root alias resolves to command help" "$output" "omarchy-capture-screenshot"
|
|
|
|
"$CLI" commands --json | jq -e '.commands[] | select(.binary == "omarchy-capture-screenshot") | .aliases | index("omarchy screenshot")' >/dev/null
|
|
pass "aliases are included in JSON metadata"
|
|
|
|
output=$("$CLI" pkg add --help)
|
|
assert_output_contains "pkg add help resolves" "$output" "omarchy-pkg-add"
|
|
assert_output_contains "pkg add help shows direct route" "$output" "omarchy pkg add <packages...>"
|
|
|
|
output=$("$CLI" system reboot --help)
|
|
assert_output_contains "system command help is safe" "$output" "omarchy-system-reboot"
|
|
|
|
output=$("$CLI" dev benchmark cli --repeat=1)
|
|
assert_output_contains "benchmark command runs" "$output" "Omarchy CLI benchmark"
|
|
|
|
"$CLI" theme list >/dev/null
|
|
pass "safe dispatch works for theme list"
|
|
|
|
"$CLI" theme current >/dev/null
|
|
pass "safe dispatch works for theme current"
|
|
|
|
"$CLI" font list >/dev/null
|
|
pass "safe dispatch works for font list"
|
|
|
|
"$CLI" font current >/dev/null
|
|
pass "safe dispatch works for font current"
|
|
|
|
make_tmpdir PI_TMPDIR
|
|
NEXT_THEME="$PI_TMPDIR/.local/state/omarchy/current/next-theme"
|
|
CURRENT_THEME="$PI_TMPDIR/.local/state/omarchy/current/theme"
|
|
USER_THEMED="$PI_TMPDIR/.config/omarchy/themed"
|
|
mkdir -p "$NEXT_THEME" "$CURRENT_THEME" "$USER_THEMED"
|
|
|
|
cat >"$NEXT_THEME/colors.toml" <<'EOF'
|
|
mode = "light"
|
|
accent = "#336699"
|
|
hyprland_active_border = "rgba(010203ee) rgba(040506ee) 45deg"
|
|
background = "#000000"
|
|
dark_background = "#010101"
|
|
darker_background = "#020202"
|
|
lighter_background = "#030303"
|
|
foreground = "#ffffff"
|
|
dark_foreground = "#cccccc"
|
|
light_foreground = "#dddddd"
|
|
selection = "#808080"
|
|
red = "#ff0000"
|
|
green = "#00ff00"
|
|
yellow = "#ffff00"
|
|
blue = "#0000ff"
|
|
magenta = "#ff00ff"
|
|
cyan = "#00ffff"
|
|
muted = "#111111"
|
|
bright_red = "#ff1111"
|
|
bright_green = "#11ff11"
|
|
bright_yellow = "#ffff11"
|
|
bright_blue = "#1111ff"
|
|
bright_magenta = "#ff11ff"
|
|
bright_cyan = "#11ffff"
|
|
bright_foreground = "#eeeeee"
|
|
|
|
# Canonical values must win when a transitional theme defines both forms.
|
|
bg = "#abcdef"
|
|
dark_bg = "#abcdef"
|
|
darker_bg = "#abcdef"
|
|
lighter_bg = "#abcdef"
|
|
fg = "#abcdef"
|
|
dark_fg = "#abcdef"
|
|
light_fg = "#abcdef"
|
|
bright_fg = "#abcdef"
|
|
EOF
|
|
|
|
cat >"$USER_THEMED/mix-test.txt.tpl" <<'EOF'
|
|
mix={{ mix background foreground 50% }}
|
|
strip={{ mix_strip background foreground 50% }}
|
|
rgb={{ mix_rgb background foreground 50% }}
|
|
EOF
|
|
|
|
cat >"$USER_THEMED/gradient-test.txt.tpl" <<'EOF'
|
|
hypr={{ hypr_gradient hyprland_active_border accent }}
|
|
shell={{ gradient_start hyprland_active_border accent }}
|
|
shell-gradient={{ shell_gradient hyprland_active_border accent }}
|
|
fallback-hypr={{ hypr_gradient missing accent }}
|
|
fallback-shell={{ gradient_start missing accent }}
|
|
fallback-shell-gradient={{ shell_gradient missing accent }}
|
|
EOF
|
|
|
|
cat >"$USER_THEMED/alias-test.txt.tpl" <<'EOF'
|
|
color={{ color1 }}
|
|
strip={{ color1_strip }}
|
|
rgb={{ color1_rgb }}
|
|
magenta={{ magenta }}
|
|
legacy-purple={{ purple }}
|
|
bright-magenta={{ bright_magenta }}
|
|
legacy-bright-purple={{ bright_purple }}
|
|
background={{ background }}
|
|
foreground={{ foreground }}
|
|
legacy-background={{ bg }}
|
|
legacy-dark-background={{ dark_bg }}
|
|
legacy-darker-background={{ darker_bg }}
|
|
legacy-lighter-background={{ lighter_bg }}
|
|
legacy-foreground={{ fg }}
|
|
legacy-dark-foreground={{ dark_fg }}
|
|
legacy-light-foreground={{ light_fg }}
|
|
legacy-bright-foreground={{ bright_fg }}
|
|
legacy-mix={{ mix bg fg 50% }}
|
|
selection-background={{ selection_background }}
|
|
selection-foreground={{ selection_foreground }}
|
|
cursor-alias={{ cursor }}
|
|
EOF
|
|
|
|
cat >"$NEXT_THEME/shell.lock.toml" <<'EOF'
|
|
text = "#ffffff"
|
|
placeholder = "#ffffff"
|
|
border = "#ffffff"
|
|
EOF
|
|
|
|
OMARCHY_PATH="$ROOT" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-templates"
|
|
grep -qx 'mix=#808080' "$NEXT_THEME/mix-test.txt" || fail "theme template mix helper works"
|
|
grep -qx 'strip=808080' "$NEXT_THEME/mix-test.txt" || fail "theme template mix_strip helper works"
|
|
grep -qx 'rgb=128,128,128' "$NEXT_THEME/mix-test.txt" || fail "theme template mix_rgb helper works"
|
|
pass "theme template color mix helpers work"
|
|
|
|
grep -qx 'color=#ff0000' "$NEXT_THEME/alias-test.txt" || fail "theme template semantic aliases expose legacy colorN"
|
|
grep -qx 'strip=ff0000' "$NEXT_THEME/alias-test.txt" || fail "theme template legacy colorN_strip works"
|
|
grep -qx 'rgb=255,0,0' "$NEXT_THEME/alias-test.txt" || fail "theme template legacy colorN_rgb works"
|
|
grep -qx 'magenta=#ff00ff' "$NEXT_THEME/alias-test.txt" || fail "theme template magenta helper works"
|
|
grep -qx 'legacy-purple=#ff00ff' "$NEXT_THEME/alias-test.txt" || fail "theme template purple alias works"
|
|
grep -qx 'bright-magenta=#ff11ff' "$NEXT_THEME/alias-test.txt" || fail "theme template bright magenta helper works"
|
|
grep -qx 'legacy-bright-purple=#ff11ff' "$NEXT_THEME/alias-test.txt" || fail "theme template bright purple alias works"
|
|
grep -qx 'background=#000000' "$NEXT_THEME/alias-test.txt" || fail "theme template resolves background"
|
|
grep -qx 'foreground=#ffffff' "$NEXT_THEME/alias-test.txt" || fail "theme template resolves foreground"
|
|
grep -qx 'legacy-background=#000000' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy bg alias"
|
|
grep -qx 'legacy-dark-background=#010101' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy dark_bg alias"
|
|
grep -qx 'legacy-darker-background=#020202' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy darker_bg alias"
|
|
grep -qx 'legacy-lighter-background=#030303' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy lighter_bg alias"
|
|
grep -qx 'legacy-foreground=#ffffff' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy fg alias"
|
|
grep -qx 'legacy-dark-foreground=#cccccc' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy dark_fg alias"
|
|
grep -qx 'legacy-light-foreground=#dddddd' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy light_fg alias"
|
|
grep -qx 'legacy-bright-foreground=#eeeeee' "$NEXT_THEME/alias-test.txt" || fail "theme template exposes legacy bright_fg alias"
|
|
grep -qx 'legacy-mix=#808080' "$NEXT_THEME/alias-test.txt" || fail "theme template mix helper accepts legacy palette aliases"
|
|
grep -qx 'selection-background=#808080' "$NEXT_THEME/alias-test.txt" || fail "theme template derives selection background from selection"
|
|
grep -qx 'selection-foreground=#eeeeee' "$NEXT_THEME/alias-test.txt" || fail "theme template derives selection foreground from bright_foreground"
|
|
grep -qx 'cursor-alias=#eeeeee' "$NEXT_THEME/alias-test.txt" || fail "theme template derives cursor alias from bright_foreground"
|
|
pass "theme template semantic aliases expose legacy palette helpers"
|
|
|
|
LEGACY_COLORS_FILE="$PI_TMPDIR/legacy-colors.toml"
|
|
cat >"$LEGACY_COLORS_FILE" <<'EOF'
|
|
mode = "dark"
|
|
accent = "#336699"
|
|
selection = "#292929"
|
|
muted = "#404040"
|
|
bg = "#101010"
|
|
dark_bg = "#111111"
|
|
darker_bg = "#121212"
|
|
lighter_bg = "#131313"
|
|
fg = "#f0f0f0"
|
|
dark_fg = "#d0d0d0"
|
|
light_fg = "#e0e0e0"
|
|
bright_fg = "#ffffff"
|
|
red = "#ff0000"
|
|
green = "#00ff00"
|
|
yellow = "#ffff00"
|
|
blue = "#0000ff"
|
|
magenta = "#ff00ff"
|
|
cyan = "#00ffff"
|
|
bright_red = "#ff1111"
|
|
bright_green = "#11ff11"
|
|
bright_yellow = "#ffff11"
|
|
bright_blue = "#1111ff"
|
|
bright_magenta = "#ff11ff"
|
|
bright_cyan = "#11ffff"
|
|
EOF
|
|
|
|
while read -r canonical expected; do
|
|
actual=$("$ROOT/bin/omarchy-theme-color" --file "$LEGACY_COLORS_FILE" "$canonical")
|
|
[[ $actual == "$expected" ]] || fail "legacy palette resolves $canonical"
|
|
done <<'EOF'
|
|
background #101010
|
|
dark_background #111111
|
|
darker_background #121212
|
|
lighter_background #131313
|
|
foreground #f0f0f0
|
|
dark_foreground #d0d0d0
|
|
light_foreground #e0e0e0
|
|
bright_foreground #ffffff
|
|
EOF
|
|
pass "legacy short palette resolves every canonical neutral color"
|
|
|
|
LEGACY_THEME_HOME="$PI_TMPDIR/legacy-theme-home"
|
|
LEGACY_NEXT_THEME="$LEGACY_THEME_HOME/.local/state/omarchy/current/next-theme"
|
|
mkdir -p "$LEGACY_NEXT_THEME"
|
|
cp "$LEGACY_COLORS_FILE" "$LEGACY_NEXT_THEME/colors.toml"
|
|
OMARCHY_PATH="$ROOT" HOME="$LEGACY_THEME_HOME" "$ROOT/bin/omarchy-theme-set-templates"
|
|
grep -qx 'background = #101010' "$LEGACY_NEXT_THEME/ghostty.conf" || fail "legacy theme generates terminal background"
|
|
grep -qx 'foreground = #f0f0f0' "$LEGACY_NEXT_THEME/ghostty.conf" || fail "legacy theme generates terminal foreground"
|
|
grep -Fq 'dark_bg = "#111111"' "$LEGACY_NEXT_THEME/neovim.lua" || fail "legacy theme preserves dark_bg in generated editor theme"
|
|
grep -Fq 'lighter_bg = "#131313"' "$LEGACY_NEXT_THEME/neovim.lua" || fail "legacy theme preserves lighter_bg in generated editor theme"
|
|
grep -Fq 'dark_fg = "#d0d0d0"' "$LEGACY_NEXT_THEME/neovim.lua" || fail "legacy theme preserves dark_fg in generated editor theme"
|
|
grep -Fq 'bright_fg = "#ffffff"' "$LEGACY_NEXT_THEME/neovim.lua" || fail "legacy theme preserves bright_fg in generated editor theme"
|
|
if rg -q '\{\{[^}]+\}\}' "$LEGACY_NEXT_THEME"; then
|
|
fail "legacy theme renders every template placeholder"
|
|
fi
|
|
pass "legacy short palette renders the complete generated theme"
|
|
|
|
osc_summary=$("$ROOT/bin/omarchy-theme-osc" "$NEXT_THEME/colors.toml" | python -c 'import sys; data = sys.stdin.buffer.read(); print(data.count(b"]4;"), b"]4;1;#ff0000" in data, b"]4;7;#ffffff" in data, b"]4;15;#eeeeee" in data, b"]12;#eeeeee" in data, b"]17;#808080" in data, b"]19;#eeeeee" in data)')
|
|
[[ $osc_summary == "16 True True True True True True" ]] || fail "theme OSC aliases semantic colors to ANSI palette"
|
|
pass "theme OSC aliases semantic colors to ANSI palette"
|
|
|
|
preview_output=$(OMARCHY_PATH="$ROOT" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-dev-theme-preview" "$NEXT_THEME/colors.toml" --no-color)
|
|
assert_output_contains "theme preview shows background to bright_foreground gradient" "$preview_output" "background -> bright_foreground gradient"
|
|
assert_output_contains "theme preview orders light mode ramp light to dark" "$preview_output" "Neutral ramp (lightest -> darkest)"
|
|
assert_output_contains "theme preview includes dark background slots" "$preview_output" "darker_background"
|
|
assert_output_contains "theme preview shows selected text sample" "$preview_output" "This is some [selected text] in a sentence"
|
|
assert_output_contains "theme preview shows practical terminal samples" "$preview_output" "Terminal/UI samples"
|
|
assert_output_contains "theme preview shows ANSI palette strips" "$preview_output" "ANSI palette strips"
|
|
|
|
tokyo_fg=$(awk -F'"' '/^foreground =/ { print $2; exit }' "$ROOT/themes/tokyo-night/colors.toml")
|
|
tokyo_light_fg=$(awk -F'"' '/^light_foreground =/ { print $2; exit }' "$ROOT/themes/tokyo-night/colors.toml")
|
|
tokyo_bright_fg=$(awk -F'"' '/^bright_foreground =/ { print $2; exit }' "$ROOT/themes/tokyo-night/colors.toml")
|
|
[[ $tokyo_fg == "#a9b1d6" && $tokyo_light_fg == "#b4bee6" && $tokyo_bright_fg == "#c0caf5" ]] || fail "tokyo night foreground ramp stays ordered"
|
|
pass "tokyo night foreground ramp stays ordered"
|
|
|
|
if rg -q '^cursor\s*=' "$ROOT/themes" -g'colors.toml'; then
|
|
fail "built-in colors.toml files omit cursor token"
|
|
fi
|
|
pass "built-in colors.toml files omit cursor token"
|
|
|
|
grep -qx 'hypr={ colors = { "rgba(010203ee)", "rgba(040506ee)" }, angle = 45 }' "$NEXT_THEME/gradient-test.txt" || fail "theme template hypr_gradient helper works"
|
|
grep -qx 'shell=#010203' "$NEXT_THEME/gradient-test.txt" || fail "theme template gradient_start helper works"
|
|
grep -qx 'shell-gradient=rgba(010203ee) rgba(040506ee) 45deg' "$NEXT_THEME/gradient-test.txt" || fail "theme template shell_gradient helper works"
|
|
grep -qx 'fallback-hypr="#336699"' "$NEXT_THEME/gradient-test.txt" || fail "theme template hypr_gradient fallback works"
|
|
grep -qx 'fallback-shell=#336699' "$NEXT_THEME/gradient-test.txt" || fail "theme template gradient_start fallback works"
|
|
grep -qx 'fallback-shell-gradient=#336699' "$NEXT_THEME/gradient-test.txt" || fail "theme template shell_gradient fallback works"
|
|
pass "theme template gradient helpers work"
|
|
|
|
awk '
|
|
/^\[lock\]$/ { in_lock = 1; next }
|
|
/^\[/ { in_lock = 0 }
|
|
in_lock && /^text = "#ffffff"$/ { text = 1 }
|
|
in_lock && /^placeholder = "#ffffff"$/ { placeholder = 1 }
|
|
in_lock && /^border = "#ffffff"$/ { border = 1 }
|
|
END { exit(text && placeholder && border ? 0 : 1) }
|
|
' "$NEXT_THEME/shell.toml" || fail "theme shell section override is merged"
|
|
pass "theme shell section override is merged"
|
|
|
|
jq -e '.name == "omarchy-system" and .vars.panel == "#0f0f0f" and .vars.border == "#4d4d4d" and .colors.accent == "accent"' "$NEXT_THEME/pi.json" >/dev/null
|
|
pass "pi theme template is generated from standard themed templates"
|
|
cp "$NEXT_THEME/pi.json" "$CURRENT_THEME/pi.json"
|
|
|
|
echo '{"name":"omarchy-system","vars":{"custom":"yes"}}' >"$NEXT_THEME/pi.json"
|
|
OMARCHY_PATH="$ROOT" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-templates"
|
|
jq -e '.name == "omarchy-system" and .vars.custom == "yes"' "$NEXT_THEME/pi.json" >/dev/null
|
|
pass "theme-specific pi.json overrides the default template"
|
|
|
|
HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-pi"
|
|
[[ ! -d $PI_TMPDIR/.pi ]] || fail "pi theme sync skips missing Pi agent when not activating"
|
|
pass "pi theme sync skips missing Pi agent when not activating"
|
|
|
|
HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-pi" --activate
|
|
[[ -f $PI_TMPDIR/.pi/agent/themes/omarchy-system.json ]] || fail "pi theme file is synced"
|
|
pass "pi theme file is synced"
|
|
[[ -f $PI_TMPDIR/.pi/agent/settings.json ]] || fail "pi settings file is generated"
|
|
pass "pi settings file is generated"
|
|
jq -e '.name == "omarchy-system" and .vars.panel == "#0f0f0f"' "$PI_TMPDIR/.pi/agent/themes/omarchy-system.json" >/dev/null
|
|
pass "pi synced theme JSON is valid"
|
|
jq -e '.theme == "omarchy-system"' "$PI_TMPDIR/.pi/agent/settings.json" >/dev/null
|
|
pass "pi generated theme is activated"
|
|
|
|
jq '.model = "keep-me"' "$PI_TMPDIR/.pi/agent/settings.json" >"$PI_TMPDIR/settings.json.tmp"
|
|
mv "$PI_TMPDIR/settings.json.tmp" "$PI_TMPDIR/.pi/agent/settings.json"
|
|
HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-pi" --activate
|
|
jq -e '.theme == "omarchy-system" and .model == "keep-me"' "$PI_TMPDIR/.pi/agent/settings.json" >/dev/null
|
|
pass "pi theme activation preserves existing settings"
|
|
|
|
jq -e '.name == "Omarchy" and .base == "light" and .overrides.text == "#ffffff"' "$NEXT_THEME/claude.json" >/dev/null
|
|
pass "claude theme template is generated from standard themed templates"
|
|
cp "$NEXT_THEME/claude.json" "$CURRENT_THEME/claude.json"
|
|
|
|
CLAUDE_TEST_CONFIG="$PI_TMPDIR/.claude-work"
|
|
mkdir -p "$CLAUDE_TEST_CONFIG"
|
|
HOME="$PI_TMPDIR" CLAUDE_CONFIG_DIR="$CLAUDE_TEST_CONFIG" "$ROOT/bin/omarchy-theme-set-claude"
|
|
[[ -f $CLAUDE_TEST_CONFIG/themes/omarchy.json ]] || fail "claude theme is synced to the configured directory"
|
|
[[ ! -d $PI_TMPDIR/.claude ]] || fail "claude theme sync avoids the default directory when configured"
|
|
pass "claude theme sync respects CLAUDE_CONFIG_DIR"
|
|
|
|
echo '{"model":"keep-me"}' >"$CLAUDE_TEST_CONFIG/settings.json"
|
|
HOME="$PI_TMPDIR" CLAUDE_CONFIG_DIR="$CLAUDE_TEST_CONFIG" "$ROOT/bin/omarchy-theme-set-claude" --activate
|
|
jq -e '.theme == "custom:omarchy" and .model == "keep-me"' "$CLAUDE_TEST_CONFIG/settings.json" >/dev/null
|
|
pass "claude theme activation preserves configured settings"
|
|
|
|
make_tmpdir THEME_TMPDIR
|
|
OMARCHY_PATH="$ROOT" HOME="$THEME_TMPDIR" OMARCHY_THEME_HEADLESS=1 "$ROOT/bin/omarchy-theme-set" "Tokyo Night"
|
|
background_path=$(readlink -f "$THEME_TMPDIR/.local/state/omarchy/current/background" 2>/dev/null || true)
|
|
expected_background="$THEME_TMPDIR/.local/state/omarchy/current/theme/backgrounds/0-winding-road.webp"
|
|
[[ $background_path == "$expected_background" ]] || fail "headless theme set creates current background symlink"
|
|
[[ -f $background_path ]] || fail "headless theme background target exists"
|
|
[[ ! -e $THEME_TMPDIR/.config/omarchy/current ]] || fail "headless theme set avoids config current state"
|
|
pass "headless theme set creates current background symlink"
|
|
|
|
make_tmpdir MIGRATION_TMPDIR
|
|
mkdir -p \
|
|
"$MIGRATION_TMPDIR/.config/omarchy/current/theme" \
|
|
"$MIGRATION_TMPDIR/.config/alacritty" \
|
|
"$MIGRATION_TMPDIR/.config/hypr" \
|
|
"$MIGRATION_TMPDIR/.config/hyprland-preview-share-picker" \
|
|
"$MIGRATION_TMPDIR/.config/btop/themes"
|
|
printf 'tokyo-night\n' >"$MIGRATION_TMPDIR/.config/omarchy/current/theme.name"
|
|
printf 'x\n' >"$MIGRATION_TMPDIR/.config/omarchy/current/theme/colors.toml"
|
|
printf 'general.import = [ "~/.config/omarchy/current/theme/alacritty.toml" ]\n' >"$MIGRATION_TMPDIR/.config/alacritty/alacritty.toml"
|
|
printf 'stylesheets: ["../omarchy/current/theme/hyprland-preview-share-picker.css"]\n' >"$MIGRATION_TMPDIR/.config/hyprland-preview-share-picker/config.yaml"
|
|
cat >"$MIGRATION_TMPDIR/.config/hypr/hyprland.lua" <<'LUA'
|
|
package.path = os.getenv("HOME")
|
|
.. "/.config/?.lua;"
|
|
.. (os.getenv("OMARCHY_PATH") or "/usr/share/omarchy")
|
|
.. "/?.lua;"
|
|
.. package.path
|
|
LUA
|
|
ln -s "$MIGRATION_TMPDIR/.config/omarchy/current/theme/btop.theme" "$MIGRATION_TMPDIR/.config/btop/themes/current.theme"
|
|
HOME="$MIGRATION_TMPDIR" bash -euo pipefail "$ROOT/migrations/1781043107.sh" >/dev/null
|
|
[[ -f $MIGRATION_TMPDIR/.local/state/omarchy/current/theme.name ]] || fail "current theme migration moves theme name"
|
|
[[ ! -e $MIGRATION_TMPDIR/.config/omarchy/current ]] || fail "current theme migration removes legacy config state"
|
|
grep -Fq '~/.local/state/omarchy/current/theme/alacritty.toml' "$MIGRATION_TMPDIR/.config/alacritty/alacritty.toml" || fail "current theme migration updates alacritty import"
|
|
grep -Fq '../../.local/state/omarchy/current/theme/hyprland-preview-share-picker.css' "$MIGRATION_TMPDIR/.config/hyprland-preview-share-picker/config.yaml" || fail "current theme migration updates relative stylesheet"
|
|
grep -Fq '/.local/state/?.lua;' "$MIGRATION_TMPDIR/.config/hypr/hyprland.lua" || fail "current theme migration keeps Hyprland theme modules discoverable"
|
|
[[ $(readlink "$MIGRATION_TMPDIR/.config/btop/themes/current.theme") == "$MIGRATION_TMPDIR/.local/state/omarchy/current/theme/btop.theme" ]] || fail "current theme migration updates btop symlink"
|
|
pass "current theme migration moves state and rewrites shipped references"
|
|
|
|
make_tmpdir NVIM_MIGRATION_TMPDIR
|
|
nvim_theme_link="$NVIM_MIGRATION_TMPDIR/.config/nvim/lua/plugins/theme.lua"
|
|
nvim_expected_target="../../../../.local/state/omarchy/current/theme/neovim.lua"
|
|
nvim_expected_resolved_target="$NVIM_MIGRATION_TMPDIR/.local/state/omarchy/current/theme/neovim.lua"
|
|
mkdir -p \
|
|
"$(dirname "$nvim_theme_link")" \
|
|
"$NVIM_MIGRATION_TMPDIR/.config/omarchy/current/theme" \
|
|
"$NVIM_MIGRATION_TMPDIR/.local/state/omarchy/current/theme"
|
|
touch "$NVIM_MIGRATION_TMPDIR/.local/state/omarchy/current/theme/neovim.lua"
|
|
for nvim_legacy_target in \
|
|
"../../../omarchy/current/theme/neovim.lua" \
|
|
"$NVIM_MIGRATION_TMPDIR/.config/omarchy/current/theme/neovim.lua"; do
|
|
ln -sfn "$nvim_legacy_target" "$nvim_theme_link"
|
|
HOME="$NVIM_MIGRATION_TMPDIR" bash -euo pipefail "$ROOT/migrations/1781158082.sh" >/dev/null
|
|
nvim_actual_target=$(readlink "$nvim_theme_link")
|
|
nvim_resolved_target=$(readlink -f "$nvim_theme_link")
|
|
[[ $nvim_actual_target == $nvim_expected_target ]] || fail "nvim theme migration updates theme symlink"
|
|
[[ $nvim_resolved_target == $nvim_expected_resolved_target ]] || fail "nvim theme migration points to current theme"
|
|
done
|
|
pass "nvim theme migration relinks current theme"
|
|
|
|
for nvim_legacy_target in \
|
|
"../../../omarchy/current/theme/neovim.lua" \
|
|
"../../../../.config/omarchy/current/theme/neovim.lua" \
|
|
"~/.config/omarchy/current/theme/neovim.lua" \
|
|
"$NVIM_MIGRATION_TMPDIR/.config/omarchy/current/theme/neovim.lua"; do
|
|
ln -sfn "$nvim_legacy_target" "$nvim_theme_link"
|
|
HOME="$NVIM_MIGRATION_TMPDIR" bash -euo pipefail "$ROOT/migrations/1785002349.sh" >/dev/null
|
|
nvim_actual_target=$(readlink "$nvim_theme_link")
|
|
nvim_resolved_target=$(readlink -f "$nvim_theme_link")
|
|
[[ $nvim_actual_target == $nvim_expected_target ]] || fail "nvim theme repair migration updates $nvim_legacy_target"
|
|
[[ $nvim_resolved_target == $nvim_expected_resolved_target ]] || fail "nvim theme repair migration points to current theme"
|
|
done
|
|
|
|
HOME="$NVIM_MIGRATION_TMPDIR" bash -euo pipefail "$ROOT/migrations/1785002349.sh" >/dev/null
|
|
[[ $(readlink "$nvim_theme_link") == $nvim_expected_target ]] || fail "nvim theme repair migration is idempotent"
|
|
|
|
touch "$NVIM_MIGRATION_TMPDIR/custom-theme.lua"
|
|
ln -sfn "../../../../custom-theme.lua" "$nvim_theme_link"
|
|
HOME="$NVIM_MIGRATION_TMPDIR" bash -euo pipefail "$ROOT/migrations/1785002349.sh" >/dev/null
|
|
[[ $(readlink "$nvim_theme_link") == "../../../../custom-theme.lua" ]] || fail "nvim theme repair migration leaves custom symlinks alone"
|
|
pass "nvim theme repair migration relinks every legacy spelling"
|
|
|
|
make_tmpdir HYPR_MIGRATION_TMPDIR
|
|
mkdir -p "$HYPR_MIGRATION_TMPDIR/.config/hypr"
|
|
cat >"$HYPR_MIGRATION_TMPDIR/.config/hypr/hyprland.lua" <<'LUA'
|
|
-- Learn how to configure Hyprland: https://wiki.hypr.land/Configuring/Start/
|
|
|
|
-- Load user modules from ~/.config and Omarchy defaults from $OMARCHY_PATH.
|
|
package.path = os.getenv("HOME")
|
|
.. "/.config/?.lua;"
|
|
.. (os.getenv("OMARCHY_PATH") or (os.getenv("HOME") .. "/.local/share/omarchy"))
|
|
.. "/?.lua;"
|
|
.. package.path
|
|
|
|
-- All Omarchy default setups
|
|
require("default.hypr.omarchy")
|
|
|
|
-- Add any other personal Hyprland configuration below.
|
|
o.window("Example", { workspace = "1" })
|
|
LUA
|
|
HOME="$HYPR_MIGRATION_TMPDIR" bash -euo pipefail "$ROOT/migrations/1781063758.sh" >/dev/null
|
|
grep -Fq 'dofile((os.getenv("OMARCHY_PATH") or "/usr/share/omarchy") .. "/default/hypr/bootstrap.lua")' "$HYPR_MIGRATION_TMPDIR/.config/hypr/hyprland.lua" || fail "hyprland bootstrap migration adds bootstrap"
|
|
! grep -Fq 'package.path = os.getenv("HOME")' "$HYPR_MIGRATION_TMPDIR/.config/hypr/hyprland.lua" || fail "hyprland bootstrap migration removes legacy path block"
|
|
grep -Fq 'o.window("Example", { workspace = "1" })' "$HYPR_MIGRATION_TMPDIR/.config/hypr/hyprland.lua" || fail "hyprland bootstrap migration preserves custom config"
|
|
pass "hyprland bootstrap migration updates stale user entrypoint"
|
|
|
|
cp "$NEXT_THEME/colors.toml" "$CURRENT_THEME/colors.toml"
|
|
cp "$NEXT_THEME/vscode-theme.json" "$CURRENT_THEME/vscode-theme.json"
|
|
|
|
FAKE_BIN="$PI_TMPDIR/fake-bin"
|
|
mkdir -p "$FAKE_BIN"
|
|
|
|
cat >"$FAKE_BIN/tmux" <<'EOF'
|
|
#!/bin/bash
|
|
case "$1" in
|
|
list-sessions)
|
|
[[ $2 == "-F" ]] && echo "session-1"
|
|
exit 0
|
|
;;
|
|
set-environment|set-option|refresh-client)
|
|
echo "$*" >>"${TMUX_LOG:-/dev/null}"
|
|
exit 0
|
|
;;
|
|
list-panes|list-clients)
|
|
exit 0
|
|
;;
|
|
*)
|
|
exit 0
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$FAKE_BIN/tmux"
|
|
|
|
TMUX_LOG="$PI_TMPDIR/tmux.log" PATH="$FAKE_BIN:$ROOT/bin:$PATH" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-tmux"
|
|
grep -q 'set-environment -g COLORFGBG 0;15' "$PI_TMPDIR/tmux.log" || fail "tmux sync reads mode from colors.toml"
|
|
pass "tmux sync reads mode from colors.toml"
|
|
|
|
cat >"$FAKE_BIN/gsettings" <<'EOF'
|
|
#!/bin/bash
|
|
echo "$*" >>"${GSETTINGS_LOG:-/dev/null}"
|
|
EOF
|
|
chmod +x "$FAKE_BIN/gsettings"
|
|
|
|
GSETTINGS_LOG="$PI_TMPDIR/gsettings.log" DBUS_SESSION_BUS_ADDRESS="unix:path=$PI_TMPDIR/bus" PATH="$FAKE_BIN:$ROOT/bin:$PATH" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-gnome"
|
|
grep -q 'org.gnome.desktop.interface color-scheme prefer-light' "$PI_TMPDIR/gsettings.log" || fail "gnome sync reads mode from colors.toml"
|
|
pass "gnome sync reads mode from colors.toml"
|
|
|
|
cat >"$FAKE_BIN/omarchy-cmd-present" <<'EOF'
|
|
#!/bin/bash
|
|
[[ $1 == "code" ]]
|
|
EOF
|
|
chmod +x "$FAKE_BIN/omarchy-cmd-present"
|
|
|
|
cat >"$FAKE_BIN/omarchy-toggle-enabled" <<'EOF'
|
|
#!/bin/bash
|
|
exit 1
|
|
EOF
|
|
chmod +x "$FAKE_BIN/omarchy-toggle-enabled"
|
|
|
|
mkdir -p "$PI_TMPDIR/.vscode/extensions"
|
|
echo '{"local.omarchy-theme-1.0.0":true}' >"$PI_TMPDIR/.vscode/extensions/.obsolete"
|
|
PATH="$FAKE_BIN:$ROOT/bin:$PATH" HOME="$PI_TMPDIR" "$ROOT/bin/omarchy-theme-set-vscode"
|
|
jq -e '.contributes.themes[0].uiTheme == "vs"' "$PI_TMPDIR/.vscode/extensions/omarchy-theme/package.json" >/dev/null || fail "vscode generated light theme uses VS Code light uiTheme"
|
|
pass "vscode generated light theme uses VS Code light uiTheme"
|
|
[[ -L $PI_TMPDIR/.vscode/extensions/omarchy-theme/themes/omarchy-color-theme.json ]] || fail "vscode generated theme references current theme file"
|
|
[[ $(readlink "$PI_TMPDIR/.vscode/extensions/omarchy-theme/themes/omarchy-color-theme.json") == "$PI_TMPDIR/.local/state/omarchy/current/theme/vscode-theme.json" ]] || fail "vscode generated theme references current theme file"
|
|
pass "vscode generated theme references current theme file"
|
|
[[ ! -f $PI_TMPDIR/.vscode/extensions/.obsolete ]] || fail "vscode generated theme clears obsolete extension marker"
|
|
pass "vscode generated theme clears obsolete extension marker"
|
|
jq -e '.[] | select(.identifier.id == "local.omarchy-theme" and .relativeLocation == "omarchy-theme")' "$PI_TMPDIR/.vscode/extensions/extensions.json" >/dev/null || fail "vscode generated theme registers local extension"
|
|
pass "vscode generated theme registers local extension"
|
|
|
|
for binary in \
|
|
omarchy-update \
|
|
omarchy-theme-set \
|
|
omarchy-capture-screenshot \
|
|
omarchy-system-reboot \
|
|
omarchy-pkg-add; do
|
|
[[ -x $ROOT/bin/$binary ]] || fail "binary is executable: $binary"
|
|
pass "binary is executable: $binary"
|
|
done
|
|
|
|
while IFS= read -r binary_path; do
|
|
header=$(awk '
|
|
NR == 1 && /^#!/ { next }
|
|
/^[[:space:]]*$/ { if (seen) print; next }
|
|
/^[[:space:]]*#/ { seen=1; print; next }
|
|
{ exit }
|
|
' "$binary_path")
|
|
|
|
grep -q '^# omarchy:summary=' <<<"$header" || fail "metadata summary is present: $binary_path"
|
|
! grep -q '^# omarchy:binary=' <<<"$header" || fail "metadata does not repeat inferred binary: $binary_path"
|
|
! grep -q '^# omarchy:args=$' <<<"$header" || fail "metadata does not include empty args: $binary_path"
|
|
! grep -Eq '^# omarchy:(legacy|usage|visibility|mutates|interactive)=' <<<"$header" || fail "metadata avoids removed fields: $binary_path"
|
|
! grep -Eq '^# omarchy:requires-sudo=false$' <<<"$header" || fail "metadata omits false booleans: $binary_path"
|
|
done < <(find "$ROOT/bin" -maxdepth 1 -type f -executable -name 'omarchy-*' | sort)
|
|
pass "all executable bins have slim self-documenting metadata"
|
|
|
|
make_tmpdir TMPDIR
|
|
ln -s "$CLI" "$TMPDIR/omarchy"
|
|
|
|
{
|
|
printf '#!/bin/bash\n\n'
|
|
printf '# ordinary comments are fine\n'
|
|
printf '# omarchy:this malformed line should be ignored\n'
|
|
printf '# omarchy:group=weird\n'
|
|
printf '# omarchy:name=test\n'
|
|
printf '# omarchy:summary=Survives malformed metadata comments\n'
|
|
printf '# omarchy:made-up=value\n'
|
|
printf 'echo weird-ok\n'
|
|
} >"$TMPDIR/omarchy-weird-test"
|
|
chmod +x "$TMPDIR/omarchy-weird-test"
|
|
|
|
{
|
|
printf '#!/bin/bash\n\n'
|
|
printf '# a partial metadata header should not destroy fallback routing\n'
|
|
printf '# omarchy:summary=Partial metadata keeps inferred route\n'
|
|
printf '# omarchy:made-up=value\n'
|
|
printf 'echo partial-ok\n'
|
|
} >"$TMPDIR/omarchy-partial-meta-test"
|
|
chmod +x "$TMPDIR/omarchy-partial-meta-test"
|
|
|
|
{
|
|
printf '#!/bin/bash\n\n'
|
|
printf 'echo body-metadata-ok\n'
|
|
printf '# omarchy:group=wrong\n'
|
|
printf '# omarchy:name=wrong\n'
|
|
} >"$TMPDIR/omarchy-body-metadata-test"
|
|
chmod +x "$TMPDIR/omarchy-body-metadata-test"
|
|
|
|
"$TMPDIR/omarchy" commands --all --json | jq -e '.commands[] | select(.route == "omarchy weird test" and .summary == "Survives malformed metadata comments")' >/dev/null
|
|
pass "unknown metadata values are non-fatal"
|
|
|
|
"$TMPDIR/omarchy" commands --all --json | jq -e '.commands[] | select(.route == "omarchy partial meta test" and .summary == "Partial metadata keeps inferred route")' >/dev/null
|
|
pass "partial metadata keeps inferred fallback route"
|
|
|
|
"$TMPDIR/omarchy" commands --all --json | jq -e '.commands[] | select(.route == "omarchy body metadata test" and .summary == "Run the body metadata test command")' >/dev/null
|
|
pass "metadata-looking comments after script body are ignored"
|
|
|
|
output=$("$TMPDIR/omarchy" weird test)
|
|
assert_output_contains "temporary metadata command dispatches" "$output" "weird-ok"
|
|
|
|
output=$("$TMPDIR/omarchy" partial meta test)
|
|
assert_output_contains "partial metadata command dispatches" "$output" "partial-ok"
|
|
|
|
output=$("$TMPDIR/omarchy" body metadata test)
|
|
assert_output_contains "body metadata command dispatches by filename" "$output" "body-metadata-ok"
|
|
|
|
# A trailing --help must render help even when the route only partially
|
|
# resolves, leaving unresolved words ahead of the flag (e.g. `update aur --help`
|
|
# used to start a real update because only the first leftover token was checked).
|
|
{
|
|
printf '#!/bin/bash\n\n'
|
|
printf '# omarchy:summary=Partial resolution help test parent\n'
|
|
printf '# omarchy:alias=omarchy parenthelp-alias\n'
|
|
printf 'echo "parenthelp-parent-ran args=[$*]"\n'
|
|
} >"$TMPDIR/omarchy-parenthelp"
|
|
chmod +x "$TMPDIR/omarchy-parenthelp"
|
|
|
|
{
|
|
printf '#!/bin/bash\n\n'
|
|
printf '# omarchy:summary=Partial resolution help test child\n'
|
|
printf 'echo parenthelp-child-ran\n'
|
|
} >"$TMPDIR/omarchy-parenthelp-child"
|
|
chmod +x "$TMPDIR/omarchy-parenthelp-child"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp bogus --help)
|
|
assert_output_contains "trailing --help after an unresolved word renders help" "$output" "omarchy-parenthelp"
|
|
assert_output_contains "partial resolution help lists related commands" "$output" "omarchy parenthelp child"
|
|
if [[ $output == *"parenthelp-parent-ran"* ]]; then
|
|
fail "trailing --help after an unresolved word does not execute the command"
|
|
fi
|
|
pass "trailing --help after an unresolved word does not execute the command"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp bogus -h)
|
|
assert_output_contains "trailing -h after an unresolved word renders help" "$output" "omarchy-parenthelp"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp-alias bogus --help)
|
|
assert_output_contains "trailing --help after an unresolved word renders help via alias route" "$output" "omarchy-parenthelp"
|
|
if [[ $output == *"parenthelp-parent-ran"* ]]; then
|
|
fail "trailing --help on an alias route does not execute the command"
|
|
fi
|
|
pass "trailing --help on an alias route does not execute the command"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp bogus --json --help)
|
|
grep -q '"ok": true' <<<"$output" || fail "--json with --help renders JSON help"
|
|
pass "--json with --help renders JSON help"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp "explain --json output" --help)
|
|
assert_output_contains "a --json embedded inside one argument does not switch help to JSON" "$output" "Partial resolution help test parent"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp bogus trailing)
|
|
assert_output_contains "leftover args without a help flag still forward" "$output" "parenthelp-parent-ran args=[bogus trailing]"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp run -- --help)
|
|
assert_output_contains "a --help behind -- belongs to the command and still forwards" "$output" "parenthelp-parent-ran args=[run -- --help]"
|
|
|
|
output=$("$TMPDIR/omarchy" parenthelp --helpme x--help)
|
|
assert_output_contains "help lookalike tokens do not trigger help" "$output" "parenthelp-parent-ran args=[--helpme x--help]"
|