diff options
-rw-r--r-- | config/p10k-classic.zsh | 10 | ||||
-rw-r--r-- | config/p10k-lean-8colors.zsh | 10 | ||||
-rw-r--r-- | config/p10k-lean.zsh | 10 | ||||
-rw-r--r-- | config/p10k-rainbow.zsh | 11 | ||||
-rw-r--r-- | internal/p10k.zsh | 1229 | ||||
-rw-r--r-- | internal/worker.zsh | 258 | ||||
-rw-r--r-- | notes.txt | 10 | ||||
-rw-r--r-- | powerlevel10k.zsh-theme | 2 |
8 files changed, 1114 insertions, 426 deletions
diff --git a/config/p10k-classic.zsh b/config/p10k-classic.zsh index 8406f291..1e966cbf 100644 --- a/config/p10k-classic.zsh +++ b/config/p10k-classic.zsh @@ -80,9 +80,10 @@ midnight_commander # midnight commander shell (https://midnight-commander.org/) vi_mode # vi mode (you don't need this if you've enabled prompt_char) # vpn_ip # virtual private network indicator + # load # CPU load # disk_usage # disk usage # ram # free RAM - # load # CPU load + # swap # used swap todo # todo items (https://github.com/todotxt/todo.txt-cli) # time # current time # =========================[ Line #2 ]========================= @@ -584,6 +585,12 @@ # Custom icon. # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + #####################################[ swap: used swap ]###################################### + # Swap color. + typeset -g POWERLEVEL9K_SWAP_FOREGROUND=96 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + ######################################[ load: CPU load ]###################################### # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. typeset -g POWERLEVEL9K_LOAD_WHICH=5 @@ -1023,6 +1030,7 @@ # VPN IP color. typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=81 # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= # Regular expression for the VPN network interface. Run ifconfig while on VPN to see the # name of the interface. diff --git a/config/p10k-lean-8colors.zsh b/config/p10k-lean-8colors.zsh index 43cd7a42..04ac7e90 100644 --- a/config/p10k-lean-8colors.zsh +++ b/config/p10k-lean-8colors.zsh @@ -79,9 +79,10 @@ vim_shell # vim shell indicator (:sh) midnight_commander # midnight commander shell (https://midnight-commander.org/) # vpn_ip # virtual private network indicator + # load # CPU load # disk_usage # disk usage # ram # free RAM - # load # CPU load + # swap # used swap todo # todo items (https://github.com/todotxt/todo.txt-cli) # time # current time # =========================[ Line #2 ]========================= @@ -563,6 +564,12 @@ # Custom icon. # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + #####################################[ swap: used swap ]###################################### + # Swap color. + typeset -g POWERLEVEL9K_SWAP_FOREGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + ######################################[ load: CPU load ]###################################### # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. typeset -g POWERLEVEL9K_LOAD_WHICH=5 @@ -1002,6 +1009,7 @@ # VPN IP color. typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=3 # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= # Regular expression for the VPN network interface. Run ifconfig while on VPN to see the # name of the interface. diff --git a/config/p10k-lean.zsh b/config/p10k-lean.zsh index 02e420c2..a7c3e369 100644 --- a/config/p10k-lean.zsh +++ b/config/p10k-lean.zsh @@ -79,9 +79,10 @@ vim_shell # vim shell indicator (:sh) midnight_commander # midnight commander shell (https://midnight-commander.org/) # vpn_ip # virtual private network indicator + # load # CPU load # disk_usage # disk usage # ram # free RAM - # load # CPU load + # swap # used swap todo # todo items (https://github.com/todotxt/todo.txt-cli) # time # current time # =========================[ Line #2 ]========================= @@ -563,6 +564,12 @@ # Custom icon. # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + #####################################[ swap: used swap ]###################################### + # Swap color. + typeset -g POWERLEVEL9K_SWAP_FOREGROUND=96 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + ######################################[ load: CPU load ]###################################### # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. typeset -g POWERLEVEL9K_LOAD_WHICH=5 @@ -1002,6 +1009,7 @@ # VPN IP color. typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=81 # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= # Regular expression for the VPN network interface. Run ifconfig while on VPN to see the # name of the interface. diff --git a/config/p10k-rainbow.zsh b/config/p10k-rainbow.zsh index 7b2ee6ba..18725ae0 100644 --- a/config/p10k-rainbow.zsh +++ b/config/p10k-rainbow.zsh @@ -80,9 +80,10 @@ midnight_commander # midnight commander shell (https://midnight-commander.org/) vi_mode # vi mode (you don't need this if you've enabled prompt_char) # vpn_ip # virtual private network indicator + # load # CPU load # disk_usage # disk usage # ram # free RAM - # load # CPU load + # swap # used swap todo # todo items (https://github.com/todotxt/todo.txt-cli) # time # current time # =========================[ Line #2 ]========================= @@ -589,6 +590,13 @@ # Custom icon. # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + #####################################[ swap: used swap ]###################################### + # Swap color. + # typeset -g POWERLEVEL9K_SWAP_FOREGROUND=0 + # typeset -g POWERLEVEL9K_SWAP_BACKGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + ######################################[ load: CPU load ]###################################### # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. typeset -g POWERLEVEL9K_LOAD_WHICH=5 @@ -1061,6 +1069,7 @@ # typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=0 # typeset -g POWERLEVEL9K_VPN_IP_BACKGROUND=6 # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= # Regular expression for the VPN network interface. Run ifconfig while on VPN to see the # name of the interface. diff --git a/internal/p10k.zsh b/internal/p10k.zsh index 2fe7fb50..1da83dc8 100644 --- a/internal/p10k.zsh +++ b/internal/p10k.zsh @@ -28,6 +28,7 @@ if ! autoload -Uz is-at-least || ! is-at-least 5.1; then fi source "${__p9k_root_dir}/internal/configure.zsh" +source "${__p9k_root_dir}/internal/worker.zsh" # For compatibility with Powerlevel9k. It's not recommended to use mnemonic color # names in the configuration except for colors 0-7 as these are standard. @@ -206,7 +207,7 @@ function _p9k_prompt_length() { _p9k_ret=$x } -typeset -gr __p9k_byte_suffix=('B' 'K' 'M' 'G' 'T' 'P' 'E' 'Z' 'Y') +typeset -g __p9k_byte_suffix=('B' 'K' 'M' 'G' 'T' 'P' 'E' 'Z' 'Y') # 42 => 42B # 1536 => 1.5K @@ -230,17 +231,6 @@ _p9k_segment_in_use() { $_POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS[(I)$1(|_joined)] )) } -function _p9k_parse_ip() { - local iface_regex="^(${1:-.*})\$" iface ip - for iface ip in "${(@kv)_p9k_iface}"; do - if [[ $iface =~ $iface_regex ]]; then - _p9k_ret=$ip - return 0 - fi - done - return 1 -} - # Caching allows storing array-to-array associations. It should be used like this: # # if ! _p9k_cache_get "$key1" "$key2"; then @@ -973,6 +963,10 @@ prompt_anaconda() { _p9k_prompt_segment "$0" "blue" "$_p9k_color1" 'PYTHON_ICON' 0 '' "$msg" } +_p9k_prompt_anaconda_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${CONDA_PREFIX:-$CONDA_ENV_PATH}' +} + ################################################################ # AWS Profile prompt_aws() { @@ -985,17 +979,20 @@ prompt_aws() { break fi done - _p9k_prompt_segment "$0$state" red white 'AWS_ICON' 0 '' "${aws_profile//\%/%%}" fi } +_p9k_prompt_aws_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${AWS_VAULT:-${AWSUME_PROFILE:-${AWS_PROFILE:-$AWS_DEFAULT_PROFILE}}}' +} + ################################################################ # Current Elastic Beanstalk environment prompt_aws_eb_env() { (( $+commands[eb] )) || return - local dir=$_p9k_pwd + local dir=$_p9k__pwd while true; do [[ $dir == / ]] && return [[ -d $dir/.elasticbeanstalk ]] && break @@ -1012,9 +1009,14 @@ prompt_aws_eb_env() { _p9k_prompt_segment "$0" black green 'AWS_EB_ICON' 0 '' "${_p9k_cache_val[1]//\%/%%}" } +_p9k_prompt_aws_eb_env_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[eb]' +} + ################################################################ # Segment to indicate background jobs with an icon. prompt_background_jobs() { + local -i len=$#_p9k__prompt local msg if (( _POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE )); then if (( _POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE_ALWAYS )); then @@ -1024,29 +1026,59 @@ prompt_background_jobs() { fi fi _p9k_prompt_segment $0 "$_p9k_color1" cyan BACKGROUND_JOBS_ICON 1 '${${(%):-%j}:#0}' "$msg" + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } ################################################################ # Segment that indicates usage level of current partition. prompt_disk_usage() { + local -i len=$#_p9k__prompt + _p9k_prompt_segment $0_CRITICAL red white DISK_ICON 1 '$_p9k__disk_usage_critical' '$_p9k__disk_usage_pct%%' + _p9k_prompt_segment $0_WARNING yellow $_p9k_color1 DISK_ICON 1 '$_p9k__disk_usage_warning' '$_p9k__disk_usage_pct%%' + if (( ! _POWERLEVEL9K_DISK_USAGE_ONLY_WARNING )); then + _p9k_prompt_segment $0_NORMAL $_p9k_color1 yellow DISK_ICON 1 '$_p9k__disk_usage_normal' '$_p9k__disk_usage_pct%%' + fi + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_disk_usage_init() { + typeset -g _p9k__disk_usage_pct= + typeset -g _p9k__disk_usage_normal= + typeset -g _p9k__disk_usage_warning= + typeset -g _p9k__disk_usage_critical= + _p9k__async_segments_compute+='_p9k_prompt_disk_usage_compute ${(q)_p9k__pwd_a}' +} + +_p9k_prompt_disk_usage_compute() { (( $+commands[df] )) || return - local disk_usage=${${=${(f)"$(df -P . 2>/dev/null)"}[2]}[5]%%%} - local state bg fg - if (( disk_usage >= _POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL )); then - state=CRITICAL - bg=red - fg=white - elif (( disk_usage >= _POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL )); then - state=WARNING - bg=yellow - fg=$_p9k_color1 - else - (( _POWERLEVEL9K_DISK_USAGE_ONLY_WARNING )) && return - state=NORMAL - bg=$_p9k_color1 - fg=yellow + _p9k_worker_async "_p9k_prompt_disk_usage_async ${(q)1}" _p9k_prompt_disk_usage_sync +} + +_p9k_prompt_disk_usage_async() { + local pct=${${=${(f)"$(df -P $1 2>/dev/null)"}[2]}[5]%%%} + [[ $pct == <0-100> && $pct != $_p9k__disk_usage_pct ]] || return + _p9k__disk_usage_pct=$pct + _p9k__disk_usage_normal= + _p9k__disk_usage_warning= + _p9k__disk_usage_critical= + if (( _p9k__disk_usage_pct >= _POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL )); then + _p9k__disk_usage_critical=1 + elif (( _p9k__disk_usage_pct >= _POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL )); then + _p9k__disk_usage_warning=1 + elif (( ! _POWERLEVEL9K_DISK_USAGE_ONLY_WARNING )); then + _p9k__disk_usage_normal=1 fi - _p9k_prompt_segment $0_$state $bg $fg DISK_ICON 0 '' "$disk_usage%%" + typeset -p \ + _p9k__disk_usage_pct \ + _p9k__disk_usage_normal \ + _p9k__disk_usage_warning \ + _p9k__disk_usage_critical + echo -E - 'reset=1' +} + +_p9k_prompt_disk_usage_sync() { + eval $REPLY + _p9k_worker_reply $REPLY } function _p9k_read_file() { @@ -1057,7 +1089,7 @@ function _p9k_read_file() { prompt_fvm() { (( $+commands[fvm] )) || return - local dir=$_p9k_pwd_a + local dir=$_p9k__pwd_a while [[ $dir != / ]]; do local link=$dir/fvm if [[ -L $link ]]; then @@ -1070,9 +1102,48 @@ prompt_fvm() { done } +_p9k_prompt_fvm_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[fvm]' +} + ################################################################ # Segment that displays the battery status in levels and colors prompt_battery() { + [[ $_p9k_os == (Linux|Android) ]] && _p9k_prompt_battery_set_args + (( $#_p9k__battery_args )) && _p9k_prompt_segment "${_p9k__battery_args[@]}" +} + +_p9k_prompt_battery_init() { + typeset -ga _p9k__battery_args=() + if [[ $_p9k_os == OSX && $+commands[pmset] == 1 ]]; then + _p9k__async_segments_compute+=_p9k_prompt_battery_compute + return + fi + if [[ $_p9k_os != (Linux|Android) || -z /sys/class/power_supply/(BAT*|battery)/(#qFN) ]]; then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' + fi +} + +_p9k_prompt_battery_compute() { + _p9k_worker_async _p9k_prompt_battery_async _p9k_prompt_battery_sync +} + +_p9k_prompt_battery_async() { + local prev="${(pj:\0:)_p9k__battery_args}" + _p9k_prompt_battery_set_args + [[ "${(pj:\0:)_p9k__battery_args}" == $prev ]] && return 1 + typeset -p _p9k__battery_args + echo -E - 'reset=2' +} + +_p9k_prompt_battery_sync() { + eval $REPLY + _p9k_worker_reply $REPLY +} + +_p9k_prompt_battery_set_args() { + _p9k__battery_args=() + local state remain local -i bat_percent @@ -1187,102 +1258,182 @@ prompt_battery() { fg=$_POWERLEVEL9K_BATTERY_LEVEL_FOREGROUND[idx] fi - _p9k_prompt_segment $0_$state "$bg" "$fg" $icon 0 '' $msg + _p9k__battery_args=(prompt_battery_$state "$bg" "$fg" $icon 0 '' $msg) } ################################################################ # Public IP segment prompt_public_ip() { - local icon='PUBLIC_IP_ICON' + local -i len=$#_p9k__prompt + local ip='${_p9k__public_ip:-$_POWERLEVEL9K_PUBLIC_IP_NONE}' if [[ -n $_POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE ]]; then - _p9k_parse_ip $_POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE && icon='VPN_ICON' + _p9k_prompt_segment "$0" "$_p9k_color1" "$_p9k_color2" PUBLIC_IP_ICON 1 '${_p9k__public_ip_not_vpn:+'$ip'}' $ip + _p9k_prompt_segment "$0" "$_p9k_color1" "$_p9k_color2" VPN_ICON 1 '${_p9k__public_ip_vpn:+'$ip'}' $ip + else + _p9k_prompt_segment "$0" "$_p9k_color1" "$_p9k_color2" PUBLIC_IP_ICON 1 $ip $ip fi + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} - local ip='${_p9k__public_ip:-$_POWERLEVEL9K_PUBLIC_IP_NONE}' - _p9k_prompt_segment "$0" "$_p9k_color1" "$_p9k_color2" "$icon" 1 $ip $ip +_p9k_prompt_public_ip_init() { + typeset -g _p9k__public_ip= + typeset -gF _p9k__public_ip_next_time=0 + _p9k__async_segments_compute+=_p9k_prompt_public_ip_compute +} + +_p9k_prompt_public_ip_compute() { + (( EPOCHREALTIME >= _p9k__public_ip_next_time )) || return + _p9k_worker_async _p9k_prompt_public_ip_async _p9k_prompt_public_ip_sync +} + +_p9k_prompt_public_ip_async() { + local ip method + local -F start=EPOCHREALTIME + local -F next='start + 5' + for method in $_POWERLEVEL9K_PUBLIC_IP_METHODS $_POWERLEVEL9K_PUBLIC_IP_METHODS; do + case $method in + dig) + if (( $+commands[dig] )); then + ip="$(dig +tries=1 +short -4 A myip.opendns.com @resolver1.opendns.com 2>/dev/null)" + [[ $ip == ';'* ]] && ip= + if [[ -z $ip ]]; then + ip="$(dig +tries=1 +short -6 AAAA myip.opendns.com @resolver1.opendns.com 2>/dev/null)" + [[ $ip == ';'* ]] && ip= + fi + fi + ;; + curl) + if (( $+commands[curl] )); then + ip="$(curl --max-time 5 -w '\n' "$ip_url" 2>/dev/null)" + fi + ;; + wget) + if (( $+commands[wget] )); then + ip="$(wget -T 5 -qO- "$ip_url" 2>/dev/null)" + fi + ;; + esac + [[ $ip =~ '^[0-9a-f.:]+$' ]] || ip='' + if [[ -n $ip ]]; then + next=$((start + _POWERLEVEL9K_PUBLIC_IP_TIMEOUT)) + break + fi + done + _p9k__public_ip_next_time=$next + typeset -p _p9k__public_ip_next_time + [[ $_p9k__public_ip == $ip ]] && return + _p9k__public_ip=$ip + typeset -p _p9k__public_ip + echo -E - 'reset=1' +} + +_p9k_prompt_public_ip_sync() { + eval $REPLY + _p9k_worker_reply $REPLY } ################################################################ # Context: user@hostname (who am I and where am I) prompt_context() { - if ! _p9k_cache_get $0 "${(%):-%#}"; then - local -i enabled=1 - local content - if [[ $_POWERLEVEL9K_ALWAYS_SHOW_CONTEXT == 0 && -n $DEFAULT_USER && $P9K_SSH == 0 ]]; then - local user="${(%):-%n}" - if [[ $user == $DEFAULT_USER ]]; then - if (( _POWERLEVEL9K_ALWAYS_SHOW_USER )); then - content="${user//\%/%%}" - else - enabled=0 - fi - fi + local -i len=$#_p9k__prompt + + local content + if [[ $_POWERLEVEL9K_ALWAYS_SHOW_CONTEXT == 0 && -n $DEFAULT_USER && $P9K_SSH == 0 ]]; then + local user="${(%):-%n}" + if [[ $user == $DEFAULT_USER ]]; then + content="${user//\%/%%}" fi + fi - local state - if (( enabled )); then - state="DEFAULT" - if [[ "${(%):-%#}" == '#' ]]; then - state="ROOT" - elif (( P9K_SSH )); then - if [[ -n "$SUDO_COMMAND" ]]; then - state="REMOTE_SUDO" - else - state="REMOTE" - fi - elif [[ -n "$SUDO_COMMAND" ]]; then - state="SUDO" - fi + local state + if (( P9K_SSH )); then + if [[ -n "$SUDO_COMMAND" ]]; then + state="REMOTE_SUDO" + else + state="REMOTE" + fi + elif [[ -n "$SUDO_COMMAND" ]]; then + state="SUDO" + else + state="DEFAULT" + fi - if [[ -z $content ]]; then - local var=_POWERLEVEL9K_CONTEXT_${state}_TEMPLATE - if (( $+parameters[$var] )); then - [[ -z $_p9k_locale ]] || local LC_ALL=$_p9k_locale - content=${(P)var} - content=${(g::)content} - else - content=$_POWERLEVEL9K_CONTEXT_TEMPLATE - fi + local cond + for state cond in $state '${${(%):-%#}:#\#}' ROOT '${${(%):-%#}:#\%}'; do + local text=$content + if [[ -z $text ]]; then + local var=_POWERLEVEL9K_CONTEXT_${state}_TEMPLATE + if (( $+parameters[$var] )); then + [[ -z $_p9k_locale ]] || local LC_ALL=$_p9k_locale + text=${(P)var} + text=${(g::)text} + else + text=$_POWERLEVEL9K_CONTEXT_TEMPLATE fi fi + _p9k_prompt_segment "$0_$state" "$_p9k_color1" yellow '' 0 "$cond" "$text" + done - _p9k_cache_set "$enabled" "$state" "$content" - fi + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} - (( _p9k_cache_val[1] )) || return - _p9k_prompt_segment "$0_$_p9k_cache_val[2]" "$_p9k_color1" yellow '' 0 '' "$_p9k_cache_val[3]" +instant_prompt_context() { + if [[ $_POWERLEVEL9K_ALWAYS_SHOW_CONTEXT == 0 && -n $DEFAULT_USER && $P9K_SSH == 0 ]]; then + if [[ ${(%):-%n} == $DEFAULT_USER ]]; then + if (( ! _POWERLEVEL9K_ALWAYS_SHOW_USER )); then + return + fi + fi + fi + prompt_context } -instant_prompt_context() { prompt_context; } +_p9k_prompt_context_init() { + if [[ $_POWERLEVEL9K_ALWAYS_SHOW_CONTEXT == 0 && -n $DEFAULT_USER && $P9K_SSH == 0 ]]; then + if [[ ${(%):-%n} == $DEFAULT_USER ]]; then + if (( ! _POWERLEVEL9K_ALWAYS_SHOW_USER )); then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' + fi + fi + fi +} ################################################################ # User: user (who am I) prompt_user() { - if ! _p9k_cache_get $0 "${(%):-%#}"; then - local user="${(%):-%n}" - if [[ $_POWERLEVEL9K_ALWAYS_SHOW_USER == 0 && $user == $DEFAULT_USER ]]; then - _p9k_cache_set true - elif [[ "${(%):-%#}" == '#' ]]; then - _p9k_cache_set _p9k_prompt_segment "${0}_ROOT" "${_p9k_color1}" yellow ROOT_ICON 0 '' "$_POWERLEVEL9K_USER_TEMPLATE" - elif [[ -n "$SUDO_COMMAND" ]]; then - _p9k_cache_set _p9k_prompt_segment "${0}_SUDO" "${_p9k_color1}" yellow SUDO_ICON 0 '' "$_POWERLEVEL9K_USER_TEMPLATE" - else - _p9k_cache_set _p9k_prompt_segment "${0}_DEFAULT" "${_p9k_color1}" yellow USER_ICON 0 '' "${user//\%/%%}" - fi + local -i len=$#_p9k__prompt + _p9k_prompt_segment "${0}_ROOT" "${_p9k_color1}" yellow ROOT_ICON 0 '${${(%):-%#}:#\%}' "$_POWERLEVEL9K_USER_TEMPLATE" + if [[ -n "$SUDO_COMMAND" ]]; then + _p9k_prompt_segment "${0}_SUDO" "${_p9k_color1}" yellow SUDO_ICON 0 '${${(%):-%#}:#\#}' "$_POWERLEVEL9K_USER_TEMPLATE" + else + _p9k_prompt_segment "${0}_DEFAULT" "${_p9k_color1}" yellow USER_ICON 0 '${${(%):-%#}:#\#}' "%n" fi - "$_p9k_cache_val[@]" + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } -instant_prompt_user() { prompt_user; } +instant_prompt_user() { + if [[ $_POWERLEVEL9K_ALWAYS_SHOW_USER == 0 && "${(%):-%n}" == $DEFAULT_USER ]]; then + return + fi + prompt_user +} + +_p9k_prompt_user_init() { + if [[ $_POWERLEVEL9K_ALWAYS_SHOW_USER == 0 && "${(%):-%n}" == $DEFAULT_USER ]]; then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' + fi +} ################################################################ # Host: machine (where am I) prompt_host() { + local -i len=$#_p9k__prompt if (( P9K_SSH )); then _p9k_prompt_segment "$0_REMOTE" "${_p9k_color1}" yellow SSH_ICON 0 '' "$_POWERLEVEL9K_HOST_TEMPLATE" else _p9k_prompt_segment "$0_LOCAL" "${_p9k_color1}" yellow HOST_ICON 0 '' "$_POWERLEVEL9K_HOST_TEMPLATE" fi + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } instant_prompt_host() { prompt_host; } @@ -1353,10 +1504,10 @@ function _p9k_shorten_delim_len() { # Dir: current working directory prompt_dir() { if (( _POWERLEVEL9K_DIR_PATH_ABSOLUTE )); then - local p=$_p9k_pwd + local p=$_p9k__pwd local -a parts=("${(s:/:)p}") elif [[ -o auto_name_dirs ]]; then - local p=${_p9k_pwd/#(#b)$HOME(|\/*)/'~'$match[1]} + local p=${_p9k__pwd/#(#b)$HOME(|\/*)/'~'$match[1]} local -a parts=("${(s:/:)p}") else local p=${(%):-%~} @@ -1369,7 +1520,7 @@ prompt_dir() { local func='' local -a parts=() reply=() for func in zsh_directory_name $zsh_directory_name_functions; do - if (( $+functions[$func] )) && $func d $_p9k_pwd && [[ $p == '~['$reply[1]']'* ]]; then + if (( $+functions[$func] )) && $func d $_p9k__pwd && [[ $p == '~['$reply[1]']'* ]]; then parts+='~['$reply[1]']' break fi @@ -1377,7 +1528,7 @@ prompt_dir() { if (( $#parts )); then parts+=(${(s:/:)${p#$parts[1]}}) else - p=$_p9k_pwd + p=$_p9k__pwd parts=("${(s:/:)p}") fi else @@ -1418,7 +1569,7 @@ prompt_dir() { $+commands[jq] == 1 && $#_POWERLEVEL9K_DIR_PACKAGE_FILES > 0 ]] || return local pats="(${(j:|:)_POWERLEVEL9K_DIR_PACKAGE_FILES})" local -i i=$#parts - local dir=$_p9k_pwd + local dir=$_p9k__pwd for (( ; i > 0; --i )); do local markers=($dir/${~pats}(N)) if (( $#markers )); then @@ -1479,7 +1630,7 @@ prompt_dir() { elif [[ $p[1] == / ]]; then (( ++i )) fi - local parent="${_p9k_pwd%/${(pj./.)parts[i,-1]}}" + local parent="${_p9k__pwd%/${(pj./.)parts[i,-1]}}" if (( i <= e )); then local MATCH= mtimes=() zstat -A mtimes +mtime -- ${(@)${:-{$i..$e}}/(#m)*/$parent/${(pj./.)parts[i,$MATCH]}} 2>/dev/null || mtimes=() @@ -1487,7 +1638,7 @@ prompt_dir() { else local key='good' fi - if ! _p9k_cache_ephemeral_get $0 $e $i $_p9k_pwd || [[ $key != $_p9k_cache_val[1] ]] ; then + if ! _p9k_cache_ephemeral_get $0 $e $i $_p9k__pwd || [[ $key != $_p9k_cache_val[1] ]] ; then _p9k_prompt_length $delim local -i real_delim_len=_p9k_ret [[ -n $parts[i-1] ]] && parts[i-1]="\${(Q)\${:-${(qqq)${(q)parts[i-1]}}}}"$'\2' @@ -1562,7 +1713,7 @@ prompt_dir() { ;; truncate_with_folder_marker) if [[ -n $_POWERLEVEL9K_SHORTEN_FOLDER_MARKER ]]; then - local dir=$_p9k_pwd + local dir=$_p9k__pwd local -a m=() local -i i=$(($#parts - 1)) for (( ; i > 1; --i )); do @@ -1586,9 +1737,9 @@ prompt_dir() { ;; esac - [[ $_POWERLEVEL9K_DIR_SHOW_WRITABLE == 1 && ! -w $_p9k_pwd ]] + [[ $_POWERLEVEL9K_DIR_SHOW_WRITABLE == 1 && ! -w $_p9k__pwd ]] local w=$? - if ! _p9k_cache_ephemeral_get $0 $_p9k_pwd $p $w $fake_first "${parts[@]}"; then + if ! _p9k_cache_ephemeral_get $0 $_p9k__pwd $p $w $fake_first "${parts[@]}"; then local state=$0 local icon='' if (( ! w )); then @@ -1597,7 +1748,7 @@ prompt_dir() { else local a='' b='' c='' for a b c in "${_POWERLEVEL9K_DIR_CLASSES[@]}"; do - if [[ $_p9k_pwd == ${~a} ]]; then + if [[ $_p9k__pwd == ${~a} ]]; then [[ -n $b ]] && state+=_${(U)b} icon=$'\1'$c break @@ -1685,7 +1836,7 @@ prompt_dir() { local content="${(pj.$sep.)parts}" if (( _POWERLEVEL9K_DIR_HYPERLINK )); then - local header=$'%{\e]8;;file://'${${_p9k_pwd//\%/%%25}//'#'/%%23}$'\a%}' + local header=$'%{\e]8;;file://'${${_p9k__pwd//\%/%%25}//'#'/%%23}$'\a%}' local footer=$'%{\e]8;;\a%}' if (( expand )); then _p9k_escape $header @@ -1722,6 +1873,10 @@ prompt_docker_machine() { fi } +_p9k_prompt_docker_machine_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$DOCKER_MACHINE_NAME' +} + ################################################################ # GO prompt prompt_go_version() { @@ -1738,8 +1893,8 @@ prompt_go_version() { p="$(go env GOPATH 2>/dev/null)" && [[ -n $p ]] || return fi fi - if [[ $_p9k_pwd/ != $p/* && $_p9k_pwd_a/ != $p/* ]]; then - local dir=$_p9k_pwd_a + if [[ $_p9k__pwd/ != $p/* && $_p9k__pwd_a/ != $p/* ]]; then + local dir=$_p9k__pwd_a while true; do [[ $dir == / ]] && return [[ -e $dir/go.mod ]] && break @@ -1750,10 +1905,16 @@ prompt_go_version() { _p9k_prompt_segment "$0" "green" "grey93" "GO_ICON" 0 '' "${v//\%/%%}" } +_p9k_prompt_go_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[go]' +} + ################################################################ # Command number (in local history) prompt_history() { + local -i len=$#_p9k__prompt _p9k_prompt_segment "$0" "grey50" "$_p9k_color1" '' 0 '' '%h' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } ################################################################ @@ -1769,18 +1930,24 @@ prompt_detect_virt() { fi } +_p9k_prompt_detect_virt_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[systemd-detect-virt]' +} + ################################################################ # Segment to display the current IP address prompt_ip() { - _p9k_parse_ip $_POWERLEVEL9K_IP_INTERFACE || return - _p9k_prompt_segment "$0" "cyan" "$_p9k_color1" 'NETWORK_ICON' 0 '' "${_p9k_ret//\%/%%}" + local -i len=$#_p9k__prompt + _p9k_prompt_segment "$0" "cyan" "$_p9k_color1" 'NETWORK_ICON' 1 '$_p9k__ip_ip' '$_p9k__ip_ip' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } ################################################################ # Segment to display if VPN is active prompt_vpn_ip() { - _p9k_parse_ip $_POWERLEVEL9K_VPN_IP_INTERFACE || return - _p9k_prompt_segment "$0" "cyan" "$_p9k_color1" 'VPN_ICON' 0 '' "${_p9k_ret//\%/%%}" + local -i len=$#_p9k__prompt + _p9k_prompt_segment "$0" "cyan" "$_p9k_color1" 'VPN_ICON' 1 '$_p9k__vpn_ip_ip' '$_p9k__vpn_ip_ip' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } ################################################################ @@ -1794,41 +1961,79 @@ prompt_laravel_version() { fi } +_p9k_prompt_laravel_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[php]' +} + ################################################################ # Segment to display load prompt_load() { - local bucket=2 - case $_POWERLEVEL9K_LOAD_WHICH in - 1) bucket=1;; - 5) bucket=2;; - 15) bucket=3;; - esac + if [[ $_p9k_os == (OSX|BSD) ]]; then + local -i len=$#_p9k__prompt + _p9k_prompt_segment $0_CRITICAL red "$_p9k_color1" LOAD_ICON 1 '$_p9k__load_critical' '$_p9k__load_value' + _p9k_prompt_segment $0_WARNING yellow "$_p9k_color1" LOAD_ICON 1 '$_p9k__load_warning' '$_p9k__load_value' + _p9k_prompt_segment $0_NORMAL green "$_p9k_color1" LOAD_ICON 1 '$_p9k__load_normal' '$_p9k__load_value' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] + return + fi + + [[ -r /proc/loadavg ]] || return + _p9k_read_file /proc/loadavg || return + local load=${${(A)=_p9k_ret}[_POWERLEVEL9K_LOAD_WHICH]//,/.} + local -F pct='100. * load / _p9k_num_cpus' + if (( pct > 70 )); then + _p9k_prompt_segment $0_CRITICAL red "$_p9k_color1" LOAD_ICON 0 '' $load + elif (( pct > 50 )); then + _p9k_prompt_segment $0_WARNING yellow "$_p9k_color1" LOAD_ICON 0 '' $load + else + _p9k_prompt_segment $0_NORMAL green "$_p9k_color1" LOAD_ICON 0 '' $load + fi +} - local load - case $_p9k_os in - OSX|BSD) - (( $+commands[sysctl] )) || return - load="$(sysctl -n vm.loadavg 2>/dev/null)" || return - load=${${(A)=load}[bucket+1]//,/.} - ;; - *) - [[ -r /proc/loadavg ]] || return - _p9k_read_file /proc/loadavg || return - load=${${(A)=_p9k_ret}[bucket]//,/.} - ;; - esac +_p9k_prompt_load_init() { + if [[ $_p9k_os == (OSX|BSD) ]]; then + typeset -g _p9k__load_value= + typeset -g _p9k__load_normal= + typeset -g _p9k__load_warning= + typeset -g _p9k__load_critical= + _p9k__async_segments_compute+=_p9k_prompt_load_compute + elif [[ ! -r /proc/loadavg ]]; then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' + fi +} - (( _p9k_num_cpus )) || return +_p9k_prompt_load_compute() { + (( $+commands[sysctl] )) || return + _p9k_worker_async _p9k_prompt_load_async _p9k_prompt_load_sync +} - if (( load > 0.7 * _p9k_num_cpus )); then - local state=CRITICAL bg=red - elif (( load > 0.5 * _p9k_num_cpus )); then - local state=WARNING bg=yellow +_p9k_prompt_load_async() { + local load="$(sysctl -n vm.loadavg 2>/dev/null)" || return + load=${${(A)=load}[_POWERLEVEL9K_LOAD_WHICH+1]//,/.} + [[ $load == <->(|.<->) && $load != $_p9k__load_value ]] || return + _p9k__load_value=$load + _p9k__load_normal= + _p9k__load_warning= + _p9k__load_critical= + local -F pct='100. * _p9k__load_value / _p9k_num_cpus' + if (( pct > 70 )); then + _p9k__load_critical=1 + elif (( pct > 50 )); then + _p9k__load_warning=1 else - local state=NORMAL bg=green + _p9k__load_normal=1 fi + typeset -p \ + _p9k__load_value \ + _p9k__load_normal \ + _p9k__load_warning \ + _p9k__load_critical + echo -E - 'reset=1' +} - _p9k_prompt_segment $0_$state $bg "$_p9k_color1" LOAD_ICON 0 '' $load +_p9k_prompt_load_sync() { + eval $REPLY + _p9k_worker_reply $REPLY } function _p9k_cached_cmd_stdout() { @@ -1863,7 +2068,7 @@ prompt_node_version() { (( $+commands[node] )) || return if (( _POWERLEVEL9K_NODE_VERSION_PROJECT_ONLY )); then - local dir=$_p9k_pwd + local dir=$_p9k__pwd while true; do [[ $dir == / ]] && return [[ -e $dir/package.json ]] && break @@ -1875,6 +2080,10 @@ prompt_node_version() { _p9k_prompt_segment "$0" "green" "white" 'NODE_ICON' 0 '' "${_p9k_ret#v}" } +_p9k_prompt_node_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[node]' +} + # Almost the same as `nvm_version default` but faster. The differences shouldn't affect # the observable behavior of Powerlevel10k. function _p9k_nvm_ls_default() { @@ -1982,6 +2191,10 @@ prompt_nvm() { _p9k_prompt_segment "$0" "magenta" "black" 'NODE_ICON' 0 '' "${${current#v}//\%/%%}" } +_p9k_prompt_nvm_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[nvm]:-${${+functions[nvm]}:#0}}' +} + ################################################################ # Segment to display NodeEnv prompt_nodeenv() { @@ -1994,6 +2207,10 @@ prompt_nodeenv() { _p9k_prompt_segment "$0" "black" "green" 'NODE_ICON' 0 '' "$msg" } +_p9k_prompt_nodeenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$NODE_VIRTUAL_ENV' +} + function _p9k_read_nodenv_version_file() { [[ -r $1 ]] || return local rest @@ -2022,7 +2239,7 @@ prompt_nodenv() { (( $+commands[nodenv] || $+functions[nodenv] )) || return _p9k_ret=$NODENV_VERSION if [[ -z $_p9k_ret ]]; then - [[ $NODENV_DIR == /* ]] && local dir=$NODENV_DIR || local dir="$_p9k_pwd_a/$NODENV_DIR" + [[ $NODENV_DIR == /* ]] && local dir=$NODENV_DIR || local dir="$_p9k__pwd_a/$NODENV_DIR" while [[ $dir != //[^/]# ]]; do _p9k_read_nodenv_version_file $dir/.node-version && break [[ $dir == / ]] && break @@ -2045,19 +2262,23 @@ prompt_nodenv() { _p9k_prompt_segment "$0" "black" "green" 'NODE_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_nodenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[nodenv]:-${${+functions[nodenv]}:#0}}' +} + prompt_dotnet_version() { (( $+commands[dotnet] )) || return if (( _POWERLEVEL9K_DOTNET_VERSION_PROJECT_ONLY )); then - case $_p9k_pwd in + case $_p9k__pwd in ~|/) return 0;; ~/*) local parent=~/ - local parts=(${(s./.)_p9k_pwd#$parent}) + local parts=(${(s./.)_p9k__pwd#$parent}) ;; *) local parent=/ - local parts=(${(s./.)_p9k_pwd}) + local parts=(${(s./.)_p9k__pwd}) ;; esac local MATCH @@ -2065,7 +2286,7 @@ prompt_dotnet_version() { local mtimes=() zstat -A mtimes +mtime -- $dirs 2>/dev/null || mtimes=() local key="${(pj.:.)mtimes}" - if ! _p9k_cache_ephemeral_get $0 $_p9k_pwd || [[ $key != $_p9k_cache_val[1] ]] ; then + if ! _p9k_cache_ephemeral_get $0 $_p9k__pwd || [[ $key != $_p9k_cache_val[1] ]] ; then local -i i found for i in {1..$#dirs}; do local dir=$dirs[i] mtime=$mtimes[i] @@ -2088,11 +2309,16 @@ prompt_dotnet_version() { _p9k_prompt_segment "$0" "magenta" "white" 'DOTNET_ICON' 0 '' "$_p9k_ret" } +_p9k_prompt_dotnet_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[dotnet]' +} ################################################################ # Segment to print a little OS icon prompt_os_icon() { + local -i len=$#_p9k__prompt _p9k_prompt_segment "$0" "black" "white" '' 0 '' "$_p9k_os_icon" + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } instant_prompt_os_icon() { prompt_os_icon; } @@ -2107,9 +2333,34 @@ prompt_php_version() { _p9k_prompt_segment "$0" "fuchsia" "grey93" '' 0 '' "${v//\%/%%}" } +_p9k_prompt_php_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[php]' +} + ################################################################ # Segment to display free RAM and used Swap prompt_ram() { + local -i len=$#_p9k__prompt + _p9k_prompt_segment $0 yellow "$_p9k_color1" RAM_ICON 1 '$_p9k__ram_free' '$_p9k__ram_free' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +function _p9k_prompt_ram_init() { + if [[ $_p9k_os == OSX && $+commands[vm_stat] == 0 || + $_p9k_os == BSD && ! -r /var/run/dmesg.boot || + $_p9k_os != (OSX|BSD) && ! -r /proc/meminfo ]]; then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' + return + fi + typeset -g _p9k__ram_free= + _p9k__async_segments_compute+=_p9k_prompt_ram_compute +} + +_p9k_prompt_ram_compute() { + _p9k_worker_async _p9k_prompt_ram_async _p9k_prompt_ram_sync +} + +_p9k_prompt_ram_async() { local -F free_bytes case $_p9k_os in @@ -2117,9 +2368,9 @@ prompt_ram() { (( $+commands[vm_stat] )) || return local stat && stat="$(vm_stat 2>/dev/null)" || return [[ $stat =~ 'Pages free:[[:space:]]+([0-9]+)' ]] || return - (( free_bytes+=match[1] )) + (( free_bytes += match[1] )) [[ $stat =~ 'Pages inactive:[[:space:]]+([0-9]+)' ]] || return - (( free_bytes+=match[1] )) + (( free_bytes += match[1] )) (( free_bytes *= 4096 )) ;; BSD) @@ -2129,13 +2380,21 @@ prompt_ram() { *) [[ -r /proc/meminfo ]] || return local stat && stat="$(</proc/meminfo)" || return - [[ $stat == (#b)*'MemAvailable:'[[:space:]]#(<->)* ]] || return - free_bytes=$(( $match[1] * 1024 )) + [[ $stat == (#b)*(MemAvailable:|MemFree:)[[:space:]]#(<->)* ]] || return + free_bytes=$(( $match[2] * 1024 )) ;; esac _p9k_human_readable_bytes $free_bytes - _p9k_prompt_segment $0 yellow "$_p9k_color1" RAM_ICON 0 '' $_p9k_ret + [[ $_p9k_ret != $_p9k__ram_free ]] || return + _p9k__ram_free=$_p9k_ret + typeset -p _p9k__ram_free + echo -E - 'reset=1' +} + +_p9k_prompt_ram_sync() { + eval $REPLY + _p9k_worker_reply $REPLY } function _p9k_read_rbenv_version_file() { @@ -2159,7 +2418,7 @@ prompt_rbenv() { local v=$RBENV_VERSION else (( ${_POWERLEVEL9K_RBENV_SOURCES[(I)local|global]} )) || return - [[ $RBENV_DIR == /* ]] && local dir=$RBENV_DIR || local dir="$_p9k_pwd_a/$RBENV_DIR" + [[ $RBENV_DIR == /* ]] && local dir=$RBENV_DIR || local dir="$_p9k__pwd_a/$RBENV_DIR" while true; do if _p9k_read_rbenv_version_file $dir/.ruby-version; then (( ${_POWERLEVEL9K_RBENV_SOURCES[(I)local]} )) || return @@ -2185,6 +2444,10 @@ prompt_rbenv() { _p9k_prompt_segment "$0" "red" "$_p9k_color1" 'RUBY_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_rbenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[rbenv]:-${${+functions[rbenv]}:#0}}' +} + function _p9k_read_luaenv_version_file() { [[ -r $1 ]] || return local rest @@ -2206,7 +2469,7 @@ prompt_luaenv() { local v=$LUAENV_VERSION else (( ${_POWERLEVEL9K_LUAENV_SOURCES[(I)local|global]} )) || return - [[ $LUAENV_DIR == /* ]] && local dir=$LUAENV_DIR || local dir="$_p9k_pwd_a/$LUAENV_DIR" + [[ $LUAENV_DIR == /* ]] && local dir=$LUAENV_DIR || local dir="$_p9k__pwd_a/$LUAENV_DIR" while true; do if _p9k_read_luaenv_version_file $dir/.lua-version; then (( ${_POWERLEVEL9K_LUAENV_SOURCES[(I)local]} )) || return @@ -2232,6 +2495,10 @@ prompt_luaenv() { _p9k_prompt_segment "$0" blue "$_p9k_color1" 'LUA_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_luaenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[luaenv]:-${${+functions[luaenv]}:#0}}' +} + function _p9k_read_jenv_version_file() { [[ -r $1 ]] || return local rest @@ -2264,7 +2531,7 @@ prompt_plenv() { local v=$PLENV_VERSION else (( ${_POWERLEVEL9K_PLENV_SOURCES[(I)local|global]} )) || return - [[ $PLENV_DIR == /* ]] && local dir=$PLENV_DIR || local dir="$_p9k_pwd_a/$PLENV_DIR" + [[ $PLENV_DIR == /* ]] && local dir=$PLENV_DIR || local dir="$_p9k__pwd_a/$PLENV_DIR" while true; do if _p9k_read_plenv_version_file $dir/.perl-version; then (( ${_POWERLEVEL9K_PLENV_SOURCES[(I)local]} )) || return @@ -2290,6 +2557,10 @@ prompt_plenv() { _p9k_prompt_segment "$0" "blue" "$_p9k_color1" 'PERL_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_plenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[plenv]:-${${+functions[plenv]}:#0}}' +} + ################################################################ # Segment to display jenv information # https://github.com/jenv/jenv @@ -2300,7 +2571,7 @@ prompt_jenv() { local v=$JENV_VERSION else (( ${_POWERLEVEL9K_JENV_SOURCES[(I)local|global]} )) || return - [[ $JENV_DIR == /* ]] && local dir=$JENV_DIR || local dir="$_p9k_pwd_a/$JENV_DIR" + [[ $JENV_DIR == /* ]] && local dir=$JENV_DIR || local dir="$_p9k__pwd_a/$JENV_DIR" while true; do if _p9k_read_jenv_version_file $dir/.java-version; then (( ${_POWERLEVEL9K_JENV_SOURCES[(I)local]} )) || return @@ -2326,6 +2597,10 @@ prompt_jenv() { _p9k_prompt_segment "$0" white red 'JAVA_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_jenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[jenv]:-${${+functions[jenv]}:#0}}' +} + ################################################################ # Segment to display chruby information # see https://github.com/postmodern/chruby/issues/245 for chruby_auto issue with ZSH @@ -2337,10 +2612,16 @@ prompt_chruby() { _p9k_prompt_segment "$0" "red" "$_p9k_color1" 'RUBY_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_chruby_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$RUBY_ENGINE' +} + ################################################################ # Segment to print an icon if user is root. prompt_root_indicator() { - _p9k_prompt_segment "$0" "$_p9k_color1" "yellow" 'ROOT_ICON' 0 '${${(%):-%#}:#%}' '' + local -i len=$#_p9k__prompt + _p9k_prompt_segment "$0" "$_p9k_color1" "yellow" 'ROOT_ICON' 0 '${${(%):-%#}:#\%}' '' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } instant_prompt_root_indicator() { prompt_root_indicator; } @@ -2351,7 +2632,7 @@ prompt_rust_version() { unset P9K_RUST_VERSION (( $+commands[rustc] )) || return if (( _POWERLEVEL9K_RUST_VERSION_PROJECT_ONLY )); then - local dir=$_p9k_pwd_a + local dir=$_p9k__pwd_a while true; do [[ $dir == / ]] && return [[ -e $dir/Cargo.toml ]] && break @@ -2384,7 +2665,7 @@ prompt_rust_version() { _p9k_cache_stat_set ${keys:^vals} fi local -A overrides=($_p9k_cache_val) - local dir=$_p9k_pwd_a + local dir=$_p9k__pwd_a while true; do if (( $+overrides[$dir] )); then toolchain=$overrides[$dir] @@ -2407,6 +2688,10 @@ prompt_rust_version() { _p9k_prompt_segment "$0" "darkorange" "$_p9k_color1" 'RUST_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_rust_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[rustc]' +} + # RSpec test ratio prompt_rspec_stats() { if [[ -d app && -d spec ]]; then @@ -2429,15 +2714,30 @@ prompt_rvm() { _p9k_prompt_segment "$0" "240" "$_p9k_color1" 'RUBY_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_rvm_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[rvm-prompt]:-${${+functions[rvm-prompt]}:#0}}' +} + ################################################################ # Segment to display SSH icon when connected prompt_ssh() { - if (( P9K_SSH )); then - _p9k_prompt_segment "$0" "$_p9k_color1" "yellow" 'SSH_ICON' 0 '' '' + local -i len=$#_p9k__prompt + _p9k_prompt_segment "$0" "$_p9k_color1" "yellow" 'SSH_ICON' 0 '' '' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_ssh_init() { + if (( ! P9K_SSH )); then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' fi } -instant_prompt_ssh() { prompt_ssh; } +instant_prompt_ssh() { + if (( ! P9K_SSH )); then + return + fi + prompt_ssh +} ################################################################ # Status: When an error occur, return the error code, or a cross icon if option is set @@ -2488,6 +2788,7 @@ instant_prompt_status() { } prompt_prompt_char() { + local -i len=$#_p9k__prompt if (( __p9k_sh_glob )); then if (( _p9k__status )); then if (( _POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE )); then @@ -2529,6 +2830,7 @@ prompt_prompt_char() { _p9k_prompt_segment $0_OK_VIVIS "$_p9k_color1" 76 '' 0 '${(M)${:-$_p9k__keymap$_p9k__region_active}:#(vicmd1|vivis?|vivli?)}' 'Ⅴ' fi fi + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } instant_prompt_prompt_char() { @@ -2538,6 +2840,25 @@ instant_prompt_prompt_char() { ################################################################ # Segment to display Swap information prompt_swap() { + local -i len=$#_p9k__prompt + _p9k_prompt_segment $0 yellow "$_p9k_color1" SWAP_ICON 1 '$_p9k__swap_used' '$_p9k__swap_used' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +function _p9k_prompt_swap_init() { + if [[ $_p9k_os == OSX && $+commands[sysctl] == 0 || $_p9k_os != OSX && ! -r /proc/meminfo ]]; then + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${:-}' + return + fi + typeset -g _p9k__swap_used= + _p9k__async_segments_compute+=_p9k_prompt_swap_compute +} + +_p9k_prompt_swap_compute() { + _p9k_worker_async _p9k_prompt_swap_async _p9k_prompt_swap_sync +} + +_p9k_prompt_swap_async() { local -F used_bytes if [[ "$_p9k_os" == "OSX" ]]; then @@ -2561,7 +2882,15 @@ prompt_swap() { fi _p9k_human_readable_bytes $used_bytes - _p9k_prompt_segment $0 yellow "$_p9k_color1" SWAP_ICON 0 '' $_p9k_ret + [[ $_p9k_ret != $_p9k__swap_used ]] || return + _p9k__swap_used=$_p9k_ret + typeset -p _p9k__swap_used + echo -E - 'reset=1' +} + +_p9k_prompt_swap_sync() { + eval $REPLY + _p9k_worker_reply $REPLY } ################################################################ @@ -2631,6 +2960,23 @@ instant_prompt_time() { _p9k_prompt_segment prompt_time "$_p9k_color2" "$_p9k_color1" "TIME_ICON" 1 '' $stash$_p9k_ret } +_p9k_prompt_time_init() { + (( _POWERLEVEL9K_EXPERIMENTAL_TIME_REALTIME )) || return + _p9k__async_segments_compute+=_p9k_prompt_time_compute +} + +_p9k_prompt_time_compute() { + _p9k_worker_async _p9k_prompt_time_async _p9k_prompt_time_sync +} + +_p9k_prompt_time_async() { + sleep 1 || true +} + +_p9k_prompt_time_sync() { + _p9k_worker_reply '_p9k_worker_invoke _p9k_prompt_time_compute _p9k_prompt_time_compute; reset=1' +} + ################################################################ # System date prompt_date() { @@ -2679,6 +3025,10 @@ prompt_todo() { fi } +_p9k_prompt_todo_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[todo.sh]' +} + ################################################################ # VCS segment: shows the state of your repository, if you are in a folder under # version control @@ -2930,7 +3280,7 @@ function _p9k_vcs_status_for_dir() { _p9k_ret=$_p9k__gitstatus_last[GIT_DIR:$GIT_DIR] [[ -n $_p9k_ret ]] else - local dir=$_p9k_pwd_a + local dir=$_p9k__pwd_a while true; do _p9k_ret=$_p9k__gitstatus_last[$dir] [[ -n $_p9k_ret ]] && return 0 @@ -3170,8 +3520,8 @@ function _p9k_vcs_resume() { if [[ -z $_p9k__gitstatus_next_dir ]]; then unset _p9k__gitstatus_next_dir case $VCS_STATUS_RESULT in - norepo-async) (( $1 )) && _p9k_vcs_status_purge $_p9k_pwd_a;; - ok-async) (( $1 )) || _p9k__gitstatus_next_dir=$_p9k_pwd_a;; + norepo-async) (( $1 )) && _p9k_vcs_status_purge $_p9k__pwd_a;; + ok-async) (( $1 )) || _p9k__gitstatus_next_dir=$_p9k__pwd_a;; esac fi @@ -3199,12 +3549,12 @@ function _p9k_vcs_resume() { function _p9k_vcs_gitstatus() { if [[ $_p9k_refresh_reason == precmd ]]; then if (( $+_p9k__gitstatus_next_dir )); then - _p9k__gitstatus_next_dir=$_p9k_pwd_a + _p9k__gitstatus_next_dir=$_p9k__pwd_a else local -F timeout=_POWERLEVEL9K_VCS_MAX_SYNC_LATENCY_SECONDS if ! _p9k_vcs_status_for_dir; then _p9k__git_dir=$GIT_DIR - gitstatus_query -d $_p9k_pwd_a -t $timeout -p -c '_p9k_vcs_resume 0' POWERLEVEL9K || return 1 + gitstatus_query -d $_p9k__pwd_a -t $timeout -p -c '_p9k_vcs_resume 0' POWERLEVEL9K || return 1 _p9k_maybe_ignore_git_repo case $VCS_STATUS_RESULT in tout) _p9k__gitstatus_next_dir=''; _p9k__gitstatus_start_time=$EPOCHREALTIME; return 0;; @@ -3215,7 +3565,7 @@ function _p9k_vcs_gitstatus() { if [[ -n $GIT_DIR ]]; then [[ $_p9k_git_slow[GIT_DIR:$GIT_DIR] == 1 ]] && timeout=0 else - local dir=$_p9k_pwd_a + local dir=$_p9k__pwd_a while true; do case $_p9k_git_slow[$dir] in "") [[ $dir == / ]] && break; dir=${dir:h};; @@ -3227,14 +3577,14 @@ function _p9k_vcs_gitstatus() { fi (( _p9k__prompt_idx == 1 )) && timeout=0 _p9k__git_dir=$GIT_DIR - if ! gitstatus_query -d $_p9k_pwd_a -t $timeout -c '_p9k_vcs_resume 1' POWERLEVEL9K; then + if ! gitstatus_query -d $_p9k__pwd_a -t $timeout -c '_p9k_vcs_resume 1' POWERLEVEL9K; then unset VCS_STATUS_RESULT return 1 fi _p9k_maybe_ignore_git_repo case $VCS_STATUS_RESULT in tout) _p9k__gitstatus_next_dir=''; _p9k__gitstatus_start_time=$EPOCHREALTIME;; - norepo-sync) _p9k_vcs_status_purge $_p9k_pwd_a;; + norepo-sync) _p9k_vcs_status_purge $_p9k__pwd_a;; ok-sync) _p9k_vcs_status_save;; esac fi @@ -3279,6 +3629,7 @@ prompt_vcs() { ################################################################ # Vi Mode: show editing mode (NORMAL|INSERT|VISUAL) prompt_vi_mode() { + local -i len=$#_p9k__prompt if (( __p9k_sh_glob )); then if (( $+_POWERLEVEL9K_VI_OVERWRITE_MODE_STRING )); then if [[ -n $_POWERLEVEL9K_VI_INSERT_MODE_STRING ]]; then @@ -3316,6 +3667,7 @@ prompt_vi_mode() { _p9k_prompt_segment $0_NORMAL "$_p9k_color1" white '' 0 '${(M)_p9k__keymap:#(vicmd|vivis|vivli)}' "$_POWERLEVEL9K_VI_COMMAND_MODE_STRING" fi fi + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] } instant_prompt_vi_mode() { @@ -3340,6 +3692,10 @@ prompt_virtualenv() { _p9k_prompt_segment "$0" "blue" "$_p9k_color1" 'PYTHON_ICON' 0 '' "$msg" } +_p9k_prompt_virtualenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$VIRTUAL_ENV' +} + function _p9k_read_pyenv_version_file() { [[ -r $1 ]] || return local content @@ -3361,7 +3717,7 @@ prompt_pyenv() { (( ${_POWERLEVEL9K_PYENV_SOURCES[(I)shell]} )) || return else (( ${_POWERLEVEL9K_PYENV_SOURCES[(I)local|global]} )) || return - [[ $PYENV_DIR == /* ]] && local dir=$PYENV_DIR || local dir="$_p9k_pwd_a/$PYENV_DIR" + [[ $PYENV_DIR == /* ]] && local dir=$PYENV_DIR || local dir="$_p9k__pwd_a/$PYENV_DIR" while true; do if _p9k_read_pyenv_version_file $dir/.python-version; then (( ${_POWERLEVEL9K_PYENV_SOURCES[(I)local]} )) || return @@ -3387,6 +3743,10 @@ prompt_pyenv() { _p9k_prompt_segment "$0" "blue" "$_p9k_color1" 'PYTHON_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_pyenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[pyenv]:-${${+functions[pyenv]}:#0}}' +} + function _p9k_read_goenv_version_file() { [[ -r $1 ]] || return local content @@ -3404,7 +3764,7 @@ prompt_goenv() { (( $+commands[goenv] || $+functions[goenv] )) || return local v=${(j.:.)${(s.:.)GOENV_VERSION}} if [[ -z $v ]]; then - [[ $GOENV_DIR == /* ]] && local dir=$GOENV_DIR || local dir="$_p9k_pwd_a/$GOENV_DIR" + [[ $GOENV_DIR == /* ]] && local dir=$GOENV_DIR || local dir="$_p9k__pwd_a/$GOENV_DIR" while true; do if _p9k_read_goenv_version_file $dir/.go-version; then v=$_p9k_ret @@ -3428,6 +3788,10 @@ prompt_goenv() { _p9k_prompt_segment "$0" "blue" "$_p9k_color1" 'GO_ICON' 0 '' "${v//\%/%%}" } +_p9k_prompt_goenv_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${commands[goenv]:-${${+functions[goenv]}:#0}}' +} + ################################################################ # Display openfoam information prompt_openfoam() { @@ -3440,6 +3804,10 @@ prompt_openfoam() { fi } +_p9k_prompt_openfoam_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$WM_PROJECT_VERSION' +} + ################################################################ # Segment to display Swift version prompt_swift_version() { @@ -3448,10 +3816,14 @@ prompt_swift_version() { _p9k_prompt_segment "$0" "magenta" "white" 'SWIFT_ICON' 0 '' "${match[1]//\%/%%}" } +_p9k_prompt_swift_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[swift]' +} + ################################################################ # dir_writable: Display information about the user's permission to write in the current directory prompt_dir_writable() { - if [[ ! -w "$_p9k_pwd" ]]; then + if [[ ! -w "$_p9k__pwd" ]]; then _p9k_prompt_segment "$0_FORBIDDEN" "red" "yellow1" 'LOCK_ICON' 0 '' '' fi } @@ -3537,6 +3909,10 @@ prompt_kubecontext() { _p9k_prompt_segment $0$_p9k_cache_val[9] magenta white KUBERNETES_ICON 0 '' "${_p9k_cache_val[8]//\%/%%}" } +_p9k_prompt_kubecontext_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[kubectl]' +} + ################################################################ # Dropbox status prompt_dropbox() { @@ -3555,6 +3931,10 @@ prompt_dropbox() { fi } +_p9k_prompt_dropbox_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[dropbox-cli]' +} + # print Java version number prompt_java_version() { _p9k_cached_cmd_stdout_stderr java -fullversion || return @@ -3565,6 +3945,10 @@ prompt_java_version() { _p9k_prompt_segment "$0" "red" "white" "JAVA_ICON" 0 '' "${v//\%/%%}" } +_p9k_prompt_java_version_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[java]' +} + prompt_azure() { (( $+commands[az] )) || return local cfg=${AZURE_CONFIG_DIR:-$HOME/.azure}/azureProfile.json @@ -3581,6 +3965,10 @@ prompt_azure() { _p9k_prompt_segment "$0" "blue" "white" "AZURE_ICON" 0 '' "${_p9k_cache_val[1]//\%/%%}" } +_p9k_prompt_azure_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[az]' +} + prompt_gcloud() { unset P9K_GCLOUD_PROJECT P9K_GCLOUD_ACCOUNT (( $+commands[gcloud] )) || return @@ -3593,6 +3981,10 @@ prompt_gcloud() { _p9k_prompt_segment "$0" "blue" "white" "GCLOUD_ICON" 0 '' "${P9K_GCLOUD_ACCOUNT//\%/%%}:${P9K_GCLOUD_PROJECT//\%/%%}" } +_p9k_prompt_gcloud_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[gcloud]' +} + prompt_google_app_cred() { unset P9K_GOOGLE_APP_CRED_{TYPE,PROJECT_ID,CLIENT_EMAIL} [[ -n $GOOGLE_APPLICATION_CREDENTIALS ]] || return @@ -3623,6 +4015,10 @@ prompt_google_app_cred() { _p9k_prompt_segment "$0$_p9k_cache_val[6]" "blue" "white" "GCLOUD_ICON" 0 '' "$_p9k_cache_val[5]" } +_p9k_prompt_google_app_cred_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${GOOGLE_APPLICATION_CREDENTIALS:+$commands[jq]}' +} + typeset -gra __p9k_nordvpn_tag=( P9K_NORDVPN_STATUS P9K_NORDVPN_TECHNOLOGY @@ -3724,9 +4120,18 @@ function prompt_nordvpn() { esac } +_p9k_prompt_nordvpn_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[nordvpn]' +} + function prompt_ranger() { - [[ -n $RANGER_LEVEL ]] || return + local -i len=$#_p9k__prompt _p9k_prompt_segment $0 $_p9k_color1 yellow RANGER_ICON 0 '' $RANGER_LEVEL + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_ranger_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$RANGER_LEVEL' } function instant_prompt_ranger() { @@ -3734,8 +4139,13 @@ function instant_prompt_ranger() { } function prompt_midnight_commander() { - [[ -n $MC_TMPDIR ]] || return + local -i len=$#_p9k__prompt _p9k_prompt_segment $0 $_p9k_color1 yellow MIDNIGHT_COMMANDER_ICON 0 '' '' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_midnight_commander_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$MC_TMPDIR' } function instant_prompt_midnight_commander() { @@ -3743,8 +4153,13 @@ function instant_prompt_midnight_commander() { } function prompt_nnn() { - [[ $NNNLVL == (0|) ]] && return + local -i len=$#_p9k__prompt _p9k_prompt_segment $0 6 $_p9k_color1 NNN_ICON 0 '' $NNNLVL + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_nnn_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${NNNLVL:#0}' } function instant_prompt_nnn() { @@ -3752,8 +4167,13 @@ function instant_prompt_nnn() { } function prompt_vim_shell() { - [[ -n $VIMRUNTIME ]] || return + local -i len=$#_p9k__prompt _p9k_prompt_segment $0 green $_p9k_color1 VIM_ICON 0 '' '' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_vim_shell_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$VIMRUNTIME' } function instant_prompt_vim_shell() { @@ -3773,6 +4193,10 @@ function prompt_terraform() { [[ $ws == default ]] || _p9k_prompt_segment $0 $_p9k_color1 blue TERRAFORM_ICON 0 '' $ws } +_p9k_prompt_terraform_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$commands[terraform]' +} + function prompt_proxy() { local -U p=( $all_proxy $http_proxy $https_proxy $ftp_proxy @@ -3783,14 +4207,20 @@ function prompt_proxy() { _p9k_prompt_segment $0 $_p9k_color1 blue PROXY_ICON 0 '' "$p[1]" } +_p9k_prompt_proxy_init() { + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='$all_proxy$http_proxy$https_proxy$ftp_proxy$ALL_PROXY$HTTP_PROXY$HTTPS_PROXY$FTP_PROXY' +} + function prompt_direnv() { - if [[ -n $DIRENV_DIR ]]; then - _p9k_prompt_segment $0 $_p9k_color1 yellow DIRENV_ICON 0 '' '' - elif [[ $precmd_functions[-1] != _p9k_precmd ]]; then - # DIRENV_DIR is set in a precmd hook. If our hook isn't the last, DIRENV_DIR might - # still get set before prompt is expanded. - _p9k_prompt_segment $0 $_p9k_color1 yellow DIRENV_ICON 0 '$DIRENV_DIR' '' - fi + local -i len=$#_p9k__prompt + _p9k_prompt_segment $0 $_p9k_color1 yellow DIRENV_ICON 0 '$DIRENV_DIR' '' + typeset -g "_p9k__segment_val_${_p9k_prompt_side}[_p9k_segment_index]"=$_p9k__prompt[len+1,-1] +} + +_p9k_prompt_direnv_init() { + # DIRENV_DIR is set in a precmd hook. If our hook isn't the last, DIRENV_DIR might + # still get set before prompt is expanded. + typeset -g "_p9k__segment_cond_${_p9k_prompt_side}[_p9k_segment_index]"='${DIRENV_DIR:-${precmd_functions[-1]:#_p9k_precmd}}' } function instant_prompt_direnv() { @@ -3818,16 +4248,37 @@ _p9k_preexec2() { _p9k__timer_start=EPOCHREALTIME } -function _p9k_set_iface() { - _p9k_iface=() +function _p9k_prompt_net_iface_init() { + typeset -g _p9k__public_ip_vpn= + typeset -g _p9k__public_ip_not_vpn= + typeset -g _p9k__ip_ip= + typeset -g _p9k__vpn_ip_ip= + [[ -z $_POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE ]] && _p9k__public_ip_not_vpn=1 + _p9k__async_segments_compute+=_p9k_prompt_net_iface_compute +} + +# reads `iface2ip` and sets `ip` +function _p9k_prompt_net_iface_match() { + local iface_regex="^($1)\$" iface + for iface ip in "${(@kv)iface2ip}"; do + [[ $iface =~ $iface_regex ]] && return + done + return 1 +} + +function _p9k_prompt_net_iface_compute() { + _p9k_worker_async _p9k_prompt_net_iface_async _p9k_prompt_net_iface_sync +} + +function _p9k_prompt_net_iface_async() { + local iface ip line var + typeset -A iface2ip if [[ -x /sbin/ifconfig ]]; then - local line - local iface for line in ${(f)"$(/sbin/ifconfig 2>/dev/null)"}; do if [[ $line == (#b)([^[:space:]]##):[[:space:]]##flags=(<->)'<'* ]]; then [[ $match[2] == *[13579] ]] && iface=$match[1] || iface= elif [[ -n $iface && $line == (#b)[[:space:]]##inet[[:space:]]##([0-9.]##)* ]]; then - _p9k_iface[$iface]=$match[1] + iface2ip[$iface]=$match[1] iface= fi done @@ -3838,52 +4289,62 @@ function _p9k_set_iface() { if [[ $line == (#b)<->:[[:space:]]##([^:]##):[[:space:]]##\<([^\>]#)\>* ]]; then [[ ,$match[2], == *,UP,* ]] && iface=$match[1] || iface= elif [[ -n $iface && $line == (#b)[[:space:]]##inet[[:space:]]##([0-9.]##)* ]]; then - _p9k_iface[$iface]=$match[1] + iface2ip[$iface]=$match[1] iface= fi done fi -} -function _p9k_build_segment() { - _p9k_segment_name=${_p9k_segment_name%_joined} - local disabled=_POWERLEVEL9K_${(U)_p9k_segment_name}_DISABLED_DIR_PATTERN - [[ $_p9k_pwd == ${(P)~disabled} ]] && return - if [[ $_p9k_segment_name == custom_* ]]; then - _p9k_custom_prompt $_p9k_segment_name[8,-1] - elif (( $+functions[prompt_$_p9k_segment_name] )); then - prompt_$_p9k_segment_name + if _p9k_prompt_net_iface_match $_POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE; then + local public_ip_vpn=1 + local public_ip_not_vpn= + else + local public_ip_vpn= + local public_ip_not_vpn=1 + fi + if _p9k_prompt_net_iface_match $_POWERLEVEL9K_IP_INTERFACE; then + local ip_ip=$ip + else + local ip_ip= + fi + if _p9k_prompt_net_iface_match $_POWERLEVEL9K_VPN_IP_INTERFACE; then + local vpn_ip_ip=$ip + else + local vpn_ip_ip= fi - ((++_p9k_segment_index)) + [[ $_p9k__public_ip_vpn == $public_ip_vpn && + $_p9k__public_ip_not_vpn == $public_ip_not_vpn && + $_p9k__ip_ip == $ip_ip && + $_p9k__vpn_ip_ip == $vpn_ip_ip ]] && return 1 + _p9k__public_ip_vpn=$public_ip_vpn + _p9k__public_ip_not_vpn=$public_ip_not_vpn + _p9k__ip_ip=$ip_ip + _p9k__vpn_ip_ip=$vpn_ip_ip + typeset -p _p9k__public_ip_vpn _p9k__public_ip_not_vpn _p9k__ip_ip _p9k__vpn_ip_ip + echo -E - 'reset=1' } -function _p9k_build_instant_segment() { - _p9k_segment_name=${_p9k_segment_name%_joined} - local disabled=_POWERLEVEL9K_${(U)_p9k_segment_name}_DISABLED_DIR_PATTERN - [[ $_p9k_pwd == ${(P)~disabled} ]] && return - if (( $+functions[instant_prompt_$_p9k_segment_name] )); then - local -i len=$#_p9k__prompt - _p9k_non_hermetic_expansion=0 - instant_prompt_$_p9k_segment_name - if (( _p9k_non_hermetic_expansion )); then - _p9k__prompt[len+1,-1]= - fi - fi - ((++_p9k_segment_index)) +_p9k_prompt_net_iface_sync() { + eval $REPLY + _p9k_worker_reply $REPLY } function _p9k_set_prompt() { local ifs=$IFS IFS=$' \t\n\0' - _p9k_pwd=${(%):-%/} - _p9k_pwd_a=${_p9k_pwd:A} + + if [[ $_p9k_refresh_reason == precmd ]]; then + local f_compute + for f_compute in "${_p9k__async_segments_compute[@]}"; do + _p9k_worker_invoke ${f_compute%% *} ${(e)f_compute} + done + fi + PROMPT= RPROMPT= [[ $1 == instant_ ]] || PROMPT+='${$((_p9k_on_expand()))+}' PROMPT+=$_p9k_prompt_prefix_left - (( _p9k_fetch_iface )) && _p9k_set_iface - local -i left_idx=1 right_idx=1 num_lines=$#_p9k_line_segments_left for _p9k_line_index in {1..$num_lines}; do local right= @@ -3892,9 +4353,42 @@ function _p9k_set_prompt() { _p9k__prompt= _p9k_segment_index=right_idx _p9k_prompt_side=right - for _p9k_segment_name in ${(@0)_p9k_line_segments_right[_p9k_line_index]}; do - _p9k_build_${1}segment - done + if [[ $1 == instant_ ]]; then + for _p9k_segment_name in ${${(0)_p9k_line_segments_right[_p9k_line_index]}%_joined}; do + if (( $+functions[instant_prompt_$_p9k_segment_name] )); then + local disabled=_POWERLEVEL9K_${(U)_p9k_segment_name}_DISABLED_DIR_PATTERN + if [[ $_p9k__pwd != ${(P)~disabled} ]]; then + local -i len=$#_p9k__prompt + _p9k_non_hermetic_expansion=0 + instant_prompt_$_p9k_segment_name + if (( _p9k_non_hermetic_expansion )); then + _p9k__prompt[len+1,-1]= + fi + fi + fi + ((++_p9k_segment_index)) + done + else + for _p9k_segment_name in ${${(0)_p9k_line_segments_right[_p9k_line_index]}%_joined}; do + local cond=$_p9k__segment_cond_right[_p9k_segment_index] + if [[ -z $cond || -n ${(e)cond} ]]; then + local disabled=_POWERLEVEL9K_${(U)_p9k_segment_name}_DISABLED_DIR_PATTERN + if [[ $_p9k__pwd != ${(P)~disabled} ]]; then + local val=$_p9k__segment_val_right[_p9k_segment_index] + if [[ -n $val ]]; then + _p9k__prompt+=$val + else + if [[ $_p9k_segment_name == custom_* ]]; then + _p9k_custom_prompt $_p9k_segment_name[8,-1] + elif (( $+functions[prompt_$_p9k_segment_name] )); then + prompt_$_p9k_segment_name + fi + fi + fi + fi + ((++_p9k_segment_index)) + done + fi _p9k__prompt=${${_p9k__prompt//$' %{\b'/'%{%G'}//$' \b'} right_idx=_p9k_segment_index if [[ -n $_p9k__prompt || $_p9k_line_never_empty_right[_p9k_line_index] == 1 ]]; then @@ -3905,9 +4399,42 @@ function _p9k_set_prompt() { _p9k__prompt=$_p9k_line_prefix_left[_p9k_line_index] _p9k_segment_index=left_idx _p9k_prompt_side=left - for _p9k_segment_name in ${(@0)_p9k_line_segments_left[_p9k_line_index]}; do - _p9k_build_${1}segment - done + if [[ $1 == instant_ ]]; then + for _p9k_segment_name in ${${(0)_p9k_line_segments_left[_p9k_line_index]}%_joined}; do + if (( $+functions[instant_prompt_$_p9k_segment_name] )); then + local disabled=_POWERLEVEL9K_${(U)_p9k_segment_name}_DISABLED_DIR_PATTERN + if [[ $_p9k__pwd != ${(P)~disabled} ]]; then + local -i len=$#_p9k__prompt + _p9k_non_hermetic_expansion=0 + instant_prompt_$_p9k_segment_name + if (( _p9k_non_hermetic_expansion )); then + _p9k__prompt[len+1,-1]= + fi + fi + fi + ((++_p9k_segment_index)) + done + else + for _p9k_segment_name in ${${(0)_p9k_line_segments_left[_p9k_line_index]}%_joined}; do + local cond=$_p9k__segment_cond_left[_p9k_segment_index] + if [[ -z $cond || -n ${(e)cond} ]]; then + local disabled=_POWERLEVEL9K_${(U)_p9k_segment_name}_DISABLED_DIR_PATTERN + if [[ $_p9k__pwd != ${(P)~disabled} ]]; then + local val=$_p9k__segment_val_left[_p9k_segment_index] + if [[ -n $val ]]; then + _p9k__prompt+=$val + else + if [[ $_p9k_segment_name == custom_* ]]; then + _p9k_custom_prompt $_p9k_segment_name[8,-1] + elif (( $+functions[prompt_$_p9k_segment_name] )); then + prompt_$_p9k_segment_name + fi + fi + fi + fi + ((++_p9k_segment_index)) + done + fi _p9k__prompt=${${_p9k__prompt//$' %{\b'/'%{%G'}//$' \b'} left_idx=_p9k_segment_index _p9k__prompt+=$_p9k_line_suffix_left[_p9k_line_index] @@ -3974,7 +4501,7 @@ _p9k_dump_instant_prompt() { local root_dir=${__p9k_dump_file:h} local prompt_dir=${root_dir}/p10k-$user local root_file=$root_dir/p10k-instant-prompt-$user.zsh - local prompt_file=$prompt_dir/prompt-${#_p9k_pwd} + local prompt_file=$prompt_dir/prompt-${#_p9k__pwd} [[ -d $prompt_dir ]] || mkdir -p $prompt_dir || return [[ -w $root_dir && -w $prompt_dir ]] || return @@ -4275,17 +4802,6 @@ _p9k_dump_instant_prompt() { zf_mv -f $tmp $prompt_file 2>/dev/null || return } -powerlevel9k_refresh_prompt_inplace() { - emulate -L zsh - setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases - (( __p9k_enabled )) || return - _p9k_refresh_reason=precmd - _p9k_set_prompt - _p9k_refresh_reason='' -} - -p9k_refresh_prompt_inplace() { powerlevel9k_refresh_prompt_inplace } - typeset -gi __p9k_sh_glob typeset -gi __p9k_ksh_arrays typeset -gi __p9k_new_status @@ -4494,7 +5010,7 @@ function _p9k_clear_instant_prompt() { function _p9k_maybe_dump() { (( __p9k_dumps_enabled )) || return 0 - _p9k__instant_prompt_sig=$_p9k_pwd:$P9K_SSH:${(%):-%#} + _p9k__instant_prompt_sig=$_p9k__pwd:$P9K_SSH:${(%):-%#} if (( ! _p9k__dump_pid )) || ! kill -0 $_p9k__dump_pid 2>/dev/null; then _p9k__dump_pid=0 @@ -4534,7 +5050,6 @@ function _p9k_maybe_dump() { } function _p9k_on_expand() { - _p9k__last_prompt_update_time=EPOCHREALTIME (( _p9k__expanded && ! $+__p9k_instant_prompt_active )) && return () { @@ -4699,6 +5214,9 @@ _p9k_precmd_impl() { (( ++_p9k__prompt_idx )) fi + _p9k__pwd=${(%):-%/} + _p9k__pwd_a=${_p9k__pwd:A} + _p9k_refresh_reason=precmd _p9k_set_prompt _p9k_refresh_reason='' @@ -4715,6 +5233,8 @@ _p9k_precmd_impl() { if [[ $preexec_functions[-1] != _p9k_preexec2 && $preexec_functions[(I)_p9k_preexec2] != 0 ]]; then preexec_functions=(${(@)preexec_functions:#_p9k_preexec2} _p9k_preexec2) fi + + _p9k_worker_receive } _p9k_trapint() { @@ -4753,169 +5273,6 @@ function _p9k_reset_prompt() { fi } -_p9k_deinit_async_pump() { - if (( _p9k__async_pump_lock_fd )); then - zsystem flock -u $_p9k__async_pump_lock_fd - _p9k__async_pump_lock_fd=0 - fi - if (( _p9k__async_pump_fd )); then - zle -F $_p9k__async_pump_fd - exec {_p9k__async_pump_fd}>&- - _p9k__async_pump_fd=0 - fi - if (( _p9k__async_pump_pid )); then - kill -- -$_p9k__async_pump_pid &>/dev/null - _p9k__async_pump_pid=0 - fi - if [[ -n $_p9k__async_pump_fifo ]]; then - rm -f $_p9k__async_pump_fifo - _p9k__async_pump_fifo='' - fi - if [[ -n $_p9k__async_pump_lock ]]; then - rm -f $_p9k__async_pump_lock - _p9k__async_pump_lock='' - fi - _p9k__async_pump_subshell=-1 - _p9k__async_pump_shell_pid=-1 - add-zsh-hook -D zshexit _p9k_kill_async_pump -} - -function _p9k_on_async_message() { - emulate -L zsh - setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases - if (( ARGC != 1 )); then - _p9k_deinit_async_pump - return 0 - fi - local msg='' IFS='' - while read -r -t -u $1 msg; do - [[ $__p9k_enabled == 1 && $1 == $_p9k__async_pump_fd ]] && eval $_p9k__async_pump_line$msg - _p9k__async_pump_line= - msg= - done - _p9k__async_pump_line+=$msg - [[ $__p9k_enabled == 1 && $1 == $_p9k__async_pump_fd ]] && _p9k_reset_prompt -} - -function _p9k_async_pump() { - emulate -L zsh || return - setopt no_aliases no_hist_expand extended_glob || return - setopt no_prompt_bang prompt_{percent,subst} || return - zmodload zsh/system zsh/datetime || return - echo $$ || return - - local ip last_ip - local -F next_ip_time - while ! zsystem flock -t 0 $lock 2>/dev/null && kill -0 $parent_pid; do - if (( time_realtime )); then - echo || break - # SIGWINCH is a workaround for a bug in zsh. After a background job completes, callbacks - # registered with `zle -F` stop firing until the user presses any key or the process - # receives a signal (any signal at all). - # Fix: https://github.com/zsh-users/zsh/commit/5e11082349bf72897f93f3a4493a97a2caf15984. - kill -WINCH $parent_pid - fi - if (( public_ip && EPOCHREALTIME >= next_ip_time )); then - ip= - local method='' - local -F start=EPOCHREALTIME - next_ip_time=$((start + 5)) - for method in $ip_methods $ip_methods; do - case $method in - dig) - if (( $+commands[dig] )); then - ip="$(dig +tries=1 +short -4 A myip.opendns.com @resolver1.opendns.com 2>/dev/null)" - [[ $ip == ';'* ]] && ip= - if [[ -z $ip ]]; then - ip="$(dig +tries=1 +short -6 AAAA myip.opendns.com @resolver1.opendns.com 2>/dev/null)" - [[ $ip == ';'* ]] && ip= - fi - fi - ;; - curl) - if (( $+commands[curl] )); then - ip="$(curl --max-time 5 -w '\n' "$ip_url" 2>/dev/null)" - fi - ;; - wget) - if (( $+commands[wget] )); then - ip="$(wget -T 5 -qO- "$ip_url" 2>/dev/null)" - fi - ;; - esac - [[ $ip =~ '^[0-9a-f.:]+$' ]] || ip='' - if [[ -n $ip ]]; then - next_ip_time=$((start + tout)) - break - fi - done - if [[ $ip != $last_ip ]]; then - last_ip=$ip - echo _p9k__public_ip=${(q)${${ip//\%/%%}//$'\n'}} || break - kill -WINCH $parent_pid - fi - fi - sleep 1 - done - rm -f $lock $fifo -} - -function _p9k_kill_async_pump() { - emulate -L zsh - setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases - if [[ $ZSH_SUBSHELL == $_p9k__async_pump_subshell && $$ == $_p9k__async_pump_shell_pid ]]; then - _p9k_deinit_async_pump - fi -} - -_p9k_init_async_pump() { - local -i public_ip time_realtime - _p9k_segment_in_use public_ip && public_ip=1 - (( _POWERLEVEL9K_EXPERIMENTAL_TIME_REALTIME )) && time_realtime=1 - (( public_ip || time_realtime )) || return - - _p9k_start_async_pump() { - setopt err_return no_bg_nice - - _p9k__async_pump_lock=${TMPDIR:-/tmp}/p9k-$$-async-pump-lock.$EPOCHREALTIME.$RANDOM - _p9k__async_pump_fifo=${TMPDIR:-/tmp}/p9k-$$-async-pump-fifo.$EPOCHREALTIME.$RANDOM - echo -n >$_p9k__async_pump_lock - mkfifo $_p9k__async_pump_fifo - sysopen -rw -o cloexec,sync -u _p9k__async_pump_fd $_p9k__async_pump_fifo - zle -F $_p9k__async_pump_fd _p9k_on_async_message - zsystem flock -f _p9k__async_pump_lock_fd $_p9k__async_pump_lock - - local cmd=" - local -i public_ip=$public_ip time_realtime=$time_realtime parent_pid=$$ - local -a ip_methods=($_POWERLEVEL9K_PUBLIC_IP_METHODS) - local -F tout=$_POWERLEVEL9K_PUBLIC_IP_TIMEOUT - local ip_url=$_POWERLEVEL9K_PUBLIC_IP_HOST - local lock=$_p9k__async_pump_lock - local fifo=$_p9k__async_pump_fifo - $functions[_p9k_async_pump]" - - local setsid=${commands[setsid]:-/usr/local/opt/util-linux/bin/setsid} - [[ -f $setsid ]] && setsid=${(q)setsid} || setsid= - local zsh=${${:-/proc/self/exe}:A} - [[ -x $zsh ]] || zsh=zsh - cmd="$setsid ${(q)zsh} -dfc ${(q)cmd} &!" - $zsh --nobgnice -dfmc $cmd </dev/null >&$_p9k__async_pump_fd 2>/dev/null &! - - IFS='' read -t 5 -r -u $_p9k__async_pump_fd _p9k__async_pump_pid && (( _p9k__async_pump_pid )) - - _p9k__async_pump_subshell=$ZSH_SUBSHELL - _p9k__async_pump_shell_pid=$$ - add-zsh-hook zshexit _p9k_kill_async_pump - } - - if ! _p9k_start_async_pump ; then - >&2 print -rP -- "%F{red}[ERROR]%f Powerlevel10k failed to start async worker. The following segments may malfunction: " - (( public_ip )) && >&2 print -rP -- " - %F{green}public_ip%f" - (( time_realtime )) && >&2 print -rP -- " - %F{green}time%f" - _p9k_deinit_async_pump - fi -} - # Does ZSH have a certain off-by-one bug that triggers when PROMPT overflows to a new line? # # Bug: https://github.com/zsh-users/zsh/commit/d8d9fee137a5aa2cf9bf8314b06895bfc2a05518. @@ -4936,7 +5293,10 @@ typeset -g _p9k__param_pat typeset -g _p9k__param_sig _p9k_init_vars() { - typeset -gF _p9k__last_prompt_update_time + typeset -ga _p9k__segment_cond_left + typeset -ga _p9k__segment_cond_right + typeset -ga _p9k__segment_val_left + typeset -ga _p9k__segment_val_right typeset -ga _p9k_show_on_command typeset -g _p9k__last_buffer typeset -ga _p9k__last_commands @@ -4992,14 +5352,6 @@ _p9k_init_vars() { typeset -gi _p9k_line_index typeset -g _p9k_refresh_reason typeset -gi _p9k__region_active - typeset -g _p9k__async_pump_line - typeset -g _p9k__async_pump_fifo - typeset -g _p9k__async_pump_lock - typeset -gi _p9k__async_pump_lock_fd - typeset -gi _p9k__async_pump_fd - typeset -gi _p9k__async_pump_pid - typeset -gi _p9k__async_pump_subshell - typeset -gi _p9k__async_pump_shell_pid typeset -ga _p9k_line_segments_left typeset -ga _p9k_line_segments_right typeset -ga _p9k_line_prefix_left @@ -5041,10 +5393,8 @@ _p9k_init_vars() { typeset -g _p9k_w typeset -gi _p9k_dir_len typeset -gi _p9k_num_cpus - typeset -g _p9k_pwd - typeset -g _p9k_pwd_a - typeset -gA _p9k_iface - typeset -gi _p9k_fetch_iface + typeset -g _p9k__pwd + typeset -g _p9k__pwd_a typeset -g _p9k__keymap typeset -g _p9k__zle_state typeset -g _p9k_uname @@ -5054,6 +5404,7 @@ _p9k_init_vars() { typeset -g _p9k__last_prompt_pwd typeset -gA _p9k_display_k typeset -ga _p9k__display_v + typeset -ga _p9k__async_segments_compute typeset -gA _p9k__dotnet_stat_cache typeset -gA _p9k__dir_stat_cache @@ -5084,6 +5435,7 @@ _p9k_init_params() { _p9k_declare -s POWERLEVEL9K_TRANSIENT_PROMPT off [[ $_POWERLEVEL9K_TRANSIENT_PROMPT == (off|always|same-dir) ]] || _POWERLEVEL9K_TRANSIENT_PROMPT=off + _p9k_declare -s POWERLEVEL9K_WORKER_LOG_LEVEL _p9k_declare -i POWERLEVEL9K_COMMANDS_MAX_TOKEN_COUNT 64 _p9k_declare -a POWERLEVEL9K_HOOK_WIDGETS -- _p9k_declare -b POWERLEVEL9K_TODO_HIDE_ZERO_TOTAL 0 @@ -5140,6 +5492,7 @@ _p9k_init_params() { _p9k_declare -e POWERLEVEL9K_PUBLIC_IP_NONE "" _p9k_declare -s POWERLEVEL9K_PUBLIC_IP_HOST "http://ident.me" _p9k_declare -s POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE "" + _p9k_segment_in_use public_ip || _POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE= _p9k_declare -b POWERLEVEL9K_ALWAYS_SHOW_CONTEXT 0 _p9k_declare -b POWERLEVEL9K_ALWAYS_SHOW_USER 0 _p9k_declare -e POWERLEVEL9K_CONTEXT_TEMPLATE "%n@%m" @@ -5232,8 +5585,17 @@ _p9k_init_params() { [[ -z $_POWERLEVEL9K_SHORTEN_FOLDER_MARKER ]] && _POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=0 _p9k_declare -i POWERLEVEL9K_SHORTEN_DIR_LENGTH _p9k_declare -s POWERLEVEL9K_IP_INTERFACE "" + : ${_POWERLEVEL9K_IP_INTERFACE:='.*'} + _p9k_segment_in_use ip || _POWERLEVEL9K_IP_INTERFACE= _p9k_declare -s POWERLEVEL9K_VPN_IP_INTERFACE "(wg|(.*tun))[0-9]*" + : ${_POWERLEVEL9K_VPN_IP_INTERFACE:='.*'} + _p9k_segment_in_use vpn_ip || _POWERLEVEL9K_VPN_IP_INTERFACE= _p9k_declare -i POWERLEVEL9K_LOAD_WHICH 5 + case $_POWERLEVEL9K_LOAD_WHICH in + 1) _POWERLEVEL9K_LOAD_WHICH=1;; + 15) _POWERLEVEL9K_LOAD_WHICH=3;; + *) _POWERLEVEL9K_LOAD_WHICH=2;; + esac _p9k_declare -b POWERLEVEL9K_NODENV_PROMPT_ALWAYS_SHOW 0 _p9k_declare -b POWERLEVEL9K_NODE_VERSION_PROJECT_ONLY 0 _p9k_declare -b POWERLEVEL9K_DOTNET_VERSION_PROJECT_ONLY 1 @@ -5345,7 +5707,6 @@ _p9k_init_params() { _p9k_declare -b POWERLEVEL9K_TIME_UPDATE_ON_COMMAND 0 # If set to true, time will update every second. _p9k_declare -b POWERLEVEL9K_EXPERIMENTAL_TIME_REALTIME 0 - _p9k_segment_in_use time || _POWERLEVEL9K_EXPERIMENTAL_TIME_REALTIME=0 local -i i=1 while (( i <= $#_POWERLEVEL9K_LEFT_PROMPT_ELEMENTS )); do @@ -5786,12 +6147,12 @@ function _p9k_on_widget_zle-line-finish() { (( $+functions[p10k-on-post-prompt] )) && p10k-on-post-prompt if [[ -n $_p9k_transient_prompt ]]; then - if [[ $_POWERLEVEL9K_TRANSIENT_PROMPT == always || $_p9k_pwd == $_p9k__last_prompt_pwd ]]; then + if [[ $_POWERLEVEL9K_TRANSIENT_PROMPT == always || $_p9k__pwd == $_p9k__last_prompt_pwd ]]; then RPROMPT= PROMPT=$_p9k_transient_prompt __p9k_reset_state=2 else - _p9k__last_prompt_pwd=$_p9k_pwd + _p9k__last_prompt_pwd=$_p9k__pwd fi fi @@ -6122,10 +6483,10 @@ _p9k_init_display() { $i/left $((n+=2)) $j/left $n $i/right $((n+=2)) $j/right $n $i/gap $((n+=2)) $j/gap $n) - for name in ${(@0)_p9k_line_segments_left[i]}; do + for name in ${${(@0)_p9k_line_segments_left[i]}%_joined}; do _p9k_display_k+=($i/left/$name $((n+=2)) $j/left/$name $n) done - for name in ${(@0)_p9k_line_segments_right[i]}; do + for name in ${${(@0)_p9k_line_segments_right[i]}%_joined}; do _p9k_display_k+=($i/right/$name $((n+=2)) $j/right/$name $n) done done @@ -6297,11 +6658,11 @@ function _p9k_init_cacheable() { _p9k_init_prompt _p9k_init_display - local elem + local elem func local -i i=0 for i in {1..$#_p9k_line_segments_left}; do - for elem in ${(@0)_p9k_line_segments_left[i]}; do + for elem in ${${(@0)_p9k_line_segments_left[i]}%_joined}; do local var=POWERLEVEL9K_${(U)elem}_SHOW_ON_COMMAND (( $+parameters[$var] )) || continue _p9k_show_on_command+=( @@ -6309,7 +6670,7 @@ function _p9k_init_cacheable() { $((1+_p9k_display_k[$i/left/$elem])) _p9k__${i}l$elem) done - for elem in ${(@0)_p9k_line_segments_right[i]}; do + for elem in ${${(@0)_p9k_line_segments_right[i]}%_joined}; do local var=POWERLEVEL9K_${(U)elem}_SHOW_ON_COMMAND (( $+parameters[$var] )) || continue local cmds=(${(P)var}) @@ -6429,6 +6790,7 @@ function _p9k_init_cacheable() { BSD) (( $+commands[sysctl] )) && _p9k_num_cpus="$(sysctl -n hw.ncpu 2>/dev/null)";; *) (( $+commands[nproc] )) && _p9k_num_cpus="$(nproc 2>/dev/null)";; esac + (( _p9k_num_cpus )) || _p9k_num_cpus=1 if _p9k_segment_in_use dir; then if (( $+_POWERLEVEL9K_DIR_CLASSES )); then @@ -6461,11 +6823,6 @@ function _p9k_init_cacheable() { done fi fi - - if [[ -n $_POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE ]] && _p9k_segment_in_use public_ip || - _p9k_segment_in_use ip || _p9k_segment_in_use vpn_ip; then - _p9k_fetch_iface=1 - fi } _p9k_init_vcs() { @@ -6565,6 +6922,37 @@ _p9k_init() { _p9k_init_vars _p9k_restore_state || _p9k_init_cacheable + local -i i + local elem + + _p9k_prompt_side=left + _p9k_segment_index=1 + for i in {1..$#_p9k_line_segments_left}; do + for elem in ${${(@0)_p9k_line_segments_left[i]}%_joined}; do + local f_init=_p9k_prompt_${elem}_init + (( $+functions[$f_init] )) && $f_init + (( ++_p9k_segment_index )) + done + done + + _p9k_prompt_side=right + _p9k_segment_index=1 + for i in {1..$#_p9k_line_segments_right}; do + for elem in ${${(@0)_p9k_line_segments_right[i]}%_joined}; do + local f_init=_p9k_prompt_${elem}_init + (( $+functions[$f_init] )) && $f_init + (( ++_p9k_segment_index )) + done + done + + if [[ -n $_POWERLEVEL9K_PUBLIC_IP_VPN_INTERFACE || + -n $_POWERLEVEL9K_IP_INTERFACE || + -n $_POWERLEVEL9K_VPN_IP_INTERFACE ]]; then + _p9k_prompt_net_iface_init + fi + + (( $#_p9k__async_segments_compute )) && _p9k_worker_start + local k v for k v in ${(kv)_p9k_display_k}; do [[ $k == -* ]] && continue @@ -6609,7 +6997,6 @@ _p9k_init() { print -rP -- 'Either install %F{green}jq%f or change the value of %BPOWERLEVEL9K_SHORTEN_STRATEGY%b.' fi - _p9k_init_async_pump _p9k_init_vcs if (( _POWERLEVEL9K_DISABLE_INSTANT_PROMPT )); then @@ -6652,7 +7039,7 @@ _p9k_init() { _p9k_deinit() { (( $+functions[_p9k_preinit] )) && unfunction _p9k_preinit (( $+functions[gitstatus_stop] )) && gitstatus_stop POWERLEVEL9K - _p9k_deinit_async_pump + _p9k_worker_stop (( _p9k__dump_pid )) && wait $_p9k__dump_pid 2>/dev/null (( $+_p9k__iterm2_precmd )) && functions[iterm2_precmd]=$_p9k__iterm2_precmd (( $+_p9k__iterm2_decorate_prompt )) && functions[iterm2_decorate_prompt]=$_p9k__iterm2_decorate_prompt diff --git a/internal/worker.zsh b/internal/worker.zsh new file mode 100644 index 00000000..99948c46 --- /dev/null +++ b/internal/worker.zsh @@ -0,0 +1,258 @@ +# invoked in worker: _p9k_worker_main <pgid> +function _p9k_worker_main() { + mkfifo $_p9k__worker_file_prefix.fifo || return + echo -nE - s$_p9k_worker_pgid$'\x1e' || return + exec 0<$_p9k__worker_file_prefix.fifo || return + zf_rm $_p9k__worker_file_prefix.fifo || return + + typeset -g IFS=$' \t\n\0' + + local -i reset + local req fd + local -a ready + local _p9k_worker_request_id + local -A _p9k_worker_fds # fd => id$'\x1f'callback + local -A _p9k_worker_inflight # id => inflight count + + function _p9k_worker_reply() { + print -nr -- e${(pj:\n:)@}$'\x1e' || kill -- -$_p9k_worker_pgid + } + + # usage: _p9k_worker_async <work> <callback> + function _p9k_worker_async() { + local fd async=$1 + sysopen -r -o cloexec -u fd <( + () { eval $async; } && print -n '\x1e') || return + (( ++_p9k_worker_inflight[$_p9k_worker_request_id] )) + _p9k_worker_fds[$fd]=$_p9k_worker_request_id$'\x1f'$2 + } + + trap '' PIPE + + { + while zselect -a ready 0 ${(k)_p9k_worker_fds}; do + [[ $ready[1] == -r ]] || return + for fd in ${ready:1}; do + if [[ $fd == 0 ]]; then + local buf= + while true; do + sysread -t 0 'buf[$#buf+1]' && continue + (( $? == 4 )) || return + [[ $buf[-1] == (|$'\x1e') ]] && break + sysread 'buf[$#buf+1]' || return + done + for req in ${(ps:\x1e:)buf}; do + _p9k_worker_request_id=${req%%$'\x1f'*} + () { eval $req[$#_p9k_worker_request_id+2,-1] } + (( $+_p9k_worker_inflight[$_p9k_worker_request_id] )) && continue + print -rn -- d$_p9k_worker_request_id$'\x1e' || return + done + else + local REPLY= + while true; do + sysread -i $fd 'REPLY[$#REPLY+1]' && continue + (( $? == 5 )) || return + break + done + local cb=$_p9k_worker_fds[$fd] + _p9k_worker_request_id=${cb%%$'\x1f'*} + unset "_p9k_worker_fds[$fd]" + exec {fd}>&- + if [[ $REPLY == *$'\x1e' ]]; then + REPLY[-1]="" + () { eval $cb[$#_p9k_worker_request_id+2,-1] } + fi + if (( --_p9k_worker_inflight[$_p9k_worker_request_id] == 0 )); then + unset "_p9k_worker_inflight[$_p9k_worker_request_id]" + print -rn -- d$_p9k_worker_request_id$'\x1e' || return + fi + fi + done + done + } always { + kill -- -$_p9k_worker_pgid + } +} + +typeset -g _p9k__worker_pid +typeset -g _p9k__worker_req_fd +typeset -g _p9k__worker_resp_fd +typeset -g _p9k__worker_shell_pid +typeset -g _p9k__worker_file_prefix +typeset -gA _p9k__worker_request_map + +# invoked in master: _p9k_worker_invoke <request-id> <list> +function _p9k_worker_invoke() { + [[ -n $_p9k__worker_resp_fd ]] || return + local req=$1$'\x1f'$2$'\x1e' + if [[ -n $_p9k__worker_req_fd && $+_p9k__worker_request_map[$1] == 0 ]]; then + _p9k__worker_request_map[$1]= + print -rnu $_p9k__worker_req_fd -- $req + else + _p9k__worker_request_map[$1]=$req + fi +} + +function _p9k_worker_cleanup() { + emulate -L zsh + setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases + [[ $_p9k__worker_shell_pid == $sysparams[pid] ]] && _p9k_worker_stop + return 0 +} + +function _p9k_worker_stop() { + emulate -L zsh + setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases + add-zsh-hook -D zshexit _p9k_worker_cleanup + [[ -n $_p9k__worker_resp_fd ]] && zle -F $_p9k__worker_resp_fd + [[ -n $_p9k__worker_resp_fd ]] && exec {_p9k__worker_resp_fd}>&- + [[ -n $_p9k__worker_req_fd ]] && exec {_p9k__worker_req_fd}>&- + [[ -n $_p9k__worker_pid ]] && kill -- -$_p9k__worker_pid 2>/dev/null + [[ -n $_p9k__worker_file_prefix ]] && zf_rm -f $_p9k__worker_file_prefix.fifo + _p9k__worker_pid= + _p9k__worker_req_fd= + _p9k__worker_resp_fd= + _p9k__worker_shell_pid= + _p9k__worker_request_map=() + return 0 +} + +function _p9k_worker_receive() { + emulate -L zsh + setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases + + [[ -z $_p9k__worker_resp_fd ]] && return + + { + (( $# <= 1 )) || return + + local buf resp + while true; do + sysread -t 0 -i $_p9k__worker_resp_fd 'buf[$#buf+1]' && continue + (( $? == 4 )) || return + [[ $buf == (|*$'\x1e')$'\x05'# ]] && break + sysread -i $_p9k__worker_resp_fd 'buf[$#buf+1]' || return + done + + local -i reset + for resp in ${(ps:\x1e:)${buf//$'\x05'}}; do + local arg=$resp[2,-1] + case $resp[1] in + d) + local req=$_p9k__worker_request_map[$arg] + if [[ -n $req ]]; then + _p9k__worker_request_map[$arg]= + print -rnu $_p9k__worker_req_fd -- $req || return + else + unset "_p9k__worker_request_map[$arg]" + fi + ;; + e) + if (( start_time )); then + local -F end_time=EPOCHREALTIME + local -F3 latency=$((1000*(end_time-start_time))) + echo "latency: $latency ms" >>/tmp/log + start_time=0 + fi + () { eval $arg } + ;; + s) + [[ -z $_p9k__worker_pid ]] || return + [[ $arg == <1-> ]] || return + _p9k__worker_pid=$arg + sysopen -w -o cloexec -u _p9k__worker_req_fd $_p9k__worker_file_prefix.fifo || return + local req= + for req in $_p9k__worker_request_map; do + print -rnu $_p9k__worker_req_fd -- $req || return + done + _p9k__worker_request_map=({${(k)^_p9k__worker_request_map},''}) + ;; + *) + return 1 + ;; + esac + done + + if (( reset == 2 )); then + _p9k_refresh_reason=worker + _p9k_set_prompt + _p9k_refresh_reason='' + fi + (( reset )) && _p9k_reset_prompt + return 0 + } always { + (( $? )) && _p9k_worker_stop + } +} + +function _p9k_worker_start() { + setopt no_bgnice monitor + { + [[ -n $_p9k__worker_resp_fd ]] && return + _p9k__worker_file_prefix=${TMPDIR:-/tmp}/p10k.worker.$EUID.$$.$EPOCHSECONDS + + sysopen -r -o cloexec -u _p9k__worker_resp_fd <( + if [[ -n $_POWERLEVEL9K_WORKER_LOG_LEVEL ]]; then + exec 2>$_p9k__worker_file_prefix.log + setopt xtrace + else + exec 2>/dev/null + fi + # todo: remove + exec 2>>/tmp/log + setopt xtrace + zmodload zsh/zselect || return + ! { zselect -t0 || (( $? != 1 )) } || return + local _p9k_worker_pgid=$sysparams[pid] + _p9k_worker_main & + { + trap '' PIPE + while syswrite $'\x05'; do zselect -t 1000; done + zf_rm -f $_p9k__worker_file_prefix.fifo + kill -- -$_p9k_worker_pgid + } & + exec =true) || return + zle -F $_p9k__worker_resp_fd _p9k_worker_receive + _p9k__worker_shell_pid=$sysparams[pid] + add-zsh-hook zshexit _p9k_worker_cleanup + } always { + (( $? )) && _p9k_worker_stop + } +} + +# todo: remove + +return + +function _p9k_reset_prompt() { + zle && zle reset-prompt && zle -R +} + +emulate -L zsh -o prompt_subst -o interactive_comments # -o xtrace + +# POWERLEVEL9K_WORKER_LOG_LEVEL=DEBUG + +zmodload zsh/datetime +zmodload zsh/system +zmodload -F zsh/files b:zf_mv b:zf_rm + +autoload -Uz add-zsh-hook + +function foo_compute() { + _p9k_worker_reply 'echo sync latency: $((1000*(EPOCHREALTIME-'$1'))) >>/tmp/log' + # _p9k_worker_async foo_async "foo_sync $1" +} + +function foo_async() { +} + +function foo_sync() { + _p9k_worker_reply 'echo async latency: $((1000*(EPOCHREALTIME-'$1'))) >>/tmp/log' +} + +typeset -F start_time=EPOCHREALTIME +_p9k_worker_start +_p9k_worker_invoke first '_p9k_worker_reply ""' +echo -E - $((1000*(EPOCHREALTIME-start_time))) + +bm() { _p9k_worker_invoke foo$1 "foo_compute $EPOCHREALTIME" } diff --git a/notes.txt b/notes.txt new file mode 100644 index 00000000..a37fbaa2 --- /dev/null +++ b/notes.txt @@ -0,0 +1,10 @@ +- battery: when state or icon change, update with _p9k_set_prompt. make sure icons can be sent with + `typset -p` in zsh 5.1. +- ram: reduce precision to 2 digits. check if it makes sense for all segments that use the same + function. +- to avoid resetting prompt too often (e.g., when battery remaining time changes by 1 minute), can + do the following: send the current state from master to worker; worker sends new state if it's + different but it only triggers prompt reset if it's sufficiently different. this requires + disabling implicit reset on every eval in _p9k_worker_receive. +- implement fake gitstatus api on top of vcs_info (or plain git?) + worker and use it if there is no + gitstatus. diff --git a/powerlevel10k.zsh-theme b/powerlevel10k.zsh-theme index 98ddc24b..834edd6d 100644 --- a/powerlevel10k.zsh-theme +++ b/powerlevel10k.zsh-theme @@ -33,7 +33,7 @@ typeset -gr __p9k_sourced=1 if [[ -w $__p9k_root_dir && -w $__p9k_root_dir/internal && -w $__p9k_root_dir/gitstatus && ${(%):-%#} == % ]]; then local f - for f in $__p9k_root_dir/{powerlevel9k.zsh-theme,powerlevel10k.zsh-theme,internal/p10k.zsh,internal/icons.zsh,internal/configure.zsh,gitstatus/gitstatus.plugin.zsh}; do + for f in $__p9k_root_dir/{powerlevel9k.zsh-theme,powerlevel10k.zsh-theme,internal/p10k.zsh,internal/icons.zsh,internal/configure.zsh,internal/worker.zsh,gitstatus/gitstatus.plugin.zsh}; do [[ $f.zwc -nt $f ]] || zcompile $f done fi |