Files
a4219f8f4a Store theme backgrounds as webp (#7477)
* 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>
2026-08-19 14:21:30 +02:00

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]"