From d7c9e16f03573fa037cafd2cb081170f61dc6abb Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Sat, 14 Feb 2015 21:28:50 -0500 Subject: [PATCH 1/8] plugins/theme: change to 2-space indenting and detabify (per https://github.com/robbyrussell/oh-my-zsh/wiki/Coding-style-guide#general) --- plugins/themes/themes.plugin.zsh | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/plugins/themes/themes.plugin.zsh b/plugins/themes/themes.plugin.zsh index 7519b0253..7a2a00fea 100644 --- a/plugins/themes/themes.plugin.zsh +++ b/plugins/themes/themes.plugin.zsh @@ -1,24 +1,24 @@ function theme { - if [ -z "$1" ] || [ "$1" = "random" ]; then - themes=($ZSH/themes/*zsh-theme) - N=${#themes[@]} - ((N=(RANDOM%N)+1)) - RANDOM_THEME=${themes[$N]} - source "$RANDOM_THEME" - echo "[oh-my-zsh] Random theme '$RANDOM_THEME' loaded..." + if [ -z "$1" ] || [ "$1" = "random" ]; then + themes=($ZSH/themes/*zsh-theme) + N=${#themes[@]} + ((N=(RANDOM%N)+1)) + RANDOM_THEME=${themes[$N]} + source "$RANDOM_THEME" + echo "[oh-my-zsh] Random theme '$RANDOM_THEME' loaded..." + else + if [ -f "$ZSH_CUSTOM/$1.zsh-theme" ] + then + source "$ZSH_CUSTOM/$1.zsh-theme" else - if [ -f "$ZSH_CUSTOM/$1.zsh-theme" ] - then - source "$ZSH_CUSTOM/$1.zsh-theme" - else - source "$ZSH/themes/$1.zsh-theme" - fi + source "$ZSH/themes/$1.zsh-theme" fi + fi } function lstheme { - cd $ZSH/themes - ls *zsh-theme | sed 's,\.zsh-theme$,,' + cd $ZSH/themes + ls *zsh-theme | sed 's,\.zsh-theme$,,' } From 2012ae812635a5e03f82d214a2902e25defb8338 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Sat, 14 Feb 2015 22:25:26 -0500 Subject: [PATCH 2/8] plugins/themes: Rewrite theme() and lstheme() to remove pwd and variable side effects and make behavior consistent. Include custom themes in lstheme() output. Add comments that lay down the function interface. Look for custom themes in $ZSH_CUSTOM/themes as well as base $ZSH_CUSTOM. Rewrite theme's random theme selection in terms of lstheme() so random themes are included, and to streamline code. Add a failure indication to theme() with nonzero return status. When a bad theme name is requested, indicate so by issuing a warning and returning nonzero. --- plugins/themes/themes.plugin.zsh | 67 +++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/plugins/themes/themes.plugin.zsh b/plugins/themes/themes.plugin.zsh index 7a2a00fea..9c1b47fcf 100644 --- a/plugins/themes/themes.plugin.zsh +++ b/plugins/themes/themes.plugin.zsh @@ -1,24 +1,55 @@ -function theme -{ - if [ -z "$1" ] || [ "$1" = "random" ]; then - themes=($ZSH/themes/*zsh-theme) - N=${#themes[@]} - ((N=(RANDOM%N)+1)) - RANDOM_THEME=${themes[$N]} - source "$RANDOM_THEME" - echo "[oh-my-zsh] Random theme '$RANDOM_THEME' loaded..." +# Load a theme +# +# Usage: +# "theme " loads the named theme +# "theme random" or "theme" with no argument loads a random theme +# Return value: +# 0 on success +# Nonzero on failure, such as requested theme not being found +function theme() { + if [[ -z "$1" ]] || [[ "$1" = "random" ]]; then + # Select a random theme + local themes n random_theme + themes=($(lstheme)) + n=${#themes[@]} + ((n=(RANDOM%n)+1)) + random_theme=${themes[$n]} + echo "[oh-my-zsh] Loading random theme '$random_theme'..." + theme $random_theme else - if [ -f "$ZSH_CUSTOM/$1.zsh-theme" ] - then - source "$ZSH_CUSTOM/$1.zsh-theme" - else - source "$ZSH/themes/$1.zsh-theme" + # Main case: load named theme + local name theme_dir found + name=$1 + found=false + for theme_dir ($ZSH_CUSTOM $ZSH_CUSTOM/themes $ZSH/themes); do + if [[ -f "$theme_dir/$name.zsh-theme" ]]; then + source "$theme_dir/$name.zsh-theme" + found=true + break + fi + done + if [[ $found == false ]]; then + echo "[oh-my-zsh] Theme not found: $name" + return 1 fi fi } -function lstheme -{ - cd $ZSH/themes - ls *zsh-theme | sed 's,\.zsh-theme$,,' +# List available themes by name +# +# The list will always be in sorted order, so you can index in to it. +function lstheme(){ + local themes x theme_dir + themes=() + for theme_dir ($ZSH_CUSTOM $ZSH_CUSTOM/themes $ZSH/themes); do + if [[ -d $theme_dir ]]; then + themes+=($(_omz_lstheme_dir $theme_dir)) + fi + done + echo ${(F)themes} | sort | uniq } + +# List themes defined in a given dir +function _omz_lstheme_dir() { + ls $1 | grep '.zsh-theme$' | sed 's,\.zsh-theme$,,' +} \ No newline at end of file From e52edc22d450feb21ce877d1a419dd64a8063d52 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Tue, 17 Feb 2015 01:02:16 -0500 Subject: [PATCH 3/8] Pull in _theme autocompletion from old plugin (which I missed during the initial folding-over). --- lib/_theme | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 lib/_theme diff --git a/lib/_theme b/lib/_theme new file mode 100644 index 000000000..8214ddb0d --- /dev/null +++ b/lib/_theme @@ -0,0 +1,3 @@ +#compdef theme + +_arguments "1: :($(lstheme | tr "\n" " "))" From 7792fbfa48bf2644b6276b5f9b4ce309eeae6c13 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Tue, 17 Feb 2015 01:03:55 -0500 Subject: [PATCH 4/8] Revert "Pull in _theme autocompletion from old plugin (which I missed during the initial folding-over)." This reverts commit e52edc22d450feb21ce877d1a419dd64a8063d52. --- lib/_theme | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 lib/_theme diff --git a/lib/_theme b/lib/_theme deleted file mode 100644 index 8214ddb0d..000000000 --- a/lib/_theme +++ /dev/null @@ -1,3 +0,0 @@ -#compdef theme - -_arguments "1: :($(lstheme | tr "\n" " "))" From 69e3840fbee405a41690c3a2cf6613845f614e37 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Tue, 17 Feb 2015 01:08:42 -0500 Subject: [PATCH 5/8] Remove `tr` which was unneeded since it's in a list context (I think). --- plugins/themes/_theme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/themes/_theme b/plugins/themes/_theme index 8214ddb0d..3186943ea 100644 --- a/plugins/themes/_theme +++ b/plugins/themes/_theme @@ -1,3 +1,3 @@ #compdef theme -_arguments "1: :($(lstheme | tr "\n" " "))" +_arguments "1: :($(lstheme))" From 66d0b80d065fd98c699abde91b6925e61ce59d22 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Tue, 31 Mar 2015 03:53:33 -0400 Subject: [PATCH 6/8] Themes: add ability to unload theme cleanly, add debugging info Unloads themes by resetting variables and removing hook functions. --- plugins/themes/themes.plugin.zsh | 172 ++++++++++++++++++++++++++++++- 1 file changed, 169 insertions(+), 3 deletions(-) diff --git a/plugins/themes/themes.plugin.zsh b/plugins/themes/themes.plugin.zsh index 9c1b47fcf..eb3ae6b0e 100644 --- a/plugins/themes/themes.plugin.zsh +++ b/plugins/themes/themes.plugin.zsh @@ -1,3 +1,8 @@ +# Set to true to enable debugging output for theme functions +# Note that this can cause unstable behavior, especially with these themes: +# agnoster dstufft +ZSH_THEME_DEBUG=${ZSH_THEME_DEBUG:-false} + # Load a theme # # Usage: @@ -23,8 +28,8 @@ function theme() { found=false for theme_dir ($ZSH_CUSTOM $ZSH_CUSTOM/themes $ZSH/themes); do if [[ -f "$theme_dir/$name.zsh-theme" ]]; then - source "$theme_dir/$name.zsh-theme" found=true + _omz_load_theme_from_file $name "$theme_dir/$name.zsh-theme" break fi done @@ -35,10 +40,169 @@ function theme() { fi } +# Variables to track hook functions installed by themes +_OMZ_THEME_CHPWD_FUNCTIONS=() +_OMZ_THEME_PRECMD_FUNCTIONS=() +_OMZ_THEME_PREEXEC_FUNCTIONS=() + +# Implementation of loading a theme +# Most of the code in here is for tracking hooks and debugging support +function _omz_load_theme_from_file() { + local name=$1 file=$2 params_before exclude_params + local -A values_before + + # Reset so theme is loaded into a clean slate + _omz_reset_theme + + # Set up tracking and debugging + local chpwd_fcns_0 precmd_fcns_0 preexec_fcns_0 chpwd_0 precmd_0 preexec_0 + local params_after params_added param ignore_params + chpwd_0=$(which chpwd) + precmd_0=$(which precmd) + preexec_0=$(which preexec) + chpwd_fcns_0=($chpwd_functions) + precmd_fcns_0=($precmd_functions) + preexec_fcns_0=($preexec_functions) + if [[ $ZSH_THEME_DEBUG == true ]]; then + params_before=($(set +)) + fi + for param ($params_before); do + values_before[$param]=${(P)param} + done + + # Actually load the theme + source $file + + # Debugging stuff + if [[ $ZSH_THEME_DEBUG == true ]]; then + params_after=($(set +)) + params_added=(${params_after:|params_before}) + ignore_params=(LINENO RANDOM _ parameters prompt values_before modules \ + params_added ignore_params params_before params_after params_changed \ + SECONDS TTYIDLE) + params_before=(${params_before:|ignore_params}) + local params_changed + params_changed=() + for param ($params_before); do + if [[ ${(P)param} != ${values_before[$param]} ]]; then + params_changed+=($param) + fi + done + fi + + # Track changes to hooks + _OMZ_THEME_CHPWD_FUNCTIONS=(${chpwd_functions:|chpwd_fcns_0}) + _OMZ_THEME_PRECMD_FUNCTIONS=(${precmd_functions:|precmd_fcns_0}) + _OMZ_THEME_PREEXEC_FUNCTIONS=(${preexec_functions:|preexec_fcns_0}) + + # Post-loading debugging + if [[ $ZSH_THEME_DEBUG == true ]]; then + echo "Loaded theme $name from file $file" + if [[ -n $params_added ]]; then + printf '=== %s ===\n%s\n' "Theme added parameters:" ${(F)params_added} + fi + if [[ -n $params_changed ]]; then + printf '=== %s ===\n%s\n' "Theme changed parameters:" ${(F)params_changed} + fi + if [[ -n "$_OMZ_THEME_CHPWD_FUNCTIONS$_OMZ_THEME_PRECMD_FUNCTIONS$_OMZ_THEME_PREEXEC_FUNCTIONS" ]]; then + printf '=== %s ===\n' "Theme added hooks:" + if [[ -n $_OMZ_THEME_CHPWD_FUNCTIONS ]]; then + echo "Theme added chpwd hooks: $_OMZ_THEME_CHPWD_FUNCTIONS" + fi + if [[ -n $_OMZ_THEME_PRECMD_FUNCTIONS ]]; then + echo "Theme added precmd hooks: $_OMZ_THEME_PRECMD_FUNCTIONS" + fi + if [[ -n $_OMZ_THEME_PREEXEC_FUNCTIONS ]]; then + echo "Theme added preexec hooks: $_OMZ_THEME_PREEXEC_FUNCTIONS" + fi + fi + if [[ $(which chpwd) != $chpwd_0 ]]; then + echo "WARNING: Theme changed chpwd()" + fi + if [[ $(which preexec) != $preexec_0 ]]; then + echo "WARNING: Theme changed preexec()" + fi + if [[ $(which precmd) != $precmd_0 ]]; then + echo "WARNING: Theme changed precmd()" + fi + fi +} + +# Resets all theme settings to their default state +# (To the extent that we know what themes do, that is.) +# This will reset all variables used by the core OMZ *_prompt_info functions. +# It will also remove any hook functions installed by the current theme, if it +# was loaded by the theme() function +function _omz_reset_theme() { + PROMPT="%n@%m:%~%# " + + # This assumes that all ZSH_THEME__* variables are owned by + # OMZ theming, and can be reset en masse + # All the commented-out variables are there to serve as a list of things + # that are used by theme support and could be given default values + + # git_prompt_info variables + unset -m 'ZSH_THEME_GIT_PROMPT_*' + ZSH_THEME_GIT_PROMPT_PREFIX="git:(" # Prefix at the very beginning of the prompt, before the branch name + ZSH_THEME_GIT_PROMPT_SUFFIX=")" # At the very end of the prompt + #ZSH_THEME_GIT_PROMPT_PREFIX= + #ZSH_THEME_GIT_PROMPT_SUFFIX= + #ZSH_THEME_GIT_COMMITS_AHEAD_PREFIX= + #ZSH_THEME_GIT_COMMITS_AHEAD_SUFFIX= + ZSH_THEME_GIT_PROMPT_DIRTY="*" # Text to display if the branch is dirty + ZSH_THEME_GIT_PROMPT_CLEAN="" # Text to display if the branch is clean + #ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE= + #ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE= + #ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE= + #ZSH_THEME_GIT_PROMPT_AHEAD= + #ZSH_THEME_GIT_PROMPT_BEHIND= + #ZSH_THEME_GIT_PROMPT_SHA_BEFORE= + #ZSH_THEME_GIT_PROMPT_SHA_AFTER= + #ZSH_THEME_GIT_PROMPT_ADDED= + #ZSH_THEME_GIT_PROMPT_MODIFIED= + #ZSH_THEME_GIT_PROMPT_RENAMED= + #ZSH_THEME_GIT_PROMPT_DELETED= + #ZSH_THEME_GIT_PROMPT_STASHED= + #ZSH_THEME_GIT_PROMPT_UNMERGED= + #ZSH_THEME_GIT_PROMPT_DIVERGED= + #ZSH_THEME_GIT_PROMPT_UNTRACKED= + # nvm_prompt_info variables + unset -m 'ZSH_THEME_NVM_PROMPT_*' + #ZSH_THEME_NVM_PROMPT_PREFIX= + #ZSH_THEME_NVM_PROMPT_SUFFIX= + # rvm_prompt_info variables + unset -m 'ZSH_THEME_RVM_PROMPT_*' + #ZSH_THEME_RVM_PROMPT_PREFIX= + #ZSH_THEME_RVM_PROMPT_SUFFIX= + #ZSH_THEME_RVM_PROMPT_OPTIONS= + # svn_prompt_info variables + unset -m 'ZSH_THEME_SVN_PROMPT_*' + #ZSH_THEME_SVN_PROMPT_CLEAN + #ZSH_THEME_SVN_PROMPT_DIRTY + #ZSH_THEME_SVN_PROMPT_PREFIX + #ZSH_THEME_SVN_PROMPT_SUFFIX + + # Hook functions + if [[ -n $_OMZ_THEME_CHPWD_FUNCTIONS ]]; then + #echo Removing chpwd hooks: $_OMZ_THEME_CHPWD_FUNCTIONS + chpwd_functions=(${chpwd_functions:|_OMZ_THEME_CHPWD_FUNCTIONS}) + fi + if [[ -n $_OMZ_THEME_PRECMD_FUNCTIONS ]]; then + #echo Removing precmd hooks: $_OMZ_THEME_PRECMD_FUNCTIONS + precmd_functions=(${precmd_functions:|_OMZ_THEME_PRECMD_FUNCTIONS}) + fi + if [[ -n $_OMZ_THEME_PREEXEC_FUNCTIONS ]]; then + #echo Removing preexec hooks: $_OMZ_THEME_PREEXEC_FUNCTIONS + preexec_functions=(${preexec_functions:|_OMZ_THEME_PREEXEC_FUNCTIONS}) + fi + +} + + # List available themes by name # # The list will always be in sorted order, so you can index in to it. -function lstheme(){ +function lstheme() { local themes x theme_dir themes=() for theme_dir ($ZSH_CUSTOM $ZSH_CUSTOM/themes $ZSH/themes); do @@ -52,4 +216,6 @@ function lstheme(){ # List themes defined in a given dir function _omz_lstheme_dir() { ls $1 | grep '.zsh-theme$' | sed 's,\.zsh-theme$,,' -} \ No newline at end of file +} + + From ae27b672e9bac15f9d1d4d03923580fdd426838a Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Tue, 31 Mar 2015 05:06:47 -0400 Subject: [PATCH 7/8] themes: add indirection to make "local" work in theme definitions --- plugins/themes/themes.plugin.zsh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/themes/themes.plugin.zsh b/plugins/themes/themes.plugin.zsh index eb3ae6b0e..bc84f39e8 100644 --- a/plugins/themes/themes.plugin.zsh +++ b/plugins/themes/themes.plugin.zsh @@ -70,8 +70,8 @@ function _omz_load_theme_from_file() { values_before[$param]=${(P)param} done - # Actually load the theme - source $file + # Actually load the theme, using an indirection function + _omz_source_theme_file $file # Debugging stuff if [[ $ZSH_THEME_DEBUG == true ]]; then @@ -128,6 +128,14 @@ function _omz_load_theme_from_file() { fi } +# Sources the given file +# The only reason this function exists is to provide a layer of +# indirection so that the theme file runs in its own function call stack frame +# and "local" statements in the theme definitions work as intended. +function _omz_source_theme_file() { + source $1 +} + # Resets all theme settings to their default state # (To the extent that we know what themes do, that is.) # This will reset all variables used by the core OMZ *_prompt_info functions. From f2a8eb33ad31ffa1ded299837040176433978124 Mon Sep 17 00:00:00 2001 From: Andrew Janke Date: Tue, 31 Mar 2015 05:48:30 -0400 Subject: [PATCH 8/8] Reset all prompt levels when resetting theme. Ignore aliases for PROMPT* variables. --- plugins/themes/themes.plugin.zsh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/themes/themes.plugin.zsh b/plugins/themes/themes.plugin.zsh index bc84f39e8..6cdf23e69 100644 --- a/plugins/themes/themes.plugin.zsh +++ b/plugins/themes/themes.plugin.zsh @@ -79,7 +79,7 @@ function _omz_load_theme_from_file() { params_added=(${params_after:|params_before}) ignore_params=(LINENO RANDOM _ parameters prompt values_before modules \ params_added ignore_params params_before params_after params_changed \ - SECONDS TTYIDLE) + SECONDS TTYIDLE PS1 PS2 PS3 PS4 RPS1 RPS2) params_before=(${params_before:|ignore_params}) local params_changed params_changed=() @@ -104,7 +104,7 @@ function _omz_load_theme_from_file() { if [[ -n $params_changed ]]; then printf '=== %s ===\n%s\n' "Theme changed parameters:" ${(F)params_changed} fi - if [[ -n "$_OMZ_THEME_CHPWD_FUNCTIONS$_OMZ_THEME_PRECMD_FUNCTIONS$_OMZ_THEME_PREEXEC_FUNCTIONS" ]]; then + if [[ -n "${_OMZ_THEME_CHPWD_FUNCTIONS}${_OMZ_THEME_PRECMD_FUNCTIONS}${_OMZ_THEME_PREEXEC_FUNCTIONS}" ]]; then printf '=== %s ===\n' "Theme added hooks:" if [[ -n $_OMZ_THEME_CHPWD_FUNCTIONS ]]; then echo "Theme added chpwd hooks: $_OMZ_THEME_CHPWD_FUNCTIONS" @@ -142,7 +142,12 @@ function _omz_source_theme_file() { # It will also remove any hook functions installed by the current theme, if it # was loaded by the theme() function function _omz_reset_theme() { + # Prompts PROMPT="%n@%m:%~%# " + PROMPT2='%_> ' + PROMPT3='?# ' + PROMPT4='+%N:%i> ' + unset RPROMPT RPROMPT2 # This assumes that all ZSH_THEME__* variables are owned by # OMZ theming, and can be reset en masse