#!/bin/bash set -euo pipefail # A theme installed with `omarchy theme install` is a stranger's git repo, so # omarchy-theme-set drops the files that would run its code -- Lua, terminal # configs, vscode.json -- and keeps the colour. A theme the user wrote themselves # is not filtered at all. source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" test_tmp=$(mktemp -d) trap 'rm -rf "$test_tmp"' EXIT home="$test_tmp/home" state="$home/.local/state/omarchy/current" themes="$home/.config/omarchy/themes" mkdir -p "$state" "$themes" marker="omarchy-theme-staging-marker" set_theme() { HOME="$home" OMARCHY_PATH="$ROOT" PATH="$ROOT/bin:$PATH" \ OMARCHY_THEME_HEADLESS=1 OMARCHY_THEME_SKIP_BACKGROUND=1 \ XDG_RUNTIME_DIR="$test_tmp" \ bash "$ROOT/bin/omarchy-theme-set" "$1" 2>"$test_tmp/stderr" || return $? } staged() { printf '%s' "$state/theme/$1" } assert_staged() { [[ -f $(staged "$1") ]] || fail "$2" } assert_not_staged() { [[ ! -e $(staged "$1") ]] || fail "$2" } assert_no_marker() { ! grep -q "$marker" "$(staged "$1")" || fail "$2" } write_colors() { cat >"$1" <"$hostile/hyprland.lua" printf 'vim.cmd("%s")\n' "$marker" >"$hostile/neovim.lua" printf 'shell %s\n' "$marker" >"$hostile/kitty.conf" printf '[terminal.shell]\nprogram = "%s"\n' "$marker" >"$hostile/alacritty.toml" printf 'shell = "%s"\n' "$marker" >"$hostile/foot.ini" printf 'command = "%s"\n' "$marker" >"$hostile/ghostty.conf" printf 'hl.env("GUM_INPUT_PROMPT", "%s")\n' "$marker" >"$hostile/gum_env.lua" printf '[bar]\nbackground = "#%s"\n' "000000" >"$hostile/shell.toml" printf '{}\n' >"$hostile/vscode.json" printf 'Yaru-red\n' >"$hostile/icons.theme" printf 'theme[main_bg]="#000000"\n' >"$hostile/btop.theme" printf 'png\n' >"$hostile/preview.png" printf 'png\n' >"$hostile/backgrounds/1-real.png" printf '%s\n' "$marker" >"$hostile/backgrounds/payload.sh" printf '# notes\n' >"$hostile/README.md" ln -s /etc/hostname "$hostile/unlock.png" set_theme hostile || fail "omarchy-theme-set applies a theme that ships disallowed files" assert_staged colors.toml "the theme's colors.toml is staged" grep -q '#7aa2f7' "$(staged colors.toml)" || fail "the staged colors.toml is the theme's palette" assert_staged light.mode "the light mode marker is staged" assert_staged preview.png "the theme's preview image is staged" assert_staged backgrounds/1-real.png "an image in backgrounds/ is staged" assert_not_staged unlock.png "a symlink is not followed out of the theme" assert_not_staged vscode.json "vscode.json names an extension to install and is not staged" assert_staged icons.theme "the theme's icon set name is staged" grep -q 'Yaru-red' "$(staged icons.theme)" || fail "the staged icons.theme is the theme's" assert_staged btop.theme "the theme's btop colours are staged" grep -q 'main_bg' "$(staged btop.theme)" || fail "the staged btop.theme is the theme's" assert_not_staged .git "the clone's own git directory is never staged" # These run code, so the theme's versions must lose to Omarchy's generated ones # rather than merely be absent. for generated in hyprland.lua neovim.lua gum_env.lua kitty.conf alacritty.toml foot.ini ghostty.conf; do assert_staged "$generated" "$generated is generated from Omarchy's template" assert_no_marker "$generated" "an installed theme cannot supply $generated" done # Colour is kept, including a file Omarchy would otherwise have generated. assert_staged shell.toml "shell.toml is staged" grep -q '000000' "$(staged shell.toml)" || fail "an installed theme's shell.toml colours are kept" grep -q 'hyprland.lua' "$test_tmp/stderr" || fail "omarchy-theme-set names the files it ignored" ! grep -q 'README.md' "$test_tmp/stderr" || fail "omarchy-theme-set does not report a theme's documentation" pass "an installed theme keeps its colour and loses everything that runs code" # icons.theme is staged verbatim and handed to gsettings, so a symlinked one # would stage a copy of whatever it points at. linked="$themes/linked" mkdir -p "$linked/.git" write_colors "$linked/colors.toml" ln -s /etc/hostname "$linked/icons.theme" set_theme linked || fail "omarchy-theme-set applies a theme whose icons.theme is a symlink" assert_not_staged icons.theme "a symlinked icons.theme is not followed" pass "a symlinked icon set name is refused like any other symlink" # A theme predating colors.toml still gets a palette, without its alacritty.toml # reaching the staged theme. legacy="$themes/legacy" mkdir -p "$legacy/.git" cat >"$legacy/alacritty.toml" <"$themes/tokyo-night/hyprland.lua" set_theme "Tokyo Night" || fail "omarchy-theme-set applies a stock theme with a user overlay" grep -q '#abcdef' "$(staged colors.toml)" || fail "a user overlay still replaces the stock palette" assert_no_marker hyprland.lua "a user overlay cannot add Lua to a stock theme" pass "an overlay on a stock theme repaints it without adding code" # A theme the user wrote themselves has no git repo behind it and is theirs. mine="$themes/mine" mkdir -p "$mine" write_colors "$mine/colors.toml" printf 'os.execute("%s")\n' "$marker" >"$mine/hyprland.lua" printf '{"name":"Mine","extension":"pub.ext"}\n' >"$mine/vscode.json" set_theme mine || fail "omarchy-theme-set applies a theme the user wrote" grep -q "$marker" "$(staged hyprland.lua)" || fail "a theme the user wrote keeps its own hyprland.lua" assert_staged vscode.json "a theme the user wrote keeps every file it ships" [[ ! -s $test_tmp/stderr ]] || fail "a theme the user wrote reports nothing ignored" "$(cat "$test_tmp/stderr")" pass "a theme the user wrote is not held to the installed-theme list" # A working copy symlinked into the themes folder is the user's own too. ln -s "$mine" "$themes/mine-link" set_theme mine-link || fail "omarchy-theme-set applies a symlinked working copy" grep -q "$marker" "$(staged hyprland.lua)" || fail "a symlinked working copy is the user's own" pass "a symlinked working copy is the user's own" # The name is joined into paths that get removed and copied into. for name in .. . "../../evil"; do if set_theme "$name" >/dev/null; then fail "omarchy-theme-set rejects the theme name '$name'" fi done pass "a theme name cannot climb out of the theme directories" # A denylist is only correct while someone adding a template classifies what it # generates. Every generated theme file is either denied to an installed theme or # recorded here as carrying colour, so a new template fails until it is placed. denied=(alacritty.toml foot.ini ghostty.conf kitty.conf gum_env.lua hyprland.lua neovim.lua vscode.json) colour_only=(btop.theme chromium.theme claude.json helix.toml hyprland-preview-share-picker.css keyboard.rgb obsidian.css pi.json shell.toml vscode-theme.json) for tpl in "$ROOT"/default/themed/*.tpl; do generated=$(basename "$tpl" .tpl) classified="" for name in "${denied[@]}" "${colour_only[@]}"; do if [[ $generated == "$name" ]]; then classified=1 break fi done [[ -n $classified ]] || fail "every generated theme file is classified as code or colour" \ "$generated has a template but is in neither list in $(basename "$0"); decide whether an installed theme may ship it" done pass "every file Omarchy generates is classified as code or colour"