From f923dcb758632cfa6a73bfc500c44ae4877e44ae Mon Sep 17 00:00:00 2001 From: fatalerrors Date: Thu, 21 May 2026 11:43:15 +0200 Subject: [PATCH] add preview and configuration saving to prompt theming --- .../bash-completion/prompt-completion.sh | 4 +- profile.d/prompt.sh | 251 ++++++++++++++++-- 2 files changed, 236 insertions(+), 19 deletions(-) diff --git a/profile.d/bash-completion/prompt-completion.sh b/profile.d/bash-completion/prompt-completion.sh index b18fa3b..513b584 100755 --- a/profile.d/bash-completion/prompt-completion.sh +++ b/profile.d/bash-completion/prompt-completion.sh @@ -30,10 +30,12 @@ _complete_set_theme() COMPREPLY=() return 0 ;; + -p|--preview|-S|--save) + ;; esac if [[ "$cur" == -* ]]; then - COMPREPLY=( $(compgen -W "-h --help -l --list" -- "$cur") ) + COMPREPLY=( $(compgen -W "-h --help -l --list -p --preview -S --save" -- "$cur") ) return 0 fi diff --git a/profile.d/prompt.sh b/profile.d/prompt.sh index 5894140..ab99a40 100644 --- a/profile.d/prompt.sh +++ b/profile.d/prompt.sh @@ -169,6 +169,107 @@ load_theme() # ------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ +# Persist PROMPT_THEME in profile configuration ([prompt] section). +# Preference order: ~/.profile.conf when present, else PROFILE_CONF. +_set_theme_save_prompt_theme() +{ + local theme_name="$1" + [[ -z "$theme_name" ]] && { + disp E "Cannot save an empty theme name." + return 1 + } + + local conf_file + if [[ -f "$HOME/.profile.conf" ]]; then + conf_file="$HOME/.profile.conf" + else + conf_file="${PROFILE_CONF:-${MYPATH}/profile.conf}" + fi + + local conf_dir + conf_dir="${conf_file%/*}" + [[ -d "$conf_dir" ]] || mkdir -p "$conf_dir" || { + disp E "Unable to create configuration directory: $conf_dir" + return 1 + } + + local tmp_file="${conf_file}.tmp.$$" + if [[ ! -e "$conf_file" ]]; then + { + printf "[prompt]\n" + printf "PROMPT_THEME=%s\n" "$theme_name" + } > "$conf_file" || { + disp E "Unable to write configuration file: $conf_file" + return 1 + } + return 0 + fi + + awk -v theme="$theme_name" ' + BEGIN { + in_prompt = 0 + saw_prompt = 0 + wrote_key = 0 + } + + { + if ($0 ~ /^\[[^]]+\][[:space:]]*$/) { + if (in_prompt && !wrote_key) { + print "PROMPT_THEME=" theme + wrote_key = 1 + } + + if ($0 == "[prompt]") { + in_prompt = 1 + saw_prompt = 1 + } else { + in_prompt = 0 + } + + print + next + } + + if (in_prompt && $0 ~ /^[[:space:]]*PROMPT_THEME[[:space:]]*=/) { + if (!wrote_key) { + print "PROMPT_THEME=" theme + wrote_key = 1 + } + next + } + + print + } + + END { + if (in_prompt && !wrote_key) { + print "PROMPT_THEME=" theme + wrote_key = 1 + } + + if (!saw_prompt) { + print "" + print "[prompt]" + print "PROMPT_THEME=" theme + } + } + ' "$conf_file" > "$tmp_file" || { + rm -f "$tmp_file" + disp E "Unable to update configuration file: $conf_file" + return 1 + } + + mv "$tmp_file" "$conf_file" || { + rm -f "$tmp_file" + disp E "Unable to replace configuration file: $conf_file" + return 1 + } +} +# Not exported, it remains private +# ------------------------------------------------------------------------------ + + # ------------------------------------------------------------------------------ # Dynamically switch the prompt theme for the current shell session. # Calls load_theme to apply the new colour values immediately, then updates @@ -179,27 +280,86 @@ load_theme() set_theme() { local theme_dir="${PROMPT_THEME_DIR:-${MYPATH}/profile.d/themes}" + local preview=0 + local save=0 + local list_only=0 + local theme_name="" - # -- help mode ----------------------------------------------------------- - if [[ "$1" == "-h" || "$1" == "--help" ]]; then - printf "set_theme: Switch the prompt colour theme for the current shell session.\n\n" - printf "Usage: set_theme [options] [theme]\n\n" - printf "Options:\n" - printf "\t-h, --help\tDisplay this help screen\n" - printf "\t-l, --list\tList available themes (default when no argument is given)\n\n" - printf "Arguments:\n" - printf "\ttheme \tBare theme name (e.g. 'dark') or an explicit path to a .theme file.\n" - printf "\t \tThemes are searched in: %s\n" "$theme_dir" - printf "\t \tOverride with PROMPT_THEME_DIR in profile.conf [prompt].\n\n" - printf "Examples:\n" - printf "\tset_theme \t— list available themes\n" - printf "\tset_theme dark \t— apply the dark theme\n" - printf "\tset_theme ~/my.theme\t— apply a theme by path\n" - return 0 + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + printf "set_theme: Switch the prompt colour theme for the current shell session.\n\n" + printf "Usage: set_theme [options] [theme]\n\n" + printf "Options:\n" + printf "\t-h, --help\tDisplay this help screen\n" + printf "\t-l, --list\tList available themes (default when no argument is given)\n" + printf "\t-p, --preview\tPreview a theme without applying it\n\n" + printf "\t-S, --save\tSave theme to configuration ([prompt] PROMPT_THEME)\n\n" + printf "Arguments:\n" + printf "\ttheme \tBare theme name (e.g. 'dark') or an explicit path to a .theme file.\n" + printf "\t \tThemes are searched in: %s\n" "$theme_dir" + printf "\t \tOverride with PROMPT_THEME_DIR in profile.conf [prompt].\n\n" + printf "Examples:\n" + printf "\tset_theme \t— list available themes\n" + printf "\tset_theme dark \t— apply the dark theme\n" + printf "\tset_theme -p dark \t— preview the dark theme\n" + printf "\tset_theme -S \t— save current theme in config\n" + printf "\tset_theme -S dark \t— apply and save the dark theme\n" + printf "\tset_theme ~/my.theme\t— apply a theme by path\n" + return 0 + ;; + -l|--list) + list_only=1 + shift + ;; + -p|--preview) + preview=1 + shift + ;; + -S|--save) + save=1 + shift + ;; + --) + shift + break + ;; + -*) + disp E "Unknown option: $1, use \"set_theme --help\" to display usage." + return 1 + ;; + *) + if [[ -n "$theme_name" ]]; then + disp E "Too many arguments. Usage: set_theme [options] [theme]" + return 1 + fi + theme_name="$1" + shift + ;; + esac + done + + if [[ $# -gt 0 ]]; then + if [[ -n "$theme_name" ]]; then + disp E "Too many arguments. Usage: set_theme [options] [theme]" + return 1 + fi + theme_name="$1" + shift fi # -- list mode ----------------------------------------------------------- - if [[ $# -eq 0 || "$1" == "-l" || "$1" == "--list" ]]; then + if (( list_only )) || [[ -z "$theme_name" && $preview -eq 0 ]]; then + if (( save )); then + if [[ -n "${PROMPT_THEME:-}" ]]; then + _set_theme_save_prompt_theme "$PROMPT_THEME" || return 1 + disp I "Saved current prompt theme '$PROMPT_THEME' to configuration." + return 0 + fi + disp E "No active theme to save. Apply a theme first or pass one with -S." + return 1 + fi + printf "Available themes in %s:\n" "$theme_dir" local f name for f in "$theme_dir"/*.theme; do @@ -215,14 +375,69 @@ set_theme() return 0 fi + if (( preview )) && [[ -z "$theme_name" ]]; then + disp E "--preview requires a theme argument." + return 1 + fi + + if (( preview && save )); then + disp E "--preview and --save cannot be used together." + return 1 + fi + + # -- preview mode -------------------------------------------------------- + if (( preview )); then + local old_theme="${PROMPT_THEME:-}" + local -a old_prompt_color_vars=() + local _v + for _v in ${!PROMPT_COLOR_@}; do + old_prompt_color_vars+=("$_v=${!_v}") + done + + set_colors + load_theme "$theme_name" || { + set_colors + if [[ -n "$old_theme" ]]; then + load_theme "$old_theme" || true + export PROMPT_THEME="$old_theme" + fi + return 1 + } + + printf "Preview for theme '%s':\n" "$theme_name" + printf " %b13:37:00%b %b0%b %b•%b %buser%b@%bhost%b %b/path/to/dir%b %bgit:main +1/-0%b\n" \ + "${PROMPT_COLOR_TIME_FG:-}" "${DEFAULTCOL:-}" \ + "${PROMPT_COLOR_OK_FG:-}" "${DEFAULTCOL:-}" \ + "${PROMPT_COLOR_OK_MARK:-}" "${DEFAULTCOL:-}" \ + "${PROMPT_COLOR_USER_FG:-}" "${DEFAULTCOL:-}" \ + "${PROMPT_COLOR_ROOT_FG:-}" "${DEFAULTCOL:-}" \ + "${PROMPT_COLOR_DIR_FG:-}" "${DEFAULTCOL:-}" \ + "${PROMPT_COLOR_CTX_FG:-}" "${DEFAULTCOL:-}" + + set_colors + if [[ -n "$old_theme" ]]; then + load_theme "$old_theme" || true + export PROMPT_THEME="$old_theme" + fi + for _v in "${old_prompt_color_vars[@]}"; do + export "$_v" + done + return 0 + fi + # -- apply mode ---------------------------------------------------------- - local theme_name="$1" # Reset colours to defaults before loading the new theme set_colors load_theme "$theme_name" || return 1 export PROMPT_THEME="$theme_name" + if (( save )); then + _set_theme_save_prompt_theme "$theme_name" || return 1 + disp I "Prompt theme set to $theme_name and saved to configuration." + return 0 + fi + disp I "Prompt theme set to $theme_name." } export -f set_theme