diff --git a/lib/theme-and-appearance.zsh b/lib/theme-and-appearance.zsh index c36a5147d..65bc205f7 100644 --- a/lib/theme-and-appearance.zsh +++ b/lib/theme-and-appearance.zsh @@ -45,6 +45,13 @@ else SCREEN_NO="" fi +# Theme and appearance +# +# Support for OMZ theming. +# +# This provides two public (user-facing) functions, theme() and lstheme(), for working +# with themes interactively. + # OMZ themes use promptsubst, so make sure it's on setopt prompt_subst @@ -64,6 +71,7 @@ _OMZ_DEBUG_BLACKLISTED_THEMES=(agnoster dstufft dogenpunk fino fino-time half-li # theme random - load a random theme # theme - load a theme by index (where is an integer) # theme next - load the next theme in the list of defined themes +# theme off - unload theme and return to zsh appearance defaults # # If no argument is given, `theme random` is the default behavior. # @@ -96,12 +104,35 @@ function theme() { elif [[ $1 =~ '^[0-9]+$' ]]; then # Select theme by index _omz_theme_n $1 + elif [[ $1 == "off" ]]; then + # Turn theming off + _omz_unload_theme else # Main case: load named theme _omz_load_theme $1 fi } +# List available themes by name +# +# The list will always be in sorted order, so you can index in to it. +# Themes in the "blacklist" are still included in lstheme, because they're +# still eligible for direct reference by explicit name or index, and that +# keeps the order stable. +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 + themes=(${(ou)themes}) + echo ${(F)themes} +} + + + function _omz_load_theme() { local name=$1 local theme_dir found @@ -121,18 +152,17 @@ function _omz_load_theme() { # Loads a theme by index # -# Usage: -# themen - advance to the next theme -# themen next - advance to the next theme -# themen - load theme number +# _omz_theme_n - loads theme at given index +# _omz_theme_n next - loads the next theme from the list of defined themes # # Loads a theme selected by index into list of defined themes, instead of by # name. This is to make it easy to cycle through all the themes for debugging # or browsing purposes. # # If called without an argument, it just advances to the next theme in the list +# after the currently loaded theme. # -# `themen next` will ignore themes in the ZSH_BLACKLISTED_THEMES variable. +# `_omz_theme_n next` will ignore themes in the ZSH_BLACKLISTED_THEMES parameter. function _omz_theme_n() { # Numeric index argument: select theme by index local themes n name n_themes blacklist @@ -147,6 +177,9 @@ function _omz_theme_n() { # from themes list to keep indexes stable blacklist=($(_omz_theme_blacklist)) while [[ ${blacklist[(i)${themes[n]}]} -le ${#blacklist} ]]; do + if [[ $ZSH_THEME_DEBUG == 'true' ]]; then + echo "[oh-my-zsh]: Skipping blacklisted theme ${themes[n]}" + fi (( n = n % n_themes + 1 )) done else @@ -172,10 +205,9 @@ function _omz_theme_n() { # This operates by "reference", so caller should pass in names of the input # parameters, not their values. # -# Implementation note: the input variables may not be named "omz_asd_a", "omz_asd_b", -# or "omz_asd_out_name". -# due to dynamic scoping conflicts. And you cannot use the numeric parameters ($1, $2, etc) -# as inputs. +# Implementation note: the input variables may not be named "_omz_asd_a", "_omz_asd_b", +# or "_omz_asd_out_name", due to dynamic scoping conflicts. And you cannot use the +# numeric parameters ($1, $2, etc) as inputs. # # Example: # @@ -186,18 +218,18 @@ function _omz_theme_n() { # After the function call, $c will contain (foo baz). # function _omz_array_setdiff() { - local omz_asd_a omz_asd_b omz_asd_out_name - omz_asd_out_name=$1 - omz_asd_a=(${(P)2}) - omz_asd_b=(${(P)3}) + local _omz_asd_a _omz_asd_b _omz_asd_out_name + _omz_asd_out_name=$1 + _omz_asd_a=(${(P)2}) + _omz_asd_b=(${(P)3}) local my_out item my_out=() - for item (${omz_asd_a}); do - if [[ ${omz_asd_b[(i)$item]} -gt ${#omz_asd_b} ]]; then + for item (${_omz_asd_a}); do + if [[ ${_omz_asd_b[(i)$item]} -gt ${#_omz_asd_b} ]]; then my_out+=($item) fi done - set -A $omz_asd_out_name $my_out + set -A $_omz_asd_out_name $my_out } @@ -314,26 +346,61 @@ 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. -# 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 +# Unloads the OMZ theme from this session, by unsetting theme-related +# parameters, removing installed hook functions, and restoring prompt parameters +# to their default ZSH values +function _omz_unload_theme() { + # Unload hook functions + if [[ -n $_OMZ_THEME_CHPWD_FUNCTIONS ]]; then + #echo Removing chpwd hooks: $_OMZ_THEME_CHPWD_FUNCTIONS + _omz_array_setdiff chpwd_functions chpwd_functions _OMZ_THEME_CHPWD_FUNCTIONS + fi + if [[ -n $_OMZ_THEME_PRECMD_FUNCTIONS ]]; then + #echo Removing precmd hooks: $_OMZ_THEME_PRECMD_FUNCTIONS + _omz_array_setdiff precmd_functions precmd_functions _OMZ_THEME_PRECMD_FUNCTIONS + fi + if [[ -n $_OMZ_THEME_PREEXEC_FUNCTIONS ]]; then + #echo Removing preexec hooks: $_OMZ_THEME_PREEXEC_FUNCTIONS + _omz_array_setdiff preexec_functions preexec_functions _OMZ_THEME_PREEXEC_FUNCTIONS + fi # 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_*' + unset -m 'ZSH_THEME_NVM_PROMPT_*' + unset -m 'ZSH_THEME_RVM_PROMPT_*' + unset -m 'ZSH_THEME_SVN_PROMPT_*' + + # Reset prompts to default ZSH values (values found in ZSH reference manual) + PROMPT='%m%# ' + PROMPT2='%_> ' + PROMPT3='?# ' + PROMPT4='+%N:%i> ' + SPROMPT="zsh: correct '%R' to '%r' [nyae]?" + unset RPROMPT RPROMPT2 + + unset ZSH_THEME +} + +# Resets all theme settings to their OMZ 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() { + _omz_unload_theme + _omz_apply_theme_defaults +} + +# Adds OMZ default values that differ from ZSH defaults +function _omz_apply_theme_defaults() { + # Prompts + PROMPT="%n@%m:%~%# " + + # git_prompt_info variables 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_COMMITS_AHEAD_PREFIX= @@ -356,59 +423,20 @@ function _omz_reset_theme() { #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}) - _omz_array_setdiff 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}) - _omz_array_setdiff 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}) - _omz_array_setdiff 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. -# Themes in the "blacklist" are still included in lstheme, because they're -# still eligible for direct reference by explicit name or index, and that -# keeps the order stable. -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 - themes=(${(ou)themes}) - echo ${(F)themes} -} - # List themes defined in a given dir function _omz_lstheme_dir() { ls $1 | grep '.zsh-theme$' | sed 's,\.zsh-theme$,,' @@ -460,3 +488,40 @@ function _omz_theme_show_prompt_key { done } +# 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} +# These themes are known to interact badly with our debugging support +_OMZ_DEBUG_BLACKLISTED_THEMES=(agnoster dstufft dogenpunk fino fino-time half-life \ + kolo peepcode smt steeef suvash zhann) + +# Configure and enable ls colors +autoload -U colors && colors +export LSCOLORS="Gxfxcxdxbxegedabagacad" +if [[ $DISABLE_LS_COLORS != "true" ]]; then + # Find the option for using colors in ls, depending on the version: Linux or BSD + if [[ "$(uname -s)" == "NetBSD" ]]; then + # On NetBSD, test if "gls" (GNU ls) is installed (this one supports colors); + # otherwise, leave ls as is, because NetBSD's ls doesn't support -G + gls --color -d . &>/dev/null 2>&1 && alias ls='gls --color=tty' + elif [[ "$(uname -s)" == "OpenBSD" ]]; then + # On OpenBSD, test if "colorls" is installed (this one supports colors); + # otherwise, leave ls as is, because OpenBSD's ls doesn't support -G + colorls -G -d . &>/dev/null 2>&1 && alias ls='colorls -G' + else + ls --color -d . &>/dev/null 2>&1 && alias ls='ls --color=tty' || alias ls='ls -G' + fi +fi + +if [[ -n $WINDOW ]]; then + SCREEN_NO="%B$WINDOW%b " +else + SCREEN_NO="" +fi + +# OMZ themes use promptsubst, so make sure it's on +setopt prompt_subst + +# Apply theming defaults, regardless of whether a specific theme is loaded +_omz_apply_theme_defaults