diff --git a/bin/omarchy-theme-osc b/bin/omarchy-theme-osc index 28f18388..8768df7c 100755 --- a/bin/omarchy-theme-osc +++ b/bin/omarchy-theme-osc @@ -17,21 +17,56 @@ awk -F= ' return value } + function alias_color(target, source) { + if (colors[target] == "" && colors[source] != "") colors[target] = colors[source] + } + + function emit_color(color_index, key) { + if (colors[key] != "") printf "\033]4;%d;%s\007", color_index, colors[key] + } + { key = $1 gsub(/^[[:space:]]+|[[:space:]]+$/, "", key) value = clean($2) + colors[key] = value } - key == "foreground" { printf "\033]10;%s\007", value } - key == "background" { printf "\033]11;%s\007", value } - key == "cursor" { printf "\033]12;%s\007", value } - key == "selection_background" { printf "\033]17;%s\007", value } - key == "selection_foreground" { printf "\033]19;%s\007", value } - key ~ /^color[0-9]+$/ { - color_index = substr(key, 6) + 0 - if (color_index >= 0 && color_index <= 15) { - printf "\033]4;%d;%s\007", color_index, value - } + END { + alias_color("color0", "bg") + alias_color("color0", "background") + alias_color("color1", "red") + alias_color("color2", "green") + alias_color("color3", "yellow") + alias_color("color4", "blue") + alias_color("color5", "purple") + alias_color("color6", "cyan") + alias_color("color7", "fg") + alias_color("color7", "foreground") + alias_color("color8", "muted") + alias_color("color8", "dark_fg") + alias_color("color8", "foreground") + alias_color("color9", "bright_red") + alias_color("color9", "red") + alias_color("color10", "bright_green") + alias_color("color10", "green") + alias_color("color11", "bright_yellow") + alias_color("color11", "yellow") + alias_color("color12", "bright_blue") + alias_color("color12", "blue") + alias_color("color13", "bright_purple") + alias_color("color13", "purple") + alias_color("color14", "bright_cyan") + alias_color("color14", "cyan") + alias_color("color15", "bright_fg") + alias_color("color15", "foreground") + + if (colors["foreground"] != "") printf "\033]10;%s\007", colors["foreground"] + if (colors["background"] != "") printf "\033]11;%s\007", colors["background"] + if (colors["cursor"] != "") printf "\033]12;%s\007", colors["cursor"] + if (colors["selection_background"] != "") printf "\033]17;%s\007", colors["selection_background"] + if (colors["selection_foreground"] != "") printf "\033]19;%s\007", colors["selection_foreground"] + + for (i = 0; i <= 15; i++) emit_color(i, "color" i) } ' "$theme" diff --git a/bin/omarchy-theme-set-gnome b/bin/omarchy-theme-set-gnome index 8b0b1ddc..c2c6f610 100755 --- a/bin/omarchy-theme-set-gnome +++ b/bin/omarchy-theme-set-gnome @@ -8,9 +8,31 @@ # 2. legacy `light.mode` file shipped beside the theme THEME_DIR=~/.config/omarchy/current/theme COLORS_FILE="$THEME_DIR/colors.toml" + +theme_color() { + local key="$1" + + awk -F= -v key="$key" ' + { + field = $1 + gsub(/^[[:space:]]+|[[:space:]]+$/, "", field) + if (field == key) { + value = $2 + gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) + if (value ~ /^"/) { + sub(/^"/, "", value) + sub(/".*$/, "", value) + } + print value + exit + } + } + ' "$COLORS_FILE" +} + mode="" -if [[ -f $COLORS_FILE ]] && command -v tomlq >/dev/null; then - mode=$(tomlq -r '.mode // empty' "$COLORS_FILE" 2>/dev/null) +if [[ -f $COLORS_FILE ]]; then + mode=$(theme_color mode) fi if [[ -z $mode && -f $THEME_DIR/light.mode ]]; then mode="light" diff --git a/bin/omarchy-theme-set-templates b/bin/omarchy-theme-set-templates index 19a6b6d8..a9a09786 100755 --- a/bin/omarchy-theme-set-templates +++ b/bin/omarchy-theme-set-templates @@ -337,6 +337,20 @@ if [[ -f $COLORS_FILE ]]; then [[ ${THEME_COLORS[bright_blue]} ]] || THEME_COLORS[bright_blue]=$(mix_color "${THEME_COLORS[blue]}" "#ffffff" 20%) [[ ${THEME_COLORS[bright_purple]} ]] || THEME_COLORS[bright_purple]=$(mix_color "${THEME_COLORS[purple]}" "#ffffff" 20%) + # Keep semantic themes compatible with user templates that still reference + # the legacy ANSI placeholders directly. + declare -A ansi_alias=( + [color0]=bg [color1]=red [color2]=green + [color3]=yellow [color4]=blue [color5]=purple + [color6]=cyan [color7]=fg [color8]=muted + [color9]=bright_red [color10]=bright_green [color11]=bright_yellow + [color12]=bright_blue [color13]=bright_purple [color14]=bright_cyan + [color15]=bright_fg + ) + for key in "${!ansi_alias[@]}"; do + [[ ${THEME_COLORS[$key]} ]] || THEME_COLORS[$key]="${THEME_COLORS[${ansi_alias[$key]}]}" + done + # Resolve theme mode (dark|light) with this precedence: # 1. `mode` key in colors.toml # 2. legacy `light.mode` file shipped beside the theme diff --git a/bin/omarchy-theme-set-tmux b/bin/omarchy-theme-set-tmux index 4b778fdd..efb696d1 100755 --- a/bin/omarchy-theme-set-tmux +++ b/bin/omarchy-theme-set-tmux @@ -37,8 +37,11 @@ sync_theme_environment() { sync_colorfgbg() { local colorfgbg="15;0" + local mode - if [[ -f $CURRENT_THEME_PATH/light.mode ]]; then + mode=$(theme_color mode) + + if [[ $mode == "light" ]] || [[ -z $mode && -f $CURRENT_THEME_PATH/light.mode ]]; then colorfgbg="0;15" fi diff --git a/bin/omarchy-theme-set-vscode b/bin/omarchy-theme-set-vscode index 1b44d0bf..569a9fcb 100755 --- a/bin/omarchy-theme-set-vscode +++ b/bin/omarchy-theme-set-vscode @@ -9,9 +9,14 @@ GENERATED_THEME="$HOME/.config/omarchy/current/theme/vscode-theme.json" # Install generated theme as a local extension for a given editor install_generated_extension() { local ext_dir="$1" - local theme_type + local theme_type ui_theme theme_type=$(jq -r '.type // "dark"' "$GENERATED_THEME") + if [[ $theme_type == "light" ]]; then + ui_theme="vs" + else + ui_theme="vs-dark" + fi mkdir -p "$ext_dir/themes" cp "$GENERATED_THEME" "$ext_dir/themes/omarchy-color-theme.json" @@ -28,7 +33,7 @@ install_generated_extension() { "contributes": { "themes": [{ "label": "Omarchy", - "uiTheme": "vs-${theme_type}", + "uiTheme": "$ui_theme", "path": "./themes/omarchy-color-theme.json" }] } diff --git a/test/cli b/test/cli index d4c14bb3..649bf33d 100755 --- a/test/cli +++ b/test/cli @@ -215,6 +215,7 @@ 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" cursor = "#ffffff" @@ -253,12 +254,27 @@ 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 }} +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" +pass "theme template semantic aliases expose legacy colorN helpers" + +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;15;#eeeeee" in data)') +[[ $osc_summary == "16 True True" ]] || fail "theme OSC aliases semantic colors to ANSI palette" +pass "theme OSC aliases semantic colors to ANSI palette" + 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" @@ -296,6 +312,63 @@ 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" +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" 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" + +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" + for binary in \ omarchy-update \ omarchy-theme-set \