diff --git a/README.md b/README.md index 218463e2..1c170601 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ it will generate the same prompt. 1. [Does Powerlevel10k always render exactly the same prompt as Powerlevel9k given the same config?](#does-powerlevel10k-always-render-exactly-the-same-prompt-as-powerlevel9k-given-the-same-config) 1. [Is there an AUR package for Powerlevel10k?](#is-there-an-aur-package-for-powerlevel10k) 1. [I cannot make Powerlevel10k work with my plugin manager. Help!](#i-cannot-make-powerlevel10k-work-with-my-plugin-manager-help) - 1. [What is the minimum supported ZSH version?](#what-is-the-minimum-supported-zsh-version) + 1. [What is the minimum supported zsh version?](#what-is-the-minimum-supported-zsh-version) ## Installation @@ -160,7 +160,7 @@ Try Powerlevel10k in Docker. You can safely make any changes to the file system the theme. Once you exit zsh, the image is deleted. ```zsh -docker run -e LANG=en_US.utf8 -e TERM -it --rm archlinux/base bash -uexc ' +docker run -e TERM -it --rm archlinux/base bash -uexc ' pacman -Sy --noconfirm zsh git git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k echo "source ~/powerlevel10k/powerlevel10k.zsh-theme" >>~/.zshrc @@ -203,44 +203,69 @@ covered by the same license. ## FAQ -### What is instant prompt? - -**IMPORTANT UPDATE**: Instant prompt is incompatible with zsh startup configs that may require -console input. This includes asking for a keyring password and *[Y/N]* confirmations. It is -currently **NOT RECOMMENDED** that you enable instant prompt. +### What is instant prompt? *Instant Prompt* is an optional feature of Powerlevel10k. When enabled, it gives you a limited -prompt within 10 milliseconds of staring zsh, alowing you to start hacking right away while zsh -is initializing. Once the initialization is complete, the full-featured Powerlevel10k will +prompt within a few milliseconds of staring zsh, alowing you to start hacking right away while zsh +is initializing. Once initialization is complete, the full-featured Powerlevel10k prompt will seamlessly replace instant prompt. -When you run `p10k configure`, Powerlevel10k will automatically enable instant prompt for you if -it hasn't been already enabled. You can also enable it manually by adding two code snippets to -`~/.zshrc`. - -At the very top of `~/.zshrc`: +You can enable instant prompt either by running `p10k configure` or by manually adding the following +code snippet at the top of `~/.zshrc`: ```zsh -# Enable Powerlevel10k instant prompt. Should stay at the top of ~/.zshrc. +# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. +# Initialization code that may require console input (password prompts, [y/n] +# confirmations, etc.) must go above this block, everything else may go below. if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" fi ``` -And at the very bottom of `~/.zshrc`: +It's important that you copy the lines verbatim. Don't replace `source` with something else, don't +call `zcompile`, don't redirect output, etc. + +When instant prompt is enabled, for the duration of zsh initialization standard input is redirected +to `/dev/null` and standard output with standard error are redirected to a temporary file. Once zsh +is fully initialized, standard file descriptors are restored and the content of the temporary file +is printed out. + +When using instant prompt, you should carefully check any output that appears on zsh startup as it +may indicate that initialization has been altered, or perhaps even broken, by instant prompt. +Initialization code that may require console input, such as asking for a keyring password or for a +*[y/n]* confirmation, must be moved above the instant prompt preamble in `~/.zshrc`. Initialization +code that merely prints to console but never reads from it will work correctly with instant prompt, +although output that normally has colors may appear uncolored. You can either leave it be, suppress +the output, or move it above the instant prompt preamble. Here's an example of `~/.zshrc` that +breaks when instant prompt is enabled. ```zsh -# Finalize Powerlevel10k instant prompt. Should stay at the bottom of ~/.zshrc. -(( ! ${+functions[p10k-instant-prompt-finalize]} )) || p10k-instant-prompt-finalize +if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then + source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" +fi +keychain id_rsa --agents ssh # asks for password +chatty-script # spams to stdout even when everything is fine ``` -It's important that you copy the lines verbatim. Don't replace `source` with something else, don't -call `zcompile`, don't redirect output, etc. Just copy the lines and restart zsh. +Fixed version: -To disable instant prompt, define `POWERLEVEL9K_DISABLE_INSTANT_PROMPT=true` together with the rest -of your `POWERLEVEL9K` parameters. `~/.p10k.zsh` already has a line that you can simply uncomment. +```zsh +keychain id_rsa --agents ssh # moved before instant prompt +if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then + source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" +fi +chatty-script >/dev/null # spam output suppressed +``` -*NOTE: Instant prompt requires ZSH >= 5.4. It's OK to enable it even when using an older ZSH version +If `POWERLEVEL9K_INSTANT_PROMPT` is unset or set to `verbose`, Powerlevel10k will print a warning +when it detects console output during initialization to bring attention to potential issues. You can +silence this warning (without suppressing console output) with `POWERLEVEL9K_INSTANT_PROMPT=quiet`. +This is recommended if some initialization code in `~/.zshrc` prints to console and it's infeasible +to move it above the instant prompt preamble or to suppress its output. You can completely disable +instant prompt with `POWERLEVEL9K_INSTANT_PROMPT=off`. Do this if instant prompt breaks zsh +initialization and you don't know how to fix it. + +*NOTE: Instant prompt requires zsh >= 5.4. It's OK to enable it even when using an older zsh version but it won't do anything.* ### Why my icons and/or powerline symbols look bad? @@ -369,7 +394,7 @@ prompt latency when using Powerlevel10k, please ### Is Powerlevel10k fast to load? -Yes, provided that you are using ZSH >= 5.4. +Yes, provided that you are using zsh >= 5.4. Loading time, or time to first prompt, can be measured with the following benchmark: @@ -440,9 +465,9 @@ echo 'source ~/powerlevel10k/powerlevel10k.zsh-theme' >>! ~/.zshrc This method of installation won't make anything slower or otherwise sub-par. -### What is the minimum supported ZSH version? +### What is the minimum supported zsh version? -ZSH 5.1 or newer should work. +Zsh 5.1 or newer should work. However, there are too many version, OS, platform, terminal and option configurations to test. If Powerlevel10k doesn't work for you, please open an issue. diff --git a/config/p10k-classic.zsh b/config/p10k-classic.zsh index 65e357e3..d8179312 100644 --- a/config/p10k-classic.zsh +++ b/config/p10k-classic.zsh @@ -813,8 +813,17 @@ typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=208 typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='${P9K_VISUAL_IDENTIFIER}' - # When instant prompt is disabled, prompt won't appear until zsh is fully initialized. - # typeset -g POWERLEVEL9K_DISABLE_INSTANT_PROMPT=true + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose } (( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} diff --git a/config/p10k-lean.zsh b/config/p10k-lean.zsh index 71151631..9e450186 100644 --- a/config/p10k-lean.zsh +++ b/config/p10k-lean.zsh @@ -793,8 +793,17 @@ typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=208 typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='${P9K_VISUAL_IDENTIFIER}' - # When instant prompt is disabled, prompt won't appear until zsh is fully initialized. - # typeset -g POWERLEVEL9K_DISABLE_INSTANT_PROMPT=true + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose } (( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} diff --git a/config/p10k-pure.zsh b/config/p10k-pure.zsh index 5be28312..c91886a7 100644 --- a/config/p10k-pure.zsh +++ b/config/p10k-pure.zsh @@ -124,6 +124,18 @@ typeset -g POWERLEVEL9K_VCS_{COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=1 # Remove space between '⇣' and '⇡'. typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${P9K_CONTENT/⇣* ⇡/⇣⇡}' + + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose } (( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} diff --git a/config/p10k-rainbow.zsh b/config/p10k-rainbow.zsh index a7cefe91..713ba18d 100644 --- a/config/p10k-rainbow.zsh +++ b/config/p10k-rainbow.zsh @@ -839,8 +839,17 @@ # typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=4 typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='${P9K_VISUAL_IDENTIFIER}' - # When instant prompt is disabled, prompt won't appear until zsh is fully initialized. - # typeset -g POWERLEVEL9K_DISABLE_INSTANT_PROMPT=true + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose } (( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} diff --git a/internal/configure.zsh b/internal/configure.zsh index 202978f6..eb991ff1 100644 --- a/internal/configure.zsh +++ b/internal/configure.zsh @@ -17,7 +17,6 @@ function _p9k_can_configure() { (( q )) || print -rP "%1F[ERROR]%f %Bp10k configure%b: $1" >&2 } { - [[ -t 0 && -t 1 ]] || { $0_error "no TTY"; return 1 } [[ -o multibyte ]] || { $0_error "multibyte option is not set"; return 1 } [[ -e $__p9k_zd ]] || { $0_error "$__p9k_zd_u does not exist"; return 1 } [[ -d $__p9k_zd ]] || { $0_error "$__p9k_zd_u is not a directory"; return 1 } @@ -53,6 +52,8 @@ function _p9k_can_configure() { $0_error "terminal size too small; must be at least $__p9k_wizard_columns x $__p9k_wizard_lines" return 1 } + [[ -t 0 && -t 1 ]] || { $0_error "no TTY"; return 2 } + return 0 } always { unfunction $0_error } diff --git a/internal/p10k.zsh b/internal/p10k.zsh index d0d8e487..5a404d63 100644 --- a/internal/p10k.zsh +++ b/internal/p10k.zsh @@ -3502,8 +3502,7 @@ _p9k_dump_instant_prompt() { [[ -d $prompt_dir ]] || mkdir -p $prompt_dir || return [[ -w $root_dir && -w $prompt_dir ]] || return - if [[ ! -e $root_file || - ($+__p9k_instant_prompt_sourced == 1 && $__p9k_instant_prompt_sourced != $__p9k_instant_prompt_version) ]]; then + if [[ ! -e $root_file ]]; then local tmp=$root_file.tmp.$$ local -i fd sysopen -a -o creat,trunc -u fd $tmp || return @@ -3513,7 +3512,8 @@ _p9k_dump_instant_prompt() { (( ! \$+__p9k_instant_prompt_disabled )) || return typeset -gi __p9k_instant_prompt_disabled=1 __p9k_instant_prompt_sourced=$__p9k_instant_prompt_version [[ -t 0 && -t 1 && -t 2 && \$ZSH_VERSION == ${(q)ZSH_VERSION} && \$ZSH_PATCHLEVEL == ${(q)ZSH_PATCHLEVEL} && - \$+VTE_VERSION == $+VTE_VERSION && \$POWERLEVEL9K_DISABLE_INSTANT_PROMPT != 'true' ]] || return + \$+VTE_VERSION == $+VTE_VERSION && \$POWERLEVEL9K_DISABLE_INSTANT_PROMPT != 'true' && + \$POWERLEVEL9K_INSTANT_PROMPT != 'off' ]] || return local -i ZLE_RPROMPT_INDENT=${ZLE_RPROMPT_INDENT:-1} local PROMPT_EOL_MARK=${(q)PROMPT_EOL_MARK-%B%S%#%s%b} [[ -n \$SSH_CLIENT || -n \$SSH_TTY || -n \$SSH_CONNECTION ]] && local ssh=1 || local ssh=0 @@ -3527,7 +3527,7 @@ _p9k_dump_instant_prompt() { fi" >&$fd print -r -- ' zmodload zsh/terminfo - (( $+terminfo[cuu] && $+terminfo[cuf] && $+terminfo[sgr0] && $+terminfo[ed] && $+terminfo[sc] && $+terminfo[rc] )) || return + (( $+terminfo[cuu] && $+terminfo[cuf] && $+terminfo[ed] && $+terminfo[sc] && $+terminfo[rc] )) || return local pwd=${(%):-%/} local prompt_file=$prompt_dir/prompt-${#pwd} local key=$pwd:$ssh:${(%):-%#} @@ -3541,22 +3541,27 @@ _p9k_dump_instant_prompt() { if (( $+VTE_VERSION )); then >&$fd print -r -- ' if (( LINES == 24 && COLUMNS == 80 )); then + zmodload -F zsh/stat b:zstat zmodload zsh/datetime - local -F deadline=$((EPOCHREALTIME+0.025)) - local tty_size - while true; do - if (( EPOCHREALTIME > deadline )) || ! tty_size="$(/bin/stty size 2>/dev/null)" || [[ $tty_size != <->" "<-> ]]; then - local __p9k_x_gap= - local __p9k_x_right= - break - fi - if [[ $tty_size != "24 80" ]]; then - local lines_columns=(${=tty_size}) - local LINES=$lines_columns[1] - local COLUMNS=$lines_columns[2] - break - fi - done + local -a tty_ctime + if ! zstat -A tty_ctime +ctime -- $TTY 2>/dev/null || (( $tty_ctime[1] + 2 > EPOCHREALTIME )); then + zmodload zsh/datetime + local -F deadline=$((EPOCHREALTIME+0.025)) + local tty_size + while true; do + if (( EPOCHREALTIME > deadline )) || ! tty_size="$(/bin/stty size 2>/dev/null)" || [[ $tty_size != <->" "<-> ]]; then + local __p9k_x_gap= + local __p9k_x_right= + break + fi + if [[ $tty_size != "24 80" ]]; then + local lines_columns=(${=tty_size}) + local LINES=$lines_columns[1] + local COLUMNS=$lines_columns[2] + break + fi + done + fi fi' fi >&$fd print -r -- ' typeset -ga __p9k_used_instant_prompt=("${(@e)_p9k_t[-3,-1]}")' @@ -3586,7 +3591,7 @@ _p9k_dump_instant_prompt() { >&$fd print -r -- ' [[ $PROMPT_EOL_MARK == "%B%S%#%s%b" ]] && _p9k_ret=1 || _p9k_prompt_length $PROMPT_EOL_MARK local -i fill=$((COLUMNS > _p9k_ret ? COLUMNS - _p9k_ret : 0)) - out+="${(%):-$PROMPT_EOL_MARK${(pl.$fill.. .)}$cr%b%k%f%E}"' + out+="${(%):-$PROMPT_EOL_MARK${(pl.$fill.. .)}$cr%b%k%f%s%u%E}"' (( $+VTE_VERSION )) && >&$fd print -r -- ' fi' >&$fd print -r -- ' out+="${(pl.$height..$lf.)}$esc${height}A$terminfo[sc]" @@ -3597,7 +3602,7 @@ _p9k_dump_instant_prompt() { _p9k_prompt_length "$__p9k_used_instant_prompt[3]" local -i gap=$((COLUMNS - left_len - _p9k_ret - ZLE_RPROMPT_INDENT)) if (( gap >= 40 )); then - out+="${(pl.$gap.. .)}${(%)${__p9k_used_instant_prompt[3]}}$terminfo[sgr0]$cr$esc${left_len}C" + out+="${(pl.$gap.. .)}${(%):-${__p9k_used_instant_prompt[3]}%b%k%f%s%u}$cr$esc${left_len}C" fi fi typeset -g __p9k_instant_prompt_output=${TMPDIR:-/tmp}/p10k-instant-prompt-output-${(%):-%n}-$$ @@ -3619,14 +3624,18 @@ _p9k_dump_instant_prompt() { exec 0<&$__p9k_fd_0 1>&$__p9k_fd_1 2>&$__p9k_fd_2 {__p9k_fd_0}>&- {__p9k_fd_1}>&- {__p9k_fd_2}>&- unset __p9k_fd_0 __p9k_fd_1 __p9k_fd_2 __p9k_instant_prompt_active typeset -gi __p9k_instant_prompt_erased=1 - print -rn -- $terminfo[rc]$terminfo[sgr0]$terminfo[ed] + print -rn -- $terminfo[rc]${(%):-%b%k%f%s%u}$terminfo[ed] if [[ -s $__p9k_instant_prompt_output ]]; then cat $__p9k_instant_prompt_output 2>/dev/null + local _p9k_ret + [[ $PROMPT_EOL_MARK == "%B%S%#%s%b" ]] && _p9k_ret=1 || _p9k_prompt_length $PROMPT_EOL_MARK + local -i fill=$((COLUMNS > _p9k_ret ? COLUMNS - _p9k_ret : 0)) + echo -nE - "${(%):-$PROMPT_EOL_MARK${(pl.$fill.. .)}$cr%b%k%f%s%u%E}" fi zmodload -F zsh/files b:zf_rm zf_rm -f -- $__p9k_instant_prompt_output ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh{,.zwc} 2>/dev/null } - setopt prompt_cr prompt_sp + setopt no_local_options prompt_cr prompt_sp } zmodload zsh/sched sched +0 _p9k_instant_prompt_sched_last @@ -3771,12 +3780,60 @@ function _p9k_clear_instant_prompt() { exec 1>&$__p9k_fd_1 2>&$__p9k_fd_2 {__p9k_fd_1}>&- {__p9k_fd_2}>&- unset __p9k_fd_1 __p9k_fd_2 __p9k_instant_prompt_active if [[ -s $__p9k_instant_prompt_output ]]; then - print -rn -- $terminfo[rc]$terminfo[sgr0]$terminfo[ed] - cat $__p9k_instant_prompt_output 2>/dev/null - zf_rm -f -- $__p9k_instant_prompt_output 2>/dev/null + { + local content + [[ $_POWERLEVEL9K_INSTANT_PROMPT == verbose ]] && content="$(<$__p9k_instant_prompt_output)" + _p9k_prompt_length $PROMPT_EOL_MARK + local -i fill=$((COLUMNS > _p9k_ret ? COLUMNS - _p9k_ret : 0)) + local sp="${(%):-$PROMPT_EOL_MARK${(pl.$fill.. .)}$cr%b%k%f%s%u%E}" + print -rn -- $terminfo[rc]${(%):-%b%k%f%s%u}$terminfo[ed] + if [[ -n ${(S)content//$'\e'*$'\a'} ]]; then + echo -E - "" + echo -E - "${(%):-[%3FWARNING%f]: Console output during zsh initialization detected.}" + echo -E - "" + echo -E - "${(%):-When using Powerlevel10k with instant prompt, console output during zsh}" + echo -E - "${(%):-initialization may indicate issues. For details, see:}" + echo - "${(%):-\e]8;;https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt\ahttps://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt\e]8;;\a}" + echo -E - "" + echo -E - "${(%):-You can:}" + echo -E - "" + echo -E - "${(%):- - %BRecommended%b: Change %B$__p9k_zshrc_u%b so that it does not perform console I/O}" + echo -E - "${(%):- after the instant prompt preamble. See the link below for details.}" + echo -E - "" + echo -E - "${(%):- * You %Bwill not%b see this error message again.}" + echo -E - "${(%):- * Zsh will start %Bquickly%b and prompt will update %Bsmoothly%b.}" + echo -E - "" + echo -E - "${(%):- - Suppress this warning either by running %Bp10k configure%b or by manually}" + echo -E - "${(%):- defining the following parameter:}" + echo -E - "" + echo -E - "${(%):- %3Ftypeset%f -g POWERLEVEL9K_INSTANT_PROMPT=quiet}" + echo -E - "" + echo -E - "${(%):- * You %Bwill not%b see this error message again.}" + echo -E - "${(%):- * Zsh will start %Bquickly%b but prompt will %Bjump down%b after initialization.}" + echo -E - "" + echo -E - "${(%):- - Disable instant prompt either by running %Bp10k configure%b or by manually}" + echo -E - "${(%):- defining the following parameter:}" + echo -E - "" + echo -E - "${(%):- %3Ftypeset%f -g POWERLEVEL9K_INSTANT_PROMPT=off}" + echo -E - "" + echo -E - "${(%):- * You %Bwill not%b see this error message again.}" + echo -E - "${(%):- * Zsh will start %Bslowly%b.}" + echo -E - "" + echo -E - "${(%):- - Do nothing.}" + echo -E - "" + echo -E - "${(%):- * You %Bwill%b see this error message every time you start zsh.}" + echo -E - "${(%):- * Zsh will start %Bquickly%b but prompt will %Bjump down%b after initialization.}" + echo -E - "" + echo - "${(%):-%3F-- console output produced during zsh initialization follows --%f}" + echo -E - "" + fi + cat $__p9k_instant_prompt_output + echo -nE - $sp + zf_rm -f -- $__p9k_instant_prompt_output + } 2>/dev/null else zf_rm -f -- $__p9k_instant_prompt_output 2>/dev/null - print -rn -- $terminfo[rc]$terminfo[sgr0]$terminfo[ed] + print -rn -- $terminfo[rc]${(%):-%b%k%f%s%u}$terminfo[ed] fi prompt_opts=(percent subst sp cr) if [[ $_POWERLEVEL9K_DISABLE_INSTANT_PROMPT == 0 && -o prompt_cr ]]; then @@ -3785,10 +3842,10 @@ function _p9k_clear_instant_prompt() { >&2 echo -E - "" >&2 echo -E - "${(%):-You can:}" >&2 echo -E - "" - >&2 echo -E - "${(%):- - %BRecommended%b: call %Bp10k-instant-prompt-finalize%b at the end of %B$__p9k_zshrc_u%b.}" + >&2 echo -E - "${(%):- - %BRecommended%b: call %Bp10k finalize%b at the end of %B$__p9k_zshrc_u%b.}" >&2 echo -E - "${(%):- You can do this by running the following command:}" >&2 echo -E - "" - >&2 echo -E - "${(%):- %2Fecho%f %3F'(( ! \${+functions[p10k-instant-prompt-finalize]\} )) || p10k-instant-prompt-finalize'%f >>! $__p9k_zshrc_u}" + >&2 echo -E - "${(%):- %2Fecho%f %3F'(( ! \${+functions[p10k]\} )) || p10k finalize'%f >>! $__p9k_zshrc_u}" >&2 echo -E - "" >&2 echo -E - "${(%):- * You %Bwill not%b see this error message again.}" >&2 echo -E - "${(%):- * Zsh will start %Bquickly%b and %Bwithout%b prompt flickering.}" @@ -3798,10 +3855,10 @@ function _p9k_clear_instant_prompt() { >&2 echo -E - "${(%):- * You %Bwill not%b see this error message again.}" >&2 echo -E - "${(%):- * Zsh will start %Bquickly%b and %Bwithout%b prompt flickering.}" >&2 echo -E - "" - >&2 echo -E - "${(%):- - Set %BPOWERLEVEL9K_DISABLE_INSTANT_PROMPT=true%b at the bottom of %B$__p9k_zshrc_u%b.}" - >&2 echo -E - "${(%):- You can do this by running the following command:}" + >&2 echo -E - "${(%):- - Disable instant prompt either by running %Bp10k configure%b or by manually}" + >&2 echo -E - "${(%):- defining the following parameter:}" >&2 echo -E - "" - >&2 echo -E - "${(%):- %2Fecho%f %3F'POWERLEVEL9K_DISABLE_INSTANT_PROMPT=true'%f >>! $__p9k_zshrc_u}" + >&2 echo -E - "${(%):- %3Ftypeset%f -g POWERLEVEL9K_INSTANT_PROMPT=off}" >&2 echo -E - "" >&2 echo -E - "${(%):- * You %Bwill not%b see this error message again.}" >&2 echo -E - "${(%):- * Zsh will start %Bslowly%b.}" @@ -3847,23 +3904,36 @@ _p9k_precmd_impl() { fi if _p9k_must_init; then + local -i instant_prompt_disabled if (( !__p9k_configured )); then __p9k_configured=1 - if [[ "${parameters[(I)POWERLEVEL9K_*]}" == (POWERLEVEL9K_MODE|) ]] && _p9k_can_configure -q; then - ( - local p=("${(@)parameters[(I)AWESOME_*|CODEPOINT_*]}") - if (( $#p )); then - typeset -x -- "$p" - fi - "$__p9k_root_dir"/internal/wizard.zsh -d "$__p9k_root_dir" - ) - if (( ! $? )); then - source "$__p9k_cfg_path" - _p9k_must_init - fi + if [[ "${parameters[(I)POWERLEVEL9K_*]}" == (POWERLEVEL9K_MODE|) ]]; then + _p9k_can_configure -q + case $? in + 0) + ( + local p=("${(@)parameters[(I)AWESOME_*|CODEPOINT_*]}") + if (( $#p )); then + typeset -x -- "$p" + fi + "$__p9k_root_dir"/internal/wizard.zsh -d "$__p9k_root_dir" + ) + if (( $? )); then + instant_prompt_disabled=1 + else + source "$__p9k_cfg_path" + _p9k_must_init + fi + ;; + 2) + zf_rm -f -- ${__p9k_dump_file:h}/p10k-instant-prompt-${(%):-%n}.zsh{,.zwc} 2>/dev/null + instant_prompt_disabled=1 + ;; + esac fi fi _p9k_init + _p9k__instant_prompt_disabled=$((_POWERLEVEL9K_DISABLE_INSTANT_PROMPT || instant_prompt_disabled)) fi if (( _p9k__timer_start )); then @@ -3900,17 +3970,16 @@ _p9k_precmd_impl() { if (( ! _p9k__dump_pid )) || ! kill -0 $_p9k__dump_pid 2>/dev/null; then _p9k__dump_pid=0 if (( _p9k__prompt_idx == 1 )) then - (( _POWERLEVEL9K_DISABLE_INSTANT_PROMPT )) || _p9k_set_instant_prompt + (( _p9k__instant_prompt_disabled )) || _p9k_set_instant_prompt if (( !_p9k_state_restored )); then - if (( !_POWERLEVEL9K_DISABLE_INSTANT_PROMPT )); then + if (( !_p9k__instant_prompt_disabled )); then _p9k_dump_instant_prompt _p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]=1 fi _p9k_dump_state _p9k__state_dump_scheduled=0 - elif [[ $_POWERLEVEL9K_DISABLE_INSTANT_PROMPT == 0 && - ( $+__p9k_instant_prompt_sourced == 1 && $__p9k_instant_prompt_sourced != $__p9k_instant_prompt_version || - "${(pj:\x1f:)__p9k_used_instant_prompt}" != "${(e)_p9k_instant_prompt}" ) ]]; then + elif [[ $_p9k__instant_prompt_disabled == 0 && + "${(pj:\x1f:)__p9k_used_instant_prompt}" != "${(e)_p9k_instant_prompt}" ]]; then _p9k_dump_instant_prompt if (( ! $+_p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig] )); then _p9k_dump_state @@ -3918,10 +3987,10 @@ _p9k_precmd_impl() { _p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]=1 fi fi - elif (( _p9k__state_dump_scheduled || ! (_POWERLEVEL9K_DISABLE_INSTANT_PROMPT || $+_p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]) )); then + elif (( _p9k__state_dump_scheduled || ! (_p9k__instant_prompt_disabled || $+_p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]) )); then setopt no_bg_nice ( - if ! (( _POWERLEVEL9K_DISABLE_INSTANT_PROMPT || $+_p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig] )); then + if ! (( _p9k__instant_prompt_disabled || $+_p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig] )); then _p9k_set_instant_prompt _p9k_dump_instant_prompt _p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]=1 @@ -3930,7 +3999,7 @@ _p9k_precmd_impl() { ) &! _p9k__dump_pid=$! _p9k__state_dump_scheduled=0 - (( _POWERLEVEL9K_DISABLE_INSTANT_PROMPT )) || _p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]=1 + (( _p9k__instant_prompt_disabled )) || _p9k_dumped_instant_prompt_sigs[$_p9k__instant_prompt_sig]=1 fi fi } @@ -4139,6 +4208,7 @@ function _p9k_prompt_overflow_bug() { } _p9k_init_vars() { + typeset -gi _p9k__instant_prompt_disabled typeset -gi _p9k_non_hermetic_expansion typeset -g _p9k_time typeset -g _p9k_date @@ -4248,7 +4318,20 @@ _p9k_init_vars() { } _p9k_init_params() { - _p9k_declare -b POWERLEVEL9K_DISABLE_INSTANT_PROMPT 0 + # invarint: _POWERLEVEL9K_INSTANT_PROMPT == (verbose|quiet|off) + # invariant: [[ ($_POWERLEVEL9K_INSTANT_PROMPT == off) == $_POWERLEVEL9K_DISABLE_INSTANT_PROMPT ]] + _p9k_declare -s POWERLEVEL9K_INSTANT_PROMPT # verbose, quiet, off + if [[ $_POWERLEVEL9K_INSTANT_PROMPT == off ]]; then + typeset -gi _POWERLEVEL9K_DISABLE_INSTANT_PROMPT=1 + else + _p9k_declare -b POWERLEVEL9K_DISABLE_INSTANT_PROMPT 0 + if (( _POWERLEVEL9K_DISABLE_INSTANT_PROMPT )); then + _POWERLEVEL9K_INSTANT_PROMPT=off + elif [[ $_POWERLEVEL9K_INSTANT_PROMPT != quiet ]]; then + _POWERLEVEL9K_INSTANT_PROMPT=verbose + fi + fi + _p9k_declare -i POWERLEVEL9K_INSTANT_PROMPT_COMMAND_LINES 3 _p9k_declare -a POWERLEVEL9K_LEFT_PROMPT_ELEMENTS -- context dir vcs _p9k_declare -a POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS -- status root_indicator background_jobs history time @@ -4854,7 +4937,7 @@ _p9k_must_init() { '${GITSTATUS_ENABLE_LOGGING}' '${GITSTATUS_DAEMON}' '${GITSTATUS_NUM_THREADS}' '${DEFAULT_USER}' '${ZLE_RPROMPT_INDENT}' '${P9K_SSH}' '${__p9k_ksh_arrays}' '${__p9k_sh_glob}' '${options[transient_rprompt]}' '${ITERM_SHELL_INTEGRATION_INSTALLED}' - '${PROMPT_EOL_MARK}' '${LANG}' '${LC_ALL}' '${LC_CTYPE}' '${+VTE_VERSION}' 'vb') + '${PROMPT_EOL_MARK}' '${LANG}' '${LC_ALL}' '${LC_CTYPE}' 'vc') IFS=$'\2' param_sig="${(e)param_sig}" [[ $param_sig == $_p9k__param_sig ]] && return 1 [[ -n $_p9k__param_sig ]] && _p9k_deinit @@ -5145,7 +5228,7 @@ _p9k_init() { if (( _POWERLEVEL9K_DISABLE_INSTANT_PROMPT )); then unset __p9k_instant_prompt_erased - zf_rm -f -- $root_dir/p10k-instant-prompt-$user.zsh{,.zwc} 2>/dev/null + zf_rm -f -- ${__p9k_dump_file:h}/p10k-instant-prompt-${(%):-%n}.zsh{,.zwc} 2>/dev/null fi if (( $+__p9k_instant_prompt_erased )); then @@ -5164,10 +5247,10 @@ _p9k_init() { >&2 echo -E - "${(%):- * You %Bwill not%b see this error message again.}" >&2 echo -E - "${(%):- * Zsh will start %Bquickly%b.}" >&2 echo -E - "" - >&2 echo -E - "${(%):- - Set %BPOWERLEVEL9K_DISABLE_INSTANT_PROMPT=true%b at the bottom of %B$__p9k_zshrc_u%b.}" - >&2 echo -E - "${(%):- You can do this by running the following command:}" + >&2 echo -E - "${(%):- - Disable instant prompt either by running %Bp10k configure%b or by manually}" + >&2 echo -E - "${(%):- defining the following parameter:}" >&2 echo -E - "" - >&2 echo -E - "${(%):- %2Fecho%f %3F'POWERLEVEL9K_DISABLE_INSTANT_PROMPT=true'%f >>! $__p9k_zshrc_u}" + >&2 echo -E - "${(%):- %3Ftypeset%f -g POWERLEVEL9K_INSTANT_PROMPT=off}" >&2 echo -E - "" >&2 echo -E - "${(%):- * You %Bwill not%b see this error message again.}" >&2 echo -E - "${(%):- * Zsh will start %Bslowly%b.}" @@ -5310,7 +5393,13 @@ typeset -gr __p9k_p10k_configure_usage="Usage: %2Fp10k%f %Bconfigure%b Run interactive configuration wizard." +typeset -gr __p9k_p10k_finalize_usage="Usage: %2Fp10k%f %Bfinalize%b + +Perform the final stage of initialization. Must be called at the very end of zshrc." + function p10k() { + [[ $# != 1 || $1 != finalize ]] || { p10k-instant-prompt-finalize; return } + emulate -L zsh setopt no_hist_expand extended_glob prompt_percent prompt_subst no_aliases @@ -5379,6 +5468,10 @@ function p10k() { return 1 fi ;; + finalize) + print -rP -- $__p9k_p10k_finalize_usage >&2 + return 1 + ;; *) print -rP -- $__p9k_p10k_usage >&2 return 1 @@ -5407,5 +5500,9 @@ if [[ $__p9k_dump_file != $__p9k_instant_prompt_dump_file && -n $__p9k_instant_p zf_rm -f $__p9k_instant_prompt_dump_file 2>/dev/null fi +if [[ $+__p9k_instant_prompt_sourced == 1 && $__p9k_instant_prompt_sourced != $__p9k_instant_prompt_version ]]; then + zf_rm -f -- ${__p9k_dump_file:h}/p10k-instant-prompt-${(%):-%n}.zsh{,.zwc} 2>/dev/null +fi + _p9k_init_ssh prompt_powerlevel9k_setup diff --git a/internal/wizard.zsh b/internal/wizard.zsh index f2e0b927..b483b4bb 100755 --- a/internal/wizard.zsh +++ b/internal/wizard.zsh @@ -1213,6 +1213,50 @@ function ask_empty_line() { done } +function ask_instant_prompt() { + autoload -Uz is-at-least + if ! is-at-least 5.4; then + instant_prompt=off + return + fi + if (( LINES < 24 )); then + local nl='' + else + local nl=$'\n' + fi + while true; do + clear + flowing -c "%BInstant Prompt Mode%b" + print -n $nl + flowing -c "$(href 'https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt')" + print -P "" + flowing +c -i 5 "%B(1) Off.%b" Disable instant prompt. Choose this if you\'ve tried instant \ + prompt and found it incompatible with your zsh configuration files. + print -n $nl + flowing +c -i 5 "%B(2) Quiet.%b" Enable instant prompt and %Bdon\'t print warnings%b when \ + detecting console output during zsh initialization. Choose this if you\'ve read and \ + understood the documentation linked above. + print -n $nl + flowing +c -i 5 "%B(3) Verbose.%b" Enable instant prompt and %Bprint a warning%b when \ + detecting console output during zsh initialization. Choose this if you\'ve never tried \ + instant prompt, haven\'t seen the warning, or if you are unsure what this all means. + print -P "" + print -P "(r) Restart from the beginning." + print -P "(q) Quit and do nothing." + print -P "" + + local key= + read -k key${(%):-"?%BChoice [123rq]: %b"} || quit -c + case $key in + q) quit;; + r) return 1;; + 1) instant_prompt=off; break;; + 2) instant_prompt=quiet; break;; + 3) instant_prompt=verbose; break;; + esac + done +} + function ask_confirm() { while true; do clear @@ -1275,10 +1319,11 @@ function ask_zshrc_edit() { zshrc_backup= zshrc_backup_u= zshrc_has_cfg=0 - zshrc_has_pre=1 - zshrc_has_post=1 + zshrc_has_instant_prompt=0 write_zshrc=0 + [[ $instant_prompt == off ]] && zshrc_has_instant_prompt=1 + if [[ -e $__p9k_zshrc ]]; then zshrc_content="$(<$__p9k_zshrc)" || quit -c local lines=(${(f)zshrc_content}) @@ -1293,12 +1338,9 @@ function ask_zshrc_edit() { fi local pre='${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh' if [[ -n ${(@M)lines:#(#b)[^#]#([^[:IDENT:]]|)source[[:space:]]##($pre|\"$pre\")(|[[:space:]]*|'#'*)} ]]; then - zshrc_has_pre=1 + zshrc_has_instant_prompt=1 fi - if [[ -n ${(@M)lines:#(#b)[^#]#([^[:IDENT:]]|)p10k-instant-prompt-finalize([^[:IDENT:]]*|)} ]]; then - zshrc_has_post=1 - fi - (( zshrc_has_cfg && zshrc_has_pre && zshrc_has_post )) && return + (( zshrc_has_cfg && zshrc_has_instant_prompt )) && return fi while true; do @@ -1487,6 +1529,8 @@ function generate_config() { (( empty_line )) && sub PROMPT_ADD_NEWLINE true || sub PROMPT_ADD_NEWLINE false + sub INSTANT_PROMPT $instant_prompt + local header=${(%):-"# Generated by Powerlevel10k configuration wizard on %D{%Y-%m-%d at %H:%M %Z}."}$'\n' header+="# Based on romkatv/powerlevel10k/config/p10k-$style.zsh" if [[ $commands[sum] == ('/bin'|'/usr/bin'|'/usr/local/bin')'/sum' ]]; then @@ -1525,25 +1569,22 @@ function change_zshrc() { { print -n >$tmp || return - if (( !zshrc_has_pre )); then - >>$tmp print -r -- "# Enable Powerlevel10k instant prompt. Should stay at the top of ${(%)__p9k_zshrc_u}. + if (( !zshrc_has_instant_prompt )); then + >>$tmp print -r -- "# Enable Powerlevel10k instant prompt. Should stay close to the top of ${(%)__p9k_zshrc_u}. +# Initialization code that may require console input (password prompts, [y/n] +# confirmations, etc.) must go above this block, everything else must go below. if [[ -r \"\${XDG_CACHE_HOME:-\$HOME/.cache}/p10k-instant-prompt-\${(%):-%n}.zsh\" ]]; then source \"\${XDG_CACHE_HOME:-\$HOME/.cache}/p10k-instant-prompt-\${(%):-%n}.zsh\" fi" || return fi if [[ -n $zshrc_content ]]; then - (( zshrc_has_pre )) || print >>$tmp || return + (( zshrc_has_instant_prompt )) || print >>$tmp || return >>$tmp print -r -- $zshrc_content || return fi if (( !zshrc_has_cfg )); then >>$tmp print -r -- " # To customize prompt, run \`p10k configure\` or edit ${(%)__p9k_cfg_path_u}. [[ ! -f ${(%)__p9k_cfg_path_u} ]] || source ${(%)__p9k_cfg_path_u}" || return - fi - if (( !zshrc_has_post )); then - >>$tmp print -r -- " -# Finalize Powerlevel10k instant prompt. Should stay at the bottom of ${(%)__p9k_zshrc_u}. -(( ! \${+functions[p10k-instant-prompt-finalize]} )) || p10k-instant-prompt-finalize" || return fi zf_mv -f -- $tmp $__p9k_zshrc || return } always { @@ -1568,8 +1609,8 @@ fi source $__p9k_root_dir/internal/icons.zsh || return while true; do - local zshrc_content= zshrc_backup= zshrc_backup_u= - local -i zshrc_has_cfg=0 zshrc_has_pre=0 zshrc_has_post=0 write_zshrc=0 + local instant_prompt=verbose zshrc_content= zshrc_backup= zshrc_backup_u= + local -i zshrc_has_cfg=0 zshrc_has_instant_prompt=0 write_zshrc=0 local POWERLEVEL9K_MODE= style= config_backup= config_backup_u= gap_char=' ' local left_subsep= right_subsep= left_tail= right_tail= left_head= right_head= show_time= local -i num_lines=0 empty_line=0 color=2 left_frame=1 right_frame=1 @@ -1649,6 +1690,7 @@ while true; do ask_prefixes || continue fi ask_confirm || continue + ask_instant_prompt || continue ask_config_overwrite || continue ask_zshrc_edit || continue break