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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion bin/omarchy-theme-set
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,49 @@ theme_came_from_a_repo() {
[[ ! -L $source && -d $source/.git ]]
}

# User-authored themes may point at files in a dotfiles tree via relative
# symlinks. `cp -r` would copy the link text verbatim, so once the tree lands
# under next-theme/ (and later current/theme/) the same relative path resolves
# from the wrong depth and goes dangling — colors.toml unreadable, templates
# empty, silent full theming break. Dereference while staging so the content is
# what ends up in the live theme path. Installed (git-cloned) themes keep the
# refuse-symlinks path above; that is a stranger's tree.
stage_user_theme() {
local source="$1"

[[ -d $source ]] || return 0
stage_user_theme_dir "$source" "$NEXT_THEME_PATH"
}

stage_user_theme_dir() {
local source="$1"
local dest="$2"
local entry name

mkdir -p "$dest"

for entry in "$source"/*; do
[[ -e $entry || -L $entry ]] || continue
name=${entry##*/}

if [[ -L $entry ]]; then
if [[ -e $entry ]]; then
if [[ -d $entry ]]; then
cp -rL "$entry" "$dest/$name"
else
cp -L "$entry" "$dest/$name"
fi
else
echo "omarchy-theme-set: skipping dangling symlink $source/$name" >&2
fi
elif [[ -d $entry ]]; then
stage_user_theme_dir "$entry" "$dest/$name"
else
cp "$entry" "$dest/$name"
fi
done
}

stage_installed_theme() {
local source="$1"
local entry name
Expand Down Expand Up @@ -272,7 +315,7 @@ if theme_came_from_a_repo "$USER_THEMES_PATH/$THEME_NAME"; then
stage_installed_theme "$USER_THEMES_PATH/$THEME_NAME"
report_ignored_theme_files
else
cp -r "$USER_THEMES_PATH/$THEME_NAME/"* "$NEXT_THEME_PATH/" 2>/dev/null
stage_user_theme "$USER_THEMES_PATH/$THEME_NAME"
fi

# Generate colors.toml from alacritty.toml if theme is missing colors.toml
Expand Down
23 changes: 23 additions & 0 deletions test/shell.d/theme-staging-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,29 @@ grep -q "$marker" "$(staged hyprland.lua)" || fail "a symlinked working copy is

pass "a symlinked working copy is the user's own"

# A user theme may keep colors.toml as a relative symlink into a dotfiles tree.
# Staging must dereference it: copying the link text lands a dangling path under
# current/theme/ and every template silently fails to generate.
realsrc="$home/realtheme"
mkdir -p "$realsrc"
write_colors "$realsrc/colors.toml"
sed -i 's/#7aa2f7/#112233/' "$realsrc/colors.toml"

relinked="$themes/relinked"
mkdir -p "$relinked"
# themes/relinked is under home/.config/omarchy/themes; ../../../../realtheme is home/realtheme
ln -s ../../../../realtheme/colors.toml "$relinked/colors.toml"
[[ -e $relinked/colors.toml ]] || fail "the relative symlink resolves from the theme directory"

set_theme relinked || fail "omarchy-theme-set applies a user theme whose colors.toml is a relative symlink"

assert_staged colors.toml "a relative-symlink colors.toml is staged as a real file"
[[ ! -L $(staged colors.toml) ]] || fail "the staged colors.toml is content, not a copied symlink"
grep -q '#112233' "$(staged colors.toml)" || fail "the staged palette is the symlink target's content"
assert_staged ghostty.conf "templates still generate when colors.toml arrived via a relative symlink"

pass "a relative-symlink colors.toml in a user theme is dereferenced on stage"

# The name is joined into paths that get removed and copied into.
for name in .. . "../../evil"; do
if set_theme "$name" >/dev/null; then
Expand Down