diff options
Diffstat (limited to 'bin/theme')
| -rwxr-xr-x | bin/theme | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/bin/theme b/bin/theme new file mode 100755 index 0000000..39f25d1 --- /dev/null +++ b/bin/theme @@ -0,0 +1,554 @@ +#!/bin/bash + +set -euo pipefail + +: ${HOME:="/Users/$(whoami)"} +: ${XDG_CONFIG_HOME:=$HOME/.config} +: ${XDG_DATA_HOME:=$HOME/.local/share} + + +_sed_i() { + if [[ "$(uname)" == "Darwin" ]]; then + sed -i '' "$@" + else + sed -i'' "$@" + fi +} + +is_auto_dark_mode() { + if [[ "$OSTYPE" == "darwin"* ]]; then + defaults read -g AppleInterfaceStyleSwitchesAutomatically >/dev/null 2>&1 + else + true + fi +} +is_ubuntu_desktop() { + [[ "$(lsb_release -is)" == "Ubuntu" ]] \ + && dpkg -l | grep -q desktop +} +is_dark_mode() { + if [[ "$OSTYPE" == "darwin"* ]]; then + defaults read -g AppleInterfaceStyle >/dev/null 2>&1 + elif [[ -n "${SSH_CONNECTION:-}" ]]; then + true + elif is_ubuntu_desktop ; then + [[ "$(gsettings get org.gnome.desktop.interface color-scheme 2>&1)" != *'light'* ]] + else + true + fi +} +set_macos_dark_mode_to() { + osascript -e 'tell application "System Events" to tell appearance preferences to set dark mode to '"$1" +} +set_dark_mode() { + if [[ "$OSTYPE" == "darwin"* ]]; then + set_macos_dark_mode_to "true" + elif is_ubuntu_desktop ; then + gsettings set org.gnome.desktop.interface color-scheme prefer-dark > /dev/null || true + fi +} +unset_dark_mode() { + if [[ "$OSTYPE" == "darwin"* ]]; then + set_macos_dark_mode_to "false" + elif is_ubuntu_desktop ; then + gsettings set org.gnome.desktop.interface color-scheme prefer-light > /dev/null || true + fi +} +get_mode() { + local mode="${1:-}" + if [[ -z "$mode" ]]; then + if is_dark_mode ; then + mode="dark" + else + mode="light" + fi + fi + if [[ "$mode" != "dark" && "$mode" != "light" ]] + then + >&2 echo "ERROR: unsupported mode '$mode'" + exit 1 + fi + if [[ "${mode}" == 'dark' ]] ; then + echo "dark" + else + echo "light" + fi +} +set_mode() { + local mode="${1:-}" + if [[ "$(get_mode "$mode")" == 'dark' ]] + then + set_dark_mode + else + unset_dark_mode + fi +} + + + +# List the available color config options +list_colors() { + local ext="$1" + local dir="$2" + if [ ! -e "$dir" ] ; then + echo "(none)" + return + fi + find "${dir}/" -mindepth 1 -type f -print0 \ + | xargs -r -0 -n 1 basename \ + | sed 's/'"$ext"'$//' \ + | sort +} +# Select the first readable file from a list of filepaths +# specified as arguments. +first_file_in() { + cd "$1" + shift + while [[ $# -ne 0 ]] + do + if [[ -r "$1" ]] + then + echo "$(pwd)/$1" + return 0 + else + shift + fi + done + return 1 +} +color_file() { + local dir="$1" + local ext="$2" + local colors="$3" + local mode="$4" + if ! first_file_in "$dir" \ + "${colors}-${mode}${ext}" \ + "${colors}${mode}${ext}" \ + "${colors}${ext}" \ + "${mode}${ext}" + then + >&2 echo "ERROR: unable to load $ext colors for $colors $mode from $dir" + return 1 + fi +} +# Create or replace colors in a given config file from another +# file specifying the color config content. +set_colors_in_config() { + config_file="$1" + colors_file="$2" + line_comment_prefix="${3:-## }" + if [[ -L "$config_file" ]] + then + config_file="$(readlink "$config_file")" + fi + mkdir -p "$(dirname "$config_file")" + if [[ -r "$config_file" ]] + then + _sed_i '/GEN COLORS START/,/GEN COLORS END/d' "$config_file" + fi + cat >> "$config_file" <<EOF +$line_comment_prefix GEN COLORS START +$line_comment_prefix from: $colors_file +$(cat "$colors_file") +$line_comment_prefix GEN COLORS END +EOF +} + +alacritty_ext='.toml' +alacritty_cfg="$XDG_DATA_HOME/alacritty/color${alacritty_ext}" +alacritty_colors_dir1="$XDG_CONFIG_HOME/alacritty/colors" +alacritty_colors_dir2="$HOME/src/alacritty/alacritty-theme/themes" +alacritty_colors() { + { + list_colors "${alacritty_ext}" "$alacritty_colors_dir1" + list_colors "${alacritty_ext}" "$alacritty_colors_dir2" + } | sort +} +alacritty_color_file() { + color_file "${alacritty_colors_dir1}" "${alacritty_ext}" "$1" "$2" 2>/dev/null || \ + color_file "${alacritty_colors_dir2}" "${alacritty_ext}" "$1" "$2" 2>/dev/null || \ + color_file "${alacritty_colors_dir1}" "${alacritty_ext}" "$1" "$2" +} +alacritty_color_check_exists() { + alacritty_color_file "$1" "$2" > /dev/null +} +alacritty_colors_set() { + set_colors_in_config "${alacritty_cfg}" "$(alacritty_color_file "$1" "$2")" + touch "$XDG_CONFIG_HOME/alacritty/alacritty${alacritty_ext}" +} + +bat_ext='.sh' +bat_cfg="$XDG_DATA_HOME/bat/color.sh" +bat_colors_dir="$XDG_CONFIG_HOME/bat/colors" +bat_colors() { + # list_colors "${bat_ext}" "$bat_colors_dir" + bat --list-themes | cat +} +bat_color_file() { + color_file "${bat_colors_dir}" "${bat_ext}" "$1" "$2" +} +bat_color_check_exists() { + bat_color_file "$1" "$2" > /dev/null +} +bat_colors_set() { + local mode="$2" + + # best for light: Coldark-Cold, Github, Monokai Extended Light, OneHalfLight, gruvbox-light + # best for dark: 1337, Coldark-Dark, Monokai Extended, OneHalfDark, gruvbox-dark + # works well with both: ansi + local theme="1337" + if [[ "$mode" == "light" ]] + then + theme="gruvbox-light" + fi + + [[ -d "$(dirname "${bat_cfg}")" ]] || mkdir -p "$(dirname "${bat_cfg}")" + echo "--theme='$theme'" > "${bat_cfg}" +} + +tmux_ext='.conf' +tmux_cfg="$XDG_DATA_HOME/tmux/color.conf" +tmux_colors_dir="$XDG_CONFIG_HOME/tmux/colors" +tmux_colors() { + list_colors "${tmux_ext}" "$tmux_colors_dir" +} +tmux_color_file() { + color_file "${tmux_colors_dir}" "${tmux_ext}" "$1" "$2" +} +tmux_color_check_exists() { + tmux_color_file "$1" "$2" > /dev/null +} +tmux_colors_set() { + set_colors_in_config "${tmux_cfg}" "$(tmux_color_file "$1" "$2")" + tmux source-file "${tmux_cfg}" +} + +neovim_ext='.lua' +neovim_cfg="${XDG_DATA_HOME}/nvim/colors.lua" +neovim_colors_dir="$XDG_CONFIG_HOME/nvim/colors" +neovim_colors() { + list_colors "${neovim_ext}" "$neovim_colors_dir" +} +neovim_color_file() { + color_file "${neovim_colors_dir}" "${neovim_ext}" "$1" "$2" +} +neovim_color_check_exists() { + neovim_color_file "$1" "$2" 2>/dev/null > /dev/null +} +neovim_colors_set() { + colors="$1" + mode="$2" + if neovim_color_check_exists "${colors}" "${mode}" + then + set_colors_in_config "${neovim_cfg}" "$(neovim_color_file "$1" "$2")" '-- ' + else + cat <<EOF > "${neovim_cfg}" +-- GEN COLORS START +local theme_mode = "$mode" +local theme_colors = "$colors" +$(cat "${neovim_colors_dir}/default.lua") +-- GEN COLORS END +EOF + fi +} + +ghostty_cfg="$XDG_DATA_HOME/ghostty/color" +ghostty_colors_dir="$XDG_CONFIG_HOME/ghostty/colors" +# Check if a custom Ghostty color file exists +ghostty_custom_color_file() { + local colors="$1" + local mode="$2" + + # Try to find custom color file (similar to other tools) + if ! first_file_in "$ghostty_colors_dir" \ + "${colors}-${mode}" \ + "${colors}${mode}" \ + "${colors}" + then + return 1 + fi +} +# Map colorscheme names to Ghostty built-in theme names +ghostty_theme_name() { + local colors="$1" + local mode="$2" + + # Direct mappings for common colorschemes + case "$colors" in + molokai) + # echo "Monokai Soda" + # echo "Monokai Pro Spectrum" + echo "Brogrammer" + ;; + gruvbox) + if [[ "$mode" == "dark" ]]; then + echo "Gruvbox Dark" + else + echo "Gruvbox Light" + fi + ;; + papercolor) + if [[ "$mode" == "dark" ]]; then + echo "GitHub Dark Default" + else + echo "GitHub Light Default" + fi + ;; + solarized) + if [[ "$mode" == "dark" ]]; then + echo "Solarized Dark Patched" + else + echo "Builtin Solarized Light" + fi + ;; + nord) + echo "Nord" + ;; + dracula) + echo "Dracula" + ;; + *) + # Fallback: try to find a matching theme name (case-insensitive) + local search_term="$colors" + ghostty +list-themes --plain 2>/dev/null | sed 's/ (resources)//' | grep -i "^${search_term}$" | head -n 1 || echo "" + ;; + esac +} +ghostty_colors() { + { + # List custom color files first + if [[ -d "$ghostty_colors_dir" ]]; then + find "$ghostty_colors_dir" -mindepth 1 -type f -print0 \ + | xargs -r -0 -n 1 basename \ + | sort + fi + # Then list built-in themes + ghostty +list-themes --plain 2>/dev/null | sed 's/ (resources)//' + } | sort -u || echo "(ghostty not found)" +} +ghostty_color_check_exists() { + local colors="$1" + local mode="$2" + + # # First check for custom color file + # if ghostty_custom_color_file "$colors" "$mode" >/dev/null 2>&1; then + # return 0 + # fi + + # Then check for built-in theme + local theme_name + theme_name="$(ghostty_theme_name "$colors" "$mode")" + if [[ -n "$theme_name" ]]; then + return 0 + else + return 1 + fi +} +ghostty_colors_set() { + local colors="$1" + local mode="$2" + local custom_file + local theme_name + + mkdir -p "$(dirname "$ghostty_cfg")" + + # First priority: use custom color file if it exists + if custom_file="$(ghostty_custom_color_file "$colors" "$mode" 2>/dev/null)"; then + cat > "$ghostty_cfg" <<EOF +# Generated by theme script +# Colorscheme: $colors ($mode) +# Using custom color file: $custom_file +$(cat "$custom_file") +EOF + else + # Second priority: use built-in theme + theme_name="$(ghostty_theme_name "$colors" "$mode")" + + if [[ -z "$theme_name" ]]; then + >&2 echo "WARNING: No Ghostty theme found for '$colors' in $mode mode, skipping Ghostty theme update" + return 0 + fi + + cat > "$ghostty_cfg" <<EOF +# Generated by theme script +# Colorscheme: $colors ($mode) +# Using built-in theme: $theme_name +theme = $theme_name +EOF + fi + + # Trigger Ghostty reload + local script_dir + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + "$script_dir/ghostty-reload" +} + + + +# default colors file saves the local colors preference for each mode +default_colors_file_dark="${XDG_DATA_HOME}/dark-colors" +default_colors_file_light="${XDG_DATA_HOME}/light-colors" +get_default_colors_file() { + local mode="${1-:}" + if [[ "$(get_mode "$mode")" == "dark" ]] ; then + echo "${default_colors_file_dark}" + else + echo "${default_colors_file_light}" + fi +} +get_colors() { + local mode="${1:-}" + local file + file="$(get_default_colors_file "$mode" )" + if [[ -r "$file" ]] + then + cat "$file" + else + is_dark_mode && echo "molokai" || echo "papercolor" + fi +} +common_colors() { + local col com aux types + col="$(mktemp)" + com="$(mktemp)" + aux="$(mktemp)" + types=( + bat + tmux + neovim + alacritty + ghostty + ) + for typ in "${types[@]}"; do + echo "[[ $typ ]]" + "${typ}_colors" | sort | tee "${col}" + if [[ "$(wc -l < "${com}")" -gt 0 ]]; then + comm -12 "${com}" "${col}" > "${aux}" + cp "${aux}" "${com}" + else + cp "${col}" "${com}" + fi + echo "" + done + echo "[[ common ]]" + cat "${com}" + rm "${com}" "${aux}" +} +color_check_exists() { + local colors="$1" + local mode="$2" + if ! tmux_color_check_exists "$colors" "$mode"; then + >&2 echo "ERROR: tmux colors '$colors' not found for mode '$mode'" + return 1 + fi + if ! alacritty_color_check_exists "$colors" "$mode"; then + >&2 echo "ERROR: alacritty colors '$colors' not found for mode '$mode'" + return 1 + fi + # neovim and bat have fallback mechanisms, so don't require strict checking + return 0 +} +set_colors() { + local mode="$1" + local colors="$2" + if [[ -z "$mode" ]]; then + mode="$(get_mode)" + fi + if [[ -z "$colors" ]]; then + colors="$(get_colors "$mode")" + fi + color_check_exists "$colors" "$mode" + + bat_colors_set "$colors" "$mode" + tmux_colors_set "$colors" "$mode" + neovim_colors_set "$colors" "$mode" + alacritty_colors_set "$colors" "$mode" + ghostty_colors_set "$colors" "$mode" + + local colors_file + colors_file="$(get_default_colors_file "$mode")" + mkdir -p "$(dirname "$colors_file")" + echo "$colors" > "$colors_file" 2>/dev/null || true +} + +set_theme() { + local mode=$1 + local colors=$2 + + set_mode "$mode" + set_colors "$mode" "$colors" + + echo "Set theme to $(get_mode "$mode") $(get_colors "$mode")" +} + +print_help() { + local s_name + s_name="$(basename $0)" + cat <<EOF +Help + +Current set theme: + + $s_name + +Current mode + + $s_name --mode + +Current colorscheme + + $s_name --colors + +Set theme + + $s_name --set [light|dark] [colorscheme] + +List available colorschemes + + $s_name --list + $s_name --list-bat + $s_name --list-tmux + $s_name --list-neovim + $s_name --list-alacritty + $s_name --list-ghostty +EOF +} + +if test $# -eq 0 +then + echo "$(get_mode) $(get_colors)" + exit 0 +fi + +while test $# -gt 0 +do + case $1 in + --mode) + get_mode; exit 0; ;; + --colors) + get_colors; exit 0; ;; + --set) + set_theme "${2:-}" "${3:-}"; exit 0; ;; + --list-alacritty) + alacritty_colors; exit 0; ;; + --list-tmux) + tmux_colors; exit 0; ;; + --list-neovim) + neovim_colors; exit 0; ;; + --list-bat) + bat_colors; exit 0; ;; + --list-ghostty) + ghostty_colors; exit 0; ;; + --list) + common_colors; exit 0; ;; + --help|-h) + print_help; exit 0; ;; + *) + print_help; exit 1; ;; + esac + shift +done + +>&2 echo "ERROR: Unexpected state!" +exit 1 + |
