Merge pull request #149 from mafredri/pure-nitro

Refactor to avoid subshell usage, prefer variables
This commit is contained in:
Sindre Sorhus
2015-07-27 23:14:24 +02:00

116
pure.zsh
View File

@@ -26,25 +26,29 @@
# turns seconds into human readable time # turns seconds into human readable time
# 165392 => 1d 21h 56m 32s # 165392 => 1d 21h 56m 32s
# https://github.com/sindresorhus/pretty-time-zsh # https://github.com/sindresorhus/pretty-time-zsh
prompt_pure_human_time() { prompt_pure_human_time_to_var() {
echo -n " " local human=" " total_seconds=$1 var=$2
local tmp=$1 local days=$(( total_seconds / 60 / 60 / 24 ))
local days=$(( tmp / 60 / 60 / 24 )) local hours=$(( total_seconds / 60 / 60 % 24 ))
local hours=$(( tmp / 60 / 60 % 24 )) local minutes=$(( total_seconds / 60 % 60 ))
local minutes=$(( tmp / 60 % 60 )) local seconds=$(( total_seconds % 60 ))
local seconds=$(( tmp % 60 )) (( days > 0 )) && human+="${days}d "
(( $days > 0 )) && echo -n "${days}d " (( hours > 0 )) && human+="${hours}h "
(( $hours > 0 )) && echo -n "${hours}h " (( minutes > 0 )) && human+="${minutes}m "
(( $minutes > 0 )) && echo -n "${minutes}m " human+="${seconds}s"
echo "${seconds}s"
# store human readable time in variable as specified by caller
typeset -g "${var}"="${human}"
} }
# displays the exec time of the last command if set threshold was exceeded # stores (into prompt_pure_cmd_exec_time) the exec time of the last command if set threshold was exceeded
prompt_pure_check_cmd_exec_time() { prompt_pure_check_cmd_exec_time() {
local stop=$EPOCHSECONDS integer elapsed
local start=${prompt_pure_cmd_timestamp:-$stop} (( elapsed = EPOCHSECONDS - ${prompt_pure_cmd_timestamp:-$EPOCHSECONDS} ))
integer elapsed=$stop-$start prompt_pure_cmd_exec_time=
(($elapsed > ${PURE_CMD_MAX_EXEC_TIME:=5})) && prompt_pure_human_time $elapsed (( elapsed > ${PURE_CMD_MAX_EXEC_TIME:=5} )) && {
prompt_pure_human_time_to_var $elapsed "prompt_pure_cmd_exec_time"
}
} }
prompt_pure_clear_screen() { prompt_pure_clear_screen() {
@@ -57,17 +61,26 @@ prompt_pure_clear_screen() {
} }
prompt_pure_check_git_arrows() { prompt_pure_check_git_arrows() {
# reset git arrows
prompt_pure_git_arrows=
# check if there is an upstream configured for this branch # check if there is an upstream configured for this branch
command git rev-parse --abbrev-ref @'{u}' &>/dev/null || return command git rev-parse --abbrev-ref @'{u}' &>/dev/null || return
local right left arrows local arrow_status
right=$(command git rev-list --right-only --count HEAD...@'{u}' 2>/dev/null) # check git left and right arrow_status
left=$(command git rev-list --left-only --count HEAD...@'{u}' 2>/dev/null) arrow_status="$(command git rev-list --left-right --count HEAD...@'{u}' 2>/dev/null)"
# exit if the command failed
(( !$? )) || return
(( ${right:-0} > 0 )) && arrows="${PURE_GIT_DOWN_ARROW:-}" # 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:-}" (( ${left:-0} > 0 )) && arrows+="${PURE_GIT_UP_ARROW:-}"
# output the arrows
[[ $arrows != "" ]] && echo " ${arrows}" [[ -n $arrows ]] && prompt_pure_git_arrows=" ${arrows}"
} }
prompt_pure_preexec() { prompt_pure_preexec() {
@@ -84,8 +97,13 @@ prompt_pure_preexec() {
} }
# string length ignoring ansi escapes # string length ignoring ansi escapes
prompt_pure_string_length() { prompt_pure_string_length_to_var() {
echo $(( ${#${(S%%)1//(\%([KF1]|)\{*\}|\%[Bbkf])}} )) local str=$1 var=$2 length
# perform expansion on str and check length
length=$(( ${#${(S%%)str//(\%([KF1]|)\{*\}|\%[Bbkf])}} ))
# store string length in variable as specified by caller
typeset -g "${var}"="${length}"
} }
prompt_pure_preprompt_render() { prompt_pure_preprompt_render() {
@@ -114,13 +132,16 @@ prompt_pure_preprompt_render() {
# only redraw if preprompt has changed # only redraw if preprompt has changed
[[ "${prompt_pure_last_preprompt}" != "${preprompt}" ]] || return [[ "${prompt_pure_last_preprompt}" != "${preprompt}" ]] || return
# calculate length of preprompt for redraw purposes # calculate length of preprompt and store it locally in preprompt_length
local preprompt_length=$(prompt_pure_string_length $preprompt) integer preprompt_length
local lines=$(( ($preprompt_length - 1) / $COLUMNS + 1 )) prompt_pure_string_length_to_var "${preprompt}" "preprompt_length"
# calculate number of preprompt lines for redraw purposes
integer lines=$(( (preprompt_length - 1) / COLUMNS + 1 ))
# disable clearing of line if last char of preprompt is last column of terminal # disable clearing of line if last char of preprompt is last column of terminal
local clr="\e[K" local clr='\e[K'
(( $COLUMNS * $lines == $preprompt_length )) && clr="" (( COLUMNS * lines == preprompt_length )) && clr=
# modify previous preprompt # modify previous preprompt
print -Pn "\e7\e[${lines}A\e[1G${preprompt}${clr}\e8" print -Pn "\e7\e[${lines}A\e[1G${preprompt}${clr}\e8"
@@ -131,15 +152,15 @@ prompt_pure_preprompt_render() {
} }
prompt_pure_precmd() { prompt_pure_precmd() {
# store exec time for when preprompt gets re-rendered # check exec time and store it in a variable
prompt_pure_cmd_exec_time=$(prompt_pure_check_cmd_exec_time) prompt_pure_check_cmd_exec_time
# by making sure that prompt_pure_cmd_timestamp is defined here the async functions are prevented from interfering # by making sure that prompt_pure_cmd_timestamp is defined here the async functions are prevented from interfering
# with the initial preprompt rendering # with the initial preprompt rendering
prompt_pure_cmd_timestamp= prompt_pure_cmd_timestamp=
# check for git arrows # check for git arrows
prompt_pure_git_arrows=$(prompt_pure_check_git_arrows) prompt_pure_check_git_arrows
# tell the terminal we are setting the title # tell the terminal we are setting the title
print -Pn "\e]0;" print -Pn "\e]0;"
@@ -193,11 +214,11 @@ prompt_pure_async_tasks() {
prompt_pure_async_init=1 prompt_pure_async_init=1
} }
# get the current git working tree, empty if not inside a git directory # store working_tree without the "x" prefix
local working_tree="$(command git rev-parse --show-toplevel 2>/dev/null)" local working_tree="${vcs_info_msg_1_#x}"
# check if the working tree changed (prompt_pure_current_working_tree is prefixed by "x") # check if the working tree changed (prompt_pure_current_working_tree is prefixed by "x")
if [[ "${prompt_pure_current_working_tree:-x}" != "x${working_tree}" ]]; then if [[ ${prompt_pure_current_working_tree#x} != $working_tree ]]; then
# stop any running async jobs # stop any running async jobs
async_flush_jobs "prompt_pure" async_flush_jobs "prompt_pure"
@@ -210,21 +231,20 @@ prompt_pure_async_tasks() {
fi fi
# only perform tasks inside git working tree # only perform tasks inside git working tree
[[ "${working_tree}" != "" ]] || return [[ -n $working_tree ]] || return
if (( ${PURE_GIT_PULL:-1} )); then # do not preform git fetch if it is disabled or working_tree == HOME
# make sure working tree is not $HOME if (( ${PURE_GIT_PULL:-1} )) && [[ $working_tree != $HOME ]]; then
[[ "${working_tree}" != "$HOME" ]] &&
# tell worker to do a git fetch # 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 fi
# if dirty checking is sufficiently fast, tell worker to check it again, or wait for timeout # if dirty checking is sufficiently fast, tell worker to check it again, or wait for timeout
local time_since_last_dirty_check=$(( $EPOCHSECONDS - ${prompt_pure_git_last_dirty_check_timestamp:-0} )) integer time_since_last_dirty_check=$(( EPOCHSECONDS - ${prompt_pure_git_last_dirty_check_timestamp:-0} ))
if (( $time_since_last_dirty_check > ${PURE_GIT_DELAY_DIRTY_CHECK:-1800} )); then if (( time_since_last_dirty_check > ${PURE_GIT_DELAY_DIRTY_CHECK:-1800} )); then
unset prompt_pure_git_last_dirty_check_timestamp unset prompt_pure_git_last_dirty_check_timestamp
# check check if there is anything to pull # 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 fi
} }
@@ -244,7 +264,7 @@ prompt_pure_async_callback() {
(( $exec_time > 2 )) && prompt_pure_git_last_dirty_check_timestamp=$EPOCHSECONDS (( $exec_time > 2 )) && prompt_pure_git_last_dirty_check_timestamp=$EPOCHSECONDS
;; ;;
prompt_pure_async_git_fetch) prompt_pure_async_git_fetch)
prompt_pure_git_arrows=$(prompt_pure_check_git_arrows) prompt_pure_check_git_arrows
prompt_pure_preprompt_render prompt_pure_preprompt_render
;; ;;
esac esac
@@ -268,8 +288,12 @@ prompt_pure_setup() {
zstyle ':vcs_info:*' enable git zstyle ':vcs_info:*' enable git
zstyle ':vcs_info:*' use-simple true zstyle ':vcs_info:*' use-simple true
zstyle ':vcs_info:git*' formats ' %b' # only export two msg variables from vcs_info
zstyle ':vcs_info:git*' actionformats ' %b|%a' zstyle ':vcs_info:*' max-exports 2
# vcs_info_msg_0_ = ' %b' (for branch)
# vcs_info_msg_1_ = 'x%R' git top level (%R), x-prefix prevents creation of a named path (AUTO_NAME_DIRS)
zstyle ':vcs_info:git*' formats ' %b' 'x%R'
zstyle ':vcs_info:git*' actionformats ' %b|%a' 'x%R'
# if the user has not registered a custom zle widget for clear-screen, # if the user has not registered a custom zle widget for clear-screen,
# override the builtin one so that the preprompt is displayed correctly when # override the builtin one so that the preprompt is displayed correctly when