diff --git a/impure.zsh b/impure.zsh index 286d05e..91fdd8d 100644 --- a/impure.zsh +++ b/impure.zsh @@ -253,21 +253,28 @@ prompt_impure_preprompt_render() { typeset -g prompt_impure_last_prompt=$prompt_fingerprint } +# Instant prompt cleanup: restore fds, replay captured output, redraw prompt. +# Validates fds before use to prevent errors if they were closed externally. +prompt_impure_instant_prompt_cleanup() { + (( ${IMPURE_INSTANT_PROMPT_ACTIVE:-0} )) || return 0 + typeset -g IMPURE_INSTANT_PROMPT_ACTIVE=0 + if (( ${IMPURE_IP_FD_1:-0} )) && { true >&${IMPURE_IP_FD_1} } 2>/dev/null; then + exec 1>&${IMPURE_IP_FD_1} 2>&${IMPURE_IP_FD_2} \ + {IMPURE_IP_FD_1}>&- {IMPURE_IP_FD_2}>&- + fi + if [[ -s "${IMPURE_IP_OUTPUT_FILE:-}" ]]; then + cat "$IMPURE_IP_OUTPUT_FILE" 2>/dev/null + fi + rm -f "${IMPURE_IP_OUTPUT_FILE:-}" 2>/dev/null + unset IMPURE_IP_FD_1 IMPURE_IP_FD_2 IMPURE_IP_OUTPUT_FILE + prompt_impure_reset_prompt +} + prompt_impure_precmd() { setopt localoptions noshwordsplit - # Instant prompt cleanup: restore fds, replay output, enrich with git/jj data. - if (( ${IMPURE_INSTANT_PROMPT_ACTIVE:-0} )); then - typeset -g IMPURE_INSTANT_PROMPT_ACTIVE=0 - exec 1>&${IMPURE_IP_FD_1} 2>&${IMPURE_IP_FD_2} \ - {IMPURE_IP_FD_1}>&- {IMPURE_IP_FD_2}>&- 2>/dev/null - if [[ -s "$IMPURE_IP_OUTPUT_FILE" ]]; then - cat "$IMPURE_IP_OUTPUT_FILE" 2>/dev/null - fi - rm -f "$IMPURE_IP_OUTPUT_FILE" 2>/dev/null - unset IMPURE_IP_FD_1 IMPURE_IP_FD_2 IMPURE_IP_OUTPUT_FILE - prompt_impure_reset_prompt - fi + # Clean up instant prompt if active. + prompt_impure_instant_prompt_cleanup # Check execution time and store it in a variable. prompt_impure_check_cmd_exec_time diff --git a/instant-prompt.zsh b/instant-prompt.zsh index 1799bbc..a47ca47 100644 --- a/instant-prompt.zsh +++ b/instant-prompt.zsh @@ -5,31 +5,35 @@ [[ -o interactive && -o zle ]] || return [[ -t 0 && -t 1 && -t 2 ]] || return -# Build minimal prompt: path + newline + prompt symbol. -local _ip_dir="$PWD" -local _ip_ssh= -[[ -n "$SSH_CLIENT$SSH_TTY$SSH_CONNECTION" ]] && _ip_ssh="${(%):-%m} " -local _ip_minimal="${_ip_ssh}${_ip_dir}"$'\n'"❯ " +() { + # Build minimal prompt: path + newline + prompt symbol. + local dir="$PWD" + local ssh= + [[ -n "$SSH_CLIENT$SSH_TTY$SSH_CONNECTION" ]] && ssh="${(%):-%m} " + local minimal="${ssh}${dir}"$'\n'"❯ " -# Print with terminal reset + cursor save + bracketed paste (p10k-compatible format). -zmodload zsh/terminfo 2>/dev/null -print -rn -- "${(%):-%b%k%f%s%u}${terminfo[sc]}${_ip_minimal}"$'\e[?2004h' + # Print with terminal reset + cursor save (p10k-compatible format). + zmodload zsh/terminfo 2>/dev/null + if (( $+terminfo[sc] )); then + print -rn -- "${(%):-%b%k%f%s%u}${terminfo[sc]}${minimal}" + else + print -rn -- "${(%):-%b%k%f%s%u}${minimal}" + fi -# Set PROMPT so ZLE's first render matches (no flicker). -PROMPT="$_ip_minimal" -RPROMPT='' + # Set PROMPT so ZLE's first render matches (no flicker). + PROMPT="$minimal" + RPROMPT='' -# Signal that instant prompt is active for cleanup on first precmd. -typeset -g IMPURE_INSTANT_PROMPT_ACTIVE=1 + # Signal that instant prompt is active for cleanup on first precmd. + typeset -g IMPURE_INSTANT_PROMPT_ACTIVE=1 -# Redirect stdout/stderr during init to prevent output smearing over the prompt. -# Uses sysopen (like p10k) for robust fd management. -zmodload zsh/system 2>/dev/null -typeset -g IMPURE_IP_OUTPUT_FILE="${TMPDIR:-/tmp}/impure-ip-output-$$" -{ : > "$IMPURE_IP_OUTPUT_FILE" } 2>/dev/null || return -local _ip_fd_null -sysopen -ru _ip_fd_null /dev/null 2>/dev/null || return -exec {IMPURE_IP_FD_1}>&1 {IMPURE_IP_FD_2}>&2 0<&$_ip_fd_null 1>"$IMPURE_IP_OUTPUT_FILE" -exec 2>&1 {_ip_fd_null}>&- - -unset _ip_dir _ip_ssh _ip_minimal _ip_fd_null + # Redirect stdout/stderr during init to prevent output smearing over the prompt. + # Uses sysopen (like p10k) for robust fd management. + zmodload zsh/system 2>/dev/null || return + typeset -g IMPURE_IP_OUTPUT_FILE="${TMPDIR:-/tmp}/impure-ip-output-$$" + { : > "$IMPURE_IP_OUTPUT_FILE" } 2>/dev/null || return + local fd_null + sysopen -ru fd_null /dev/null 2>/dev/null || return + exec {IMPURE_IP_FD_1}>&1 {IMPURE_IP_FD_2}>&2 0<&$fd_null 1>"$IMPURE_IP_OUTPUT_FILE" + exec 2>&1 {fd_null}>&- +}