A theme installed from a git repo is named after the repo URL, and that name becomes its directory name under ~/.config/omarchy/themes. Style > Unlock built a command line out of the name the picker returned and handed it to omarchy-launch-floating-terminal-with-presentation, which runs its argument as a shell string -- so a theme directory called `a';id;'b` ran `id`. Themes are already held to contributing colour and nothing that executes, which is why omarchy-theme-set stages no .lua, terminal config, or vscode.json from one. Hold the derived name to the characters a theme name needs, which stops it from being dangerous at every place it lands rather than at the one found, and quote it with printf %q on the way into the action for the names already on disk. omarchy-theme-remove keeps its existing path-climb guard: its name reaches only a quoted rm, and the same charset would strand a theme installed before this. Reported-by: Luis Alvarez (lalvarezt) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011WFcUm5HWFyxaVYdwAeWPP
59 lines
2.3 KiB
Bash
Executable File
59 lines
2.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Install a theme from a git repository
|
|
# omarchy:args=[git-repo-url]
|
|
# omarchy:examples=omarchy theme install https://github.com/example/omarchy-example-theme.git
|
|
# omarchy:examples=omarchy theme install git@github.com:example/omarchy-example-theme.git
|
|
|
|
if [[ -z $1 ]]; then
|
|
echo -e "\e[32mSee https://omarchy.org/themes/\n\e[0m"
|
|
REPO_URL=$(gum input --placeholder="Git repo URL (https or git@host:org/repo.git)" --header="")
|
|
else
|
|
REPO_URL="$1"
|
|
fi
|
|
|
|
if [[ -z $REPO_URL ]]; then
|
|
exit 1
|
|
fi
|
|
|
|
# Refuse a URL that names a git option or a transport helper before cloning. The
|
|
# check is shared with omarchy-plugin-add and explains itself; a missing checker
|
|
# leaves this non-zero, which refuses the URL rather than cloning it.
|
|
omarchy-git-url-check "$REPO_URL" || exit 1
|
|
|
|
THEMES_DIR="$HOME/.config/omarchy/themes"
|
|
|
|
# Strip user@host: prefix from scp-style SSH URLs so basename sees just the path
|
|
REPO_PATH="$REPO_URL"
|
|
[[ $REPO_PATH != *"://"* && $REPO_PATH == *:*/* ]] && REPO_PATH="${REPO_PATH#*:}"
|
|
THEME_NAME=$(basename -- "$REPO_PATH" .git | sed -E 's/^omarchy-//; s/-theme$//' | tr '[:upper:]' '[:lower:]')
|
|
THEME_PATH="$THEMES_DIR/$THEME_NAME"
|
|
|
|
# The name comes from the URL, is joined into a path that is about to be
|
|
# removed, and then names a directory the rest of Omarchy passes around by
|
|
# name: Style > Unlock builds a command line out of the one the picker
|
|
# returned. So it is held to the characters a theme name needs rather than
|
|
# screened for the harm of the day -- a repo called `..` would take
|
|
# ~/.config/omarchy with it, and one called `a';'id` would carry its own
|
|
# command into that picker. The leading character is kept out of `.` and `-`,
|
|
# which also covers `host:-s/foo.git` leaving basename with `.git`.
|
|
if [[ ! $THEME_NAME =~ ^[a-z0-9][a-z0-9._-]*$ ]]; then
|
|
echo "Error: '$REPO_URL' does not give a usable theme name."
|
|
exit 1
|
|
fi
|
|
|
|
# Remove existing theme if present
|
|
if [[ -d $THEME_PATH ]]; then
|
|
rm -rf "$THEME_PATH"
|
|
fi
|
|
|
|
# Clone the repo directly to ~/.config/omarchy/themes
|
|
if ! git clone -- "$REPO_URL" "$THEME_PATH"; then
|
|
echo "Error: Failed to clone theme repo."
|
|
exit 1
|
|
fi
|
|
|
|
# Apply the new theme with omarchy-theme-set, which stages only the files an
|
|
# extra theme is allowed to contribute and names anything it dropped.
|
|
omarchy-theme-set "$THEME_NAME"
|