Merge remote-tracking branch 'source/master'

This commit is contained in:
2017-02-07 13:58:54 +01:00
6 changed files with 450 additions and 178 deletions

156
pure.zsh
View File

@@ -61,30 +61,10 @@ prompt_pure_clear_screen() {
prompt_pure_preprompt_render precmd
}
prompt_pure_check_git_arrows() {
# reset git arrows
prompt_pure_git_arrows=
# check if there is an upstream configured for this branch
command git rev-parse --abbrev-ref @'{u}' &>/dev/null || return
local arrow_status
# check git left and right arrow_status
arrow_status="$(command git rev-list --left-right --count HEAD...@'{u}' 2>/dev/null)"
# exit if the command failed
(( !$? )) || return
# left and right are tab-separated, split on tab and store as array
arrow_status=(${(ps:\t:)arrow_status})
local arrows left=${arrow_status[1]} right=${arrow_status[2]}
(( ${right:-0} > 0 )) && arrows+="${PURE_GIT_DOWN_ARROW:-}"
(( ${left:-0} > 0 )) && arrows+="${PURE_GIT_UP_ARROW:-}"
[[ -n $arrows ]] && prompt_pure_git_arrows=" ${arrows}"
}
prompt_pure_set_title() {
# emacs terminal does not support settings the title
(( ${+EMACS} )) && return
# tell the terminal we are setting the title
print -n '\e]0;'
# show hostname if connected through ssh
@@ -120,6 +100,12 @@ prompt_pure_string_length_to_var() {
}
prompt_pure_preprompt_render() {
# store the current prompt_subst setting so that it can be restored later
local prompt_subst_status=$options[prompt_subst]
# make sure prompt_subst is unset to prevent parameter expansion in preprompt
setopt local_options no_prompt_subst
# check that no command is currently running, the preprompt will otherwise be rendered in the wrong place
[[ -n ${prompt_pure_cmd_timestamp+x} && "$1" != "precmd" ]] && return
@@ -138,12 +124,15 @@ prompt_pure_preprompt_render() {
# execution time
preprompt+="%F{yellow}${prompt_pure_cmd_exec_time}%f"
# make sure prompt_pure_last_preprompt is a global array
typeset -g -a prompt_pure_last_preprompt
# if executing through precmd, do not perform fancy terminal editing
if [[ "$1" == "precmd" ]]; then
print -P "${preprompt}"
else
# only redraw if preprompt has changed
[[ "${prompt_pure_last_preprompt}" != "${preprompt}" ]] || return
# only redraw if the expanded preprompt has changed
[[ "${prompt_pure_last_preprompt[2]}" != "${(S%%)preprompt}" ]] || return
# calculate length of preprompt and store it locally in preprompt_length
integer preprompt_length lines
@@ -154,7 +143,7 @@ prompt_pure_preprompt_render() {
# calculate previous preprompt lines to figure out how the new preprompt should behave
integer last_preprompt_length last_lines
prompt_pure_string_length_to_var "${prompt_pure_last_preprompt}" "last_preprompt_length"
prompt_pure_string_length_to_var "${prompt_pure_last_preprompt[1]}" "last_preprompt_length"
(( last_lines = ( last_preprompt_length - 1 ) / COLUMNS + 1 ))
# clr_prev_preprompt erases visual artifacts from previous preprompt
@@ -174,9 +163,6 @@ prompt_pure_preprompt_render() {
elif (( last_lines < lines )); then
# move cursor using newlines because ansi cursor movement can't push the cursor beyond the last line
printf $'\n'%.0s {1..$(( lines - last_lines ))}
# redraw the prompt since it has been moved by print
zle && zle .reset-prompt
fi
# disable clearing of line if last char of preprompt is last column of terminal
@@ -184,11 +170,19 @@ prompt_pure_preprompt_render() {
(( COLUMNS * lines == preprompt_length )) && clr=
# modify previous preprompt
print -Pn "\e7${clr_prev_preprompt}\e[${lines}A\e[1G${preprompt}${clr}\e8"
print -Pn "${clr_prev_preprompt}\e[${lines}A\e[${COLUMNS}D${preprompt}${clr}\n"
if [[ $prompt_subst_status = 'on' ]]; then
# re-eanble prompt_subst for expansion on PS1
setopt prompt_subst
fi
# redraw prompt (also resets cursor position)
zle && zle .reset-prompt
fi
# store previous preprompt for comparison
prompt_pure_last_preprompt=$preprompt
# store both unexpanded and expanded preprompt for comparison
prompt_pure_last_preprompt=("$preprompt" "${(S%%)preprompt}")
}
prompt_pure_precmd() {
@@ -199,9 +193,6 @@ prompt_pure_precmd() {
# with the initial preprompt rendering
prompt_pure_cmd_timestamp=
# check for git arrows
prompt_pure_check_git_arrows
# shows the full path in the title
prompt_pure_set_title 'expand-prompt' '%~'
@@ -220,29 +211,46 @@ prompt_pure_precmd() {
# fastest possible way to check if repo is dirty
prompt_pure_async_git_dirty() {
local untracked_dirty=$1; shift
setopt localoptions noshwordsplit
local untracked_dirty=$1 dir=$2
# use cd -q to avoid side effects of changing directory, e.g. chpwd hooks
cd -q "$*"
builtin cd -q $dir
if [[ "$untracked_dirty" == "0" ]]; then
if [[ $untracked_dirty = 0 ]]; then
command git diff --no-ext-diff --quiet --exit-code
else
test -z "$(command git status --porcelain --ignore-submodules -unormal)"
fi
(( $? )) && echo "%F{red}*%f"
return $?
}
prompt_pure_async_git_fetch() {
setopt localoptions noshwordsplit
# use cd -q to avoid side effects of changing directory, e.g. chpwd hooks
cd -q "$*"
builtin cd -q $1
# set GIT_TERMINAL_PROMPT=0 to disable auth prompting for git fetch (git 2.3+)
GIT_TERMINAL_PROMPT=0 command git -c gc.auto=0 fetch
export GIT_TERMINAL_PROMPT=0
# set ssh BachMode to disable all interactive ssh password prompting
export GIT_SSH_COMMAND=${GIT_SSH_COMMAND:-"ssh -o BatchMode=yes"}
command git -c gc.auto=0 fetch &>/dev/null || return 1
# check arrow status after a successful git fetch
prompt_pure_async_git_arrows $1
}
prompt_pure_async_git_arrows() {
setopt localoptions noshwordsplit
builtin cd -q $1
command git rev-list --left-right --count HEAD...@'{u}'
}
prompt_pure_async_tasks() {
setopt localoptions noshwordsplit
# initialize async worker
((!${prompt_pure_async_init:-0})) && {
async_start_worker "prompt_pure" -u -n
@@ -261,6 +269,7 @@ prompt_pure_async_tasks() {
# reset git preprompt variables, switching working tree
unset prompt_pure_git_dirty
unset prompt_pure_git_last_dirty_check_timestamp
prompt_pure_git_arrows=
# set the new working tree and prefix with "x" to prevent the creation of a named path by AUTO_NAME_DIRS
prompt_pure_current_working_tree="x${working_tree}"
@@ -269,10 +278,12 @@ prompt_pure_async_tasks() {
# only perform tasks inside git working tree
[[ -n $working_tree ]] || return
async_job "prompt_pure" prompt_pure_async_git_arrows $working_tree
# do not preform git fetch if it is disabled or working_tree == HOME
if (( ${PURE_GIT_PULL:-1} )) && [[ $working_tree != $HOME ]]; then
# tell worker to do a git fetch
async_job "prompt_pure" prompt_pure_async_git_fetch "${working_tree}"
async_job "prompt_pure" prompt_pure_async_git_fetch $working_tree
fi
# if dirty checking is sufficiently fast, tell worker to check it again, or wait for timeout
@@ -280,41 +291,76 @@ prompt_pure_async_tasks() {
if (( time_since_last_dirty_check > ${PURE_GIT_DELAY_DIRTY_CHECK:-1800} )); then
unset prompt_pure_git_last_dirty_check_timestamp
# check check if there is anything to pull
async_job "prompt_pure" prompt_pure_async_git_dirty "${PURE_GIT_UNTRACKED_DIRTY:-1}" "${working_tree}"
async_job "prompt_pure" prompt_pure_async_git_dirty ${PURE_GIT_UNTRACKED_DIRTY:-1} $working_tree
fi
}
prompt_pure_async_callback() {
local job=$1
local output=$3
local exec_time=$4
prompt_pure_check_git_arrows() {
setopt localoptions noshwordsplit
local arrows left=${1:-0} right=${2:-0}
case "${job}" in
(( right > 0 )) && arrows+=${PURE_GIT_DOWN_ARROW:-}
(( left > 0 )) && arrows+=${PURE_GIT_UP_ARROW:-}
[[ -n $arrows ]] || return
typeset -g REPLY=" $arrows"
}
prompt_pure_async_callback() {
setopt localoptions noshwordsplit
local job=$1 code=$2 output=$3 exec_time=$4
case $job in
prompt_pure_async_git_dirty)
prompt_pure_git_dirty=$output
prompt_pure_preprompt_render
local prev_dirty=$prompt_pure_git_dirty
if (( code == 0 )); then
prompt_pure_git_dirty=
else
prompt_pure_git_dirty="%F{red}*%f"
fi
[[ $prev_dirty != $prompt_pure_git_dirty ]] && prompt_pure_preprompt_render
# When prompt_pure_git_last_dirty_check_timestamp is set, the git info is displayed in a different color.
# To distinguish between a "fresh" and a "cached" result, the preprompt is rendered before setting this
# variable. Thus, only upon next rendering of the preprompt will the result appear in a different color.
(( $exec_time > 2 )) && prompt_pure_git_last_dirty_check_timestamp=$EPOCHSECONDS
;;
prompt_pure_async_git_fetch)
prompt_pure_check_git_arrows
prompt_pure_preprompt_render
prompt_pure_async_git_fetch|prompt_pure_async_git_arrows)
# prompt_pure_async_git_fetch executes prompt_pure_async_git_arrows
# after a successful fetch.
if (( code == 0 )); then
local REPLY
prompt_pure_check_git_arrows ${(ps:\t:)output}
if [[ $prompt_pure_git_arrows != $REPLY ]]; then
prompt_pure_git_arrows=$REPLY
prompt_pure_preprompt_render
fi
fi
;;
esac
}
prompt_pure_setup() {
local autoload_name=$1; shift
# prevent percentage showing up
# if output doesn't end with a newline
export PROMPT_EOL_MARK=''
prompt_opts=(subst percent)
# if autoload_name or eval context differ, pure wasn't autoloaded via
# promptinit and we need to take care of setting the options ourselves
if [[ $autoload_name != prompt_pure_setup ]] || [[ $zsh_eval_context[-2] != loadautofunc ]]; then
# borrowed from `promptinit`, set the pure prompt options
setopt noprompt{bang,cr,percent,subst} "prompt${^prompt_opts[@]}"
fi
zmodload zsh/datetime
zmodload zsh/zle
zmodload zsh/parameter
autoload -Uz add-zsh-hook
autoload -Uz vcs_info
autoload -Uz async && async
@@ -345,7 +391,7 @@ prompt_pure_setup() {
[[ $UID -eq 0 ]] && prompt_pure_username=' %F{white}%n%f%F{242}@%m%f'
# prompt turns red if the previous command didn't exit with 0
PROMPT="%(?.%F{magenta}.%F{red})${PURE_PROMPT_SYMBOL:-}%f "
PROMPT='%(?.%F{magenta}.%F{red})${PURE_PROMPT_SYMBOL:-}%f '
}
prompt_pure_setup "$@"
prompt_pure_setup "$0" "$@"