about summary refs log tree commit diff
path: root/Functions
diff options
context:
space:
mode:
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Chpwd/cdr2
-rw-r--r--Functions/MIME/zsh-mime-handler2
-rw-r--r--Functions/Misc/add-zle-hook-widget4
-rw-r--r--Functions/Misc/colors28
-rw-r--r--Functions/Misc/is-at-least8
-rw-r--r--Functions/Misc/mkshadow11
-rw-r--r--Functions/Misc/regexp-replace2
-rw-r--r--Functions/Misc/run-help12
-rw-r--r--Functions/Misc/run-help-docker9
-rw-r--r--Functions/Misc/run-help-ip2
-rw-r--r--Functions/Misc/run-help-openssl8
-rw-r--r--Functions/Misc/run-help-perf1
-rw-r--r--Functions/Misc/run-help-podman9
-rw-r--r--Functions/Misc/run-help-ssh6
-rw-r--r--Functions/Misc/run-help-svk1
-rw-r--r--Functions/Misc/run-help-svnadmin1
-rw-r--r--Functions/Misc/zargs73
-rw-r--r--Functions/Misc/zcalc4
-rw-r--r--Functions/Misc/zed14
-rw-r--r--Functions/Misc/zmv8
-rw-r--r--Functions/Misc/zslurp31
-rw-r--r--Functions/Newuser/zsh-newuser-install2
-rw-r--r--Functions/Prompts/prompt_sprint2_setup128
-rw-r--r--Functions/Prompts/promptinit5
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_git51
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_hg8
-rw-r--r--Functions/VCS_Info/VCS_INFO_formats2
-rw-r--r--Functions/VCS_Info/VCS_INFO_patch2subject2
-rw-r--r--Functions/VCS_Info/VCS_INFO_quilt54
-rw-r--r--Functions/VCS_Info/VCS_INFO_set-branch-format2
-rw-r--r--Functions/VCS_Info/VCS_INFO_set-patch-format10
-rwxr-xr-xFunctions/VCS_Info/test-repo-git-rebase-apply12
l---------Functions/VCS_Info/test-repo-git-rebase-merge1
-rw-r--r--Functions/Zle/edit-command-line23
-rw-r--r--Functions/Zle/incarg322
-rw-r--r--Functions/Zle/keeper3
36 files changed, 718 insertions, 143 deletions
diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr
index 4bed88b13..43745e5aa 100644
--- a/Functions/Chpwd/cdr
+++ b/Functions/Chpwd/cdr
@@ -55,7 +55,7 @@
 # pattern from the directory list.  The match is against the fully
 # expanded directory path and the full string must match (use wildcards
 # at the ends if needed).  If output is going to a terminal, the
-# function will print the new list for the user to confrim; this can be
+# function will print the new list for the user to confirm; this can be
 # skipped by giving -P instead of -p.
 #
 # Details of directory handling
diff --git a/Functions/MIME/zsh-mime-handler b/Functions/MIME/zsh-mime-handler
index 288a0796d..2feacf063 100644
--- a/Functions/MIME/zsh-mime-handler
+++ b/Functions/MIME/zsh-mime-handler
@@ -193,7 +193,7 @@ if ! zsh-mime-contexts -s $suffix flags flags; then
   # Same again for flags.
   s=$suffix
   while true; do
-    flags="${zsh_mime_flags[$suffix]}"
+    flags="${zsh_mime_flags[$s]}"
     if [[ -n $flags ]]; then
       break
     fi
diff --git a/Functions/Misc/add-zle-hook-widget b/Functions/Misc/add-zle-hook-widget
index 4d8049083..4293a07dd 100644
--- a/Functions/Misc/add-zle-hook-widget
+++ b/Functions/Misc/add-zle-hook-widget
@@ -39,7 +39,7 @@ zstyle zle-hook types ${hooktypes#zle-}
 
 # Relying on multifuncdef option here
 function azhw:${^hooktypes} {
-    local -a hook_widgets
+    local -a hook_widgets match mbegin mend
     local hook
     # Values of these styles look like number:name
     # and we run them in number order
@@ -58,7 +58,7 @@ function azhw:${^hooktypes} {
 # Redefine ourself with the setup left out
 
 function add-zle-hook-widget {
-    local -a hooktypes
+    local -a hooktypes match mbegin mend
     zstyle -a zle-hook types hooktypes
 
     # This part copied from add-zsh-hook
diff --git a/Functions/Misc/colors b/Functions/Misc/colors
index b221e6688..8a0cec383 100644
--- a/Functions/Misc/colors
+++ b/Functions/Misc/colors
@@ -44,7 +44,7 @@ color=(
   35 magenta                45 bg-magenta
   36 cyan                   46 bg-cyan
   37 white                  47 bg-white
-# 38 iso-8316-6           # 48 bg-iso-8316-6
+# 38 iso-8613-6           # 48 bg-iso-8613-6
   39 default                49 bg-default
 
 # Other codes:
@@ -63,6 +63,16 @@ color=(
 # 63 double-overline-or-left
 # 64 stress
 # 65 no-ideogram-marking
+
+# Bright color codes (xterm extension)
+  90 bright-gray            100 bg-bright-gray
+  91 bright-red             101 bg-bright-red
+  92 bright-green           102 bg-bright-green
+  93 bright-yellow          103 bg-bright-yellow
+  94 bright-blue            104 bg-bright-blue
+  95 bright-magenta         105 bg-bright-magenta
+  96 bright-cyan            106 bg-bright-cyan
+  97 bright-white           107 bg-bright-white
 )
 
 # A word about black and white:  The "normal" shade of white is really a
@@ -79,15 +89,21 @@ for k in ${(k)color}; do color[${color[$k]}]=$k; done
 
 # Add "fg-" keys for all the text colors, for clarity.
 
-for k in ${color[(I)3?]}; do color[fg-${color[$k]}]=$k; done
+for k in ${color[(I)[39]?]}; do color[fg-${color[$k]}]=$k; done
 
 # This is inaccurate, but the prompt theme system needs it.
 
-color[grey]=${color[black]}
-color[fg-grey]=${color[grey]}
-color[bg-grey]=${color[bg-black]}
+for k in grey gray; do
+  color[$k]=${color[black]}
+  color[fg-$k]=${color[$k]}
+  color[bg-$k]=${color[bg-black]}
+done
+
+# Assistance for the colo(u)r-blind.
 
-# Assistance for the color-blind.
+for k in '' fg- bg-; do
+  color[${k}bright-grey]=${color[${k}bright-gray]}
+done
 
 colour=(${(kv)color})	# A case where ksh namerefs would be useful ...
 
diff --git a/Functions/Misc/is-at-least b/Functions/Misc/is-at-least
index d4ff3552a..5985684be 100644
--- a/Functions/Misc/is-at-least
+++ b/Functions/Misc/is-at-least
@@ -24,8 +24,14 @@ emulate -L zsh
 
 local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version order
 
+: ${2=$ZSH_VERSION}
+
+# sort out the easy corner cases first
+[[ $1 = $2 ]] && return 0 # same version
+[[ -n $2 ]] || return 1   # no version
+
 min_ver=(${=1})
-version=(${=2:-$ZSH_VERSION} 0)
+version=(${=2} 0)
 
 while (( $min_cnt <= ${#min_ver} )); do
   while [[ "$part" != <-> ]]; do
diff --git a/Functions/Misc/mkshadow b/Functions/Misc/mkshadow
new file mode 100644
index 000000000..2ae3a0f2c
--- /dev/null
+++ b/Functions/Misc/mkshadow
@@ -0,0 +1,11 @@
+#autoload
+# Front-end to the completion helper _shadow for use outside completion.
+# This just forces proper autoload of _shadow/_unshadow and calls them.
+
+autoload _shadow
+mkshadow() { unset REPLY; _shadow "$@" }
+rmshadow() { unset REPLY; _unshadow }
+
+# Bootstrap because of autoload special case
+unset REPLY
+_shadow "$@"
diff --git a/Functions/Misc/regexp-replace b/Functions/Misc/regexp-replace
index 0d5948075..d4408f0f7 100644
--- a/Functions/Misc/regexp-replace
+++ b/Functions/Misc/regexp-replace
@@ -40,7 +40,7 @@ if (( $4 )); then
     # append offsets and computed replacement to the array
     # we need to perform the evaluation in a scalar assignment so that if
     # it generates an array, the elements are converted to string (by
-    # joining with the first chararacter of $IFS as usual)
+    # joining with the first character of $IFS as usual)
     5=${(e)3}
     argv+=(${(s: :)ZPCRE_OP} "$5")
 
diff --git a/Functions/Misc/run-help b/Functions/Misc/run-help
index d52c1b032..462044b72 100644
--- a/Functions/Misc/run-help
+++ b/Functions/Misc/run-help
@@ -58,11 +58,11 @@ do
     case $what in
     (*( is an alias for (noglob|nocorrect))*)
 	[[ ${what[(w)7]:t} != ${what[(w)1]} ]] &&
-	  run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)7]:t}
+	  run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)7]:t} ${(z)${what[(w)8,-1]}}
 	;;
     (*( is an alias)*)
 	[[ ${what[(w)6]:t} != ${what[(w)1]} ]] &&
-	  run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)6]:t}
+	  run_help_orig_cmd=${what[(w)1]} run-help ${what[(w)6]:t} ${(z)${what[(w)7,-1]}}
 	;;
     (*( is a * function))
 	case ${what[(w)1]} in
@@ -98,13 +98,13 @@ do
 	    if whence "run-help-$1:t" >/dev/null
 	    then
 		local cmd_args
-		builtin getln cmd_args
+		builtin getln cmd_args &&
 		builtin print -z "$cmd_args"
-		cmd_args=( ${(z)cmd_args} )
+		cmd_args=( ${(z)${cmd_args:-"$*"}} )
 
                 # Discard the command itself & everything before it.
-                shift $cmd_args[(i)${run_help_orig_cmd:-$1}] cmd_args ||
-                    return
+                shift $cmd_args[(i)(${run_help_orig_cmd}|$1)] cmd_args 2>/dev/null ||
+                    continue
 
                 # Discard options, parameter assignments & paths.
                 cmd_args=( ${cmd_args[@]:#([-+]*|*=*|*/*|\~*)} )
diff --git a/Functions/Misc/run-help-docker b/Functions/Misc/run-help-docker
new file mode 100644
index 000000000..09a8a221a
--- /dev/null
+++ b/Functions/Misc/run-help-docker
@@ -0,0 +1,9 @@
+if [[ $# == 0 ]]
+then
+    man docker
+elif [[ $# > 1 && $1 == (builder|checkpoint|config|container|context|image|manifest|network|node|plugin|secret|service|stack|swarm|system|trust|volume) ]]
+then
+    man docker-$1-$2
+else
+    man docker-$1
+fi
diff --git a/Functions/Misc/run-help-ip b/Functions/Misc/run-help-ip
index b811ce352..f635cce71 100644
--- a/Functions/Misc/run-help-ip
+++ b/Functions/Misc/run-help-ip
@@ -18,7 +18,7 @@ case $1 in
     (addrl*) man ip-addrlabel ;;
     (a*) man ip-address ;;
     (l2*) man ip-l2tp ;;
-    (li*) man ip-link ;;
+    (l*) man ip-link ;;
     (ma*) man ip-maddress ;;
     (mo*) man ip-monitor ;;
     (mr*) man ip-mroute ;;
diff --git a/Functions/Misc/run-help-openssl b/Functions/Misc/run-help-openssl
index c528418c8..e4e45070e 100644
--- a/Functions/Misc/run-help-openssl
+++ b/Functions/Misc/run-help-openssl
@@ -1,7 +1 @@
-
-if [ $# -eq 0 ]; then
-    man openssl
-else
-    man $1
-fi
-
+man openssl${1:+-$1} || man ${1:-openssl}
diff --git a/Functions/Misc/run-help-perf b/Functions/Misc/run-help-perf
new file mode 100644
index 000000000..2e0695af2
--- /dev/null
+++ b/Functions/Misc/run-help-perf
@@ -0,0 +1 @@
+man perf${1:+-$1}
diff --git a/Functions/Misc/run-help-podman b/Functions/Misc/run-help-podman
new file mode 100644
index 000000000..64d9cd83f
--- /dev/null
+++ b/Functions/Misc/run-help-podman
@@ -0,0 +1,9 @@
+if [[ $# == 0 ]]
+then
+    man podman
+elif [[ $# > 1 && $1 == (container|generate|healthcheck|image|kube|machine|manifest|network|pod|secret|system|volume) ]]
+then
+    man podman-$1-$2
+else
+    man podman-$1
+fi
diff --git a/Functions/Misc/run-help-ssh b/Functions/Misc/run-help-ssh
new file mode 100644
index 000000000..9c48596ff
--- /dev/null
+++ b/Functions/Misc/run-help-ssh
@@ -0,0 +1,6 @@
+if [[ $# < 2 ]]
+then
+    man ssh
+else
+    run-help $2
+fi
diff --git a/Functions/Misc/run-help-svk b/Functions/Misc/run-help-svk
deleted file mode 100644
index 782538246..000000000
--- a/Functions/Misc/run-help-svk
+++ /dev/null
@@ -1 +0,0 @@
-svk help $1 | ${=PAGER:-more}
diff --git a/Functions/Misc/run-help-svnadmin b/Functions/Misc/run-help-svnadmin
new file mode 100644
index 000000000..dbddd6396
--- /dev/null
+++ b/Functions/Misc/run-help-svnadmin
@@ -0,0 +1 @@
+svnadmin help $1 | ${=PAGER:-more}
diff --git a/Functions/Misc/zargs b/Functions/Misc/zargs
index ecd69f7e4..782d6811e 100644
--- a/Functions/Misc/zargs
+++ b/Functions/Misc/zargs
@@ -39,18 +39,21 @@
 #
 # "Killed by a signal" is determined by the usual shell rule that $? is
 # the signal number plus 128, so zargs can be fooled by a command that
-# explicitly exits with 129+.  Also, zsh prior to 4.1.x returns 1 rather
-# than 127 for "command not found" so this function incorrectly returns
-# 123 in that case if used with zsh 4.0.x.
+# explicitly exits with 129+.  If the command passed to zargs is a shell
+# function which uses "exit" instead of "return", zsh interprets 129+ as
+# a signal sent to the process group and may terminate zargs with that
+# status.  This is avoided when running zargs -P 2 or greater.
 #
-# With the --max-procs option, zargs may not correctly capture the exit
-# status of the backgrounded jobs, because of limitations of the "wait"
-# builtin.  If the zsh/parameter module is not available, the status is
-# NEVER correctly returned, otherwise the status of the longest-running
-# job in each batch is captured.
+# ZARGS_VERSION 1.5 is the last to support zsh 4.x.  Also, zsh prior to
+# 4.1.x returns 1 rather than 127 for "command not found" so zargs
+# incorrectly returned 123 in that case if used with zsh 4.0.x.
 #
-# Also because of "wait" limitations, --max-procs spawns max-procs jobs,
-# then waits for all of those, then spawns another batch, etc.
+# Because of "wait" limitations, --max-procs spawns max-procs jobs, then
+# waits for all of those, then spawns another batch, etc.
+#
+# The maximum number of parallel jobs for which exit status is available
+# is determined by the sysconf CHILD_MAX parameter, which can't be read
+# or changed from within the shell.
 #
 # Differences from POSIX xargs:
 #
@@ -69,6 +72,13 @@
 #   -I/-L and implementations reportedly differ.)  In zargs, -i/-I have
 #   this behavior, as do -l/-L, but when -i/-I appear anywhere then -l/-L
 #   are ignored (forced to 1).
+#
+# * The use of SIGUSR1 and SIGUSR2 to change the number of parallel jobs
+#   is not supported.
+
+{ # Begin "always" block to reset locally defined functions
+
+local ZARGS_VERSION="1.8"
 
 # First, capture the current setopts as "sticky emulation"
 if zmodload zsh/parameter
@@ -83,11 +93,20 @@ else
   emulate $(emulate -l) -c '_zarun() { eval "$@" }'
 fi
 
+local _zaTRAPS="$(trap)"
+_zatraps() {
+  # In children, these traps may be reset to default behavior, even
+  # if the calling shell has traps.  Restore to surrounding context,
+  # but assure that if zargs itself is signaled, children will exit.
+  [[ -o interactive ]] &&
+    function TRAP{HUP,INT,QUIT,TERM} { exit $((128 + $1)) }
+  [[ -n "$_zaTRAPS" ]] && eval "$_zaTRAPS"
+  unset _zaTRAPS
+}
+
 emulate -L zsh || return 1
 local -a opts eof n s l P i
 
-local ZARGS_VERSION="1.5"
-
 if zparseopts -a opts -D -- \
 	-eof::=eof e::=eof \
 	-exit x \
@@ -192,14 +211,14 @@ then (( c = $#command - 1 ))
 else command=( print -r -- )
 fi
 
-local wait bg
-local execute='
+local bg execute='
     if (( $opts[(I)-(-interactive|p)] ))
     then read -q "?$call?..." || continue
     elif (( $opts[(I)-(-verbose|t)] ))
     then print -u2 -r -- "$call"
     fi
     _zarun "{
+	_zatraps
 	\"\${call[@]}\"
     } $bg"'
 local ret=0 analyze='
@@ -262,19 +281,19 @@ fi
 
 if (( P != 1 && ARGC > 1 ))
 then
-    # These setopts are necessary for "wait" on multiple jobs to work.
-    setopt nonotify nomonitor
-    bg='&'
-    if zmodload -i zsh/parameter 2>/dev/null
-    then
-	wait='wait ${${jobstates[(R)running:*]/#*:/}/%=*/}'
-    else
-	wait='wait'
-    fi
+    setopt nonotify	# Do not report each exiting job
+    local -a _zajobs
+    local j
+    bg='& _zajobs+=( $! )'
+    analyze='
+    for j in $_zajobs; do
+      wait $j
+      '"$analyze"'
+    done; _zajobs=()'
 fi
 
-# Everything has to be in a subshell just in case of backgrounding jobs,
-# so that we don't unintentionally "wait" for jobs of the parent shell.
+# Everything has to be in a subshell so that we don't "wait" for any
+# unrelated jobs of the parent shell.
 (
 
 while ((ARGC))
@@ -313,4 +332,8 @@ return $ret
 
 )
 
+} always {
+  builtin unfunction _zarun _zatraps
+}
+
 # }
diff --git a/Functions/Misc/zcalc b/Functions/Misc/zcalc
index 480373345..6cd2822c9 100644
--- a/Functions/Misc/zcalc
+++ b/Functions/Misc/zcalc
@@ -124,8 +124,10 @@ integer _rpn_mode _matched _show_stack _i _n
 integer _max_stack _push
 local -a _expressions stack
 
+
 # We use our own history file with an automatic pop on exit.
-history -ap "${ZDOTDIR:-$HOME}/.zcalc_history"
+history -ap "${ZCALC_HISTFILE:-${ZDOTDIR:-$HOME}/.zcalc_history}"
+
 
 _forms=( '%2$g' '%.*g' '%.*f' '%.*E' '')
 
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
index 7d0d590db..bb075512c 100644
--- a/Functions/Misc/zed
+++ b/Functions/Misc/zed
@@ -14,15 +14,17 @@ local var opts zed_file_name
 integer TMOUT=0 okargs=1 fun hist bind
 local -a expand
 
-zparseopts -D -A opts f h b x:
+zparseopts -D -A opts f h b x: || return 1
 fun=$+opts[-f]
 hist=$+opts[-h]
 bind=$+opts[-b]
-if [[ $opts[-x] == <-> ]]; then
-  expand=(-x $opts[-x])
-elif (( $+opts[-x] )); then
-  print -r "Integer expected after -x: $opts[-x]" >&2
-  return 1
+if (( $+opts[-x] )); then
+  if [[ $opts[-x] == <-> ]]; then
+    expand=(-x $opts[-x])
+  else
+    print -r "Integer expected after -x: $opts[-x]" >&2
+    return 1
+  fi
 fi
 
 [[ $0 = fned ]] && fun=1
diff --git a/Functions/Misc/zmv b/Functions/Misc/zmv
index 269fe5ba5..5c03e9ea1 100644
--- a/Functions/Misc/zmv
+++ b/Functions/Misc/zmv
@@ -236,12 +236,18 @@ if [[ $pat = (#b)(*)\((\*\*##/)\)(*) ]]; then
 else
   fpat=$pat
 fi
-files=(${~fpat})
 
 [[ -n $hasglobqual ]] && pat=$opat
 
 errs=()
 
+() {
+  # (#qN) breaks bareglobqual -Q option, so:
+  setopt localoptions nullglob
+  files=(${~fpat})
+}
+(( ${#files} )) || errs=( "no files matched \`$fpat'" )
+
 for f in $files; do
   if [[ $pat = (#b)(*)\(\*\*##/\)(*) ]]; then
     # This looks like a recursive glob.  This isn't good enough,
diff --git a/Functions/Misc/zslurp b/Functions/Misc/zslurp
new file mode 100644
index 000000000..84df0c948
--- /dev/null
+++ b/Functions/Misc/zslurp
@@ -0,0 +1,31 @@
+#!/bin/zsh -f
+
+# Read stdin verbatim and as efficiently as possible into $REPLY,
+# stopping without any change to $REPLY in the event of any error.
+# Benchmarked by Roman Perepelitsa in zsh-users/29472
+
+# Although this function faithfully records the input stream, later
+# references to $REPLY with the multibyte option back in effect will
+# (re-)interpret the content as multibyte characters.  This may not be
+# what is desired.
+
+emulate -L zsh -o no_multibyte
+
+### Alternate formulation, faster on bigger files
+# # /dev/fd/0 is treated specially by -f so also check /dev/fd
+# if [[ -d /dev/fd && -f /dev/fd/0 ]] && zmodload zsh/mapfile
+# then
+#     local +h -Ar mapfile
+#     typeset -g REPLY="${mapfile[/dev/fd/0]}" && return
+# fi
+# # else fall through to read from pipe/socket
+
+zmodload zsh/system || return
+local -a content
+local -i i=0
+while true; do
+    sysread 'content[++i]' && continue
+    (( $? == 5 )) || return
+    break
+done
+typeset -g REPLY=${(j::)content}
diff --git a/Functions/Newuser/zsh-newuser-install b/Functions/Newuser/zsh-newuser-install
index 60ac16b13..9e911d07c 100644
--- a/Functions/Newuser/zsh-newuser-install
+++ b/Functions/Newuser/zsh-newuser-install
@@ -627,7 +627,7 @@ Type:
 }
 
 
-# Print and despatch a submenu.
+# Print and dispatch a submenu.
 # The first argument is the title.  The remaining arguments
 # are pairs of descriptions and functions to execute.
 # There shouldn't be more than 9 entries.
diff --git a/Functions/Prompts/prompt_sprint2_setup b/Functions/Prompts/prompt_sprint2_setup
new file mode 100644
index 000000000..0eaea4473
--- /dev/null
+++ b/Functions/Prompts/prompt_sprint2_setup
@@ -0,0 +1,128 @@
+# Created by Sebastian Gniazdowski 
+
+prompt_sprint2_help () {
+    cat <<EOF
+This prompt is color themable. You can invoke it in following way:
+
+prompt sprint2 <time/line color> <braces clr.> <text clr.> <at/colon clr.> <prompt clr.>
+
+You can provide only N first arguments, N=1..5.
+
+The default colors are: 39 green blue green yellow
+EOF
+}
+
+prompt_sprint2_setup () {
+    local col_time_line=${1:-'39'}
+    local col_parens=${2:-'green'}
+    local col_text=${3:-'blue'}
+    local col_at_colon=${4:-'green'}
+    local col_prompt=${5:-'yellow'}
+
+    autoload -Uz vcs_info
+
+    typeset -gA _psvar
+
+    local cl_time_line="%B%F{$col_time_line}"
+    local cl_text="%b%F{$col_text}"
+    local cl_parens="%B%F{$col_parens}"
+    local cl_at_colon="%b%F{$col_at_colon}"
+    local cl_prompt="%B%F{$col_prompt}"
+    local cl_rst="%b%f"
+
+    local _lpar="${cl_parens}["
+    local _rpar="${cl_parens}]"
+
+    local _time="$cl_time_line%D{%H:%M}"
+    _psvar[user]='%n'
+    local _user="$cl_text"'${_psvar[user]}'
+    _psvar[at]="@"
+    _psvar[host]='%m'
+    local _at="$cl_at_colon"'${_psvar[at]}'"$cl_text"'${_psvar[host]}'
+    _psvar[colon]=':'
+    local _path="$cl_at_colon"'${_psvar[colon]}'"$cl_text%28<*<%/%<<"
+    local _line="$cl_time_line%i"
+    local _prompt="$cl_prompt# "
+
+    # You can instantly shorten the prompt by setting PSSHORT=1
+    if [[ "$COLUMNS" -le 94 || "$PSSHORT" = "1" ]]; then
+        _psvar=()
+    else
+        _psvar[user]='%n'
+        _psvar[at]="@"
+        _psvar[host]='%m'
+        _psvar[colon]=':'
+    fi
+
+    PS1="$_time$_lpar$_user$_at$_path$_rpar$_line$_prompt$cl_rst"
+
+    PS2="$cl_parens> $cl_rst"
+
+    RPS1='${vcs_info_msg_0_}'
+    prompt_opts=(cr subst percent)
+
+    zstyle ':vcs_info:*' enable git svn darcs bzr hg
+    zstyle ':vcs_info:*' stagedstr "%F{green}●$cl_rst"
+    zstyle ':vcs_info:*' unstagedstr "%F{yellow}●$cl_rst"
+    zstyle ':vcs_info:*' check-for-changes true
+    zstyle ':vcs_info:*' formats '(%s)-[%b%u%c]-'
+
+    add-zsh-hook precmd prompt_sprint2_precmd
+}
+
+prompt_sprint2_precmd () {
+    setopt localoptions noxtrace noksharrays 
+
+    # You can instantly shorten the prompt by setting PSSHORT=1
+    if [[ "$COLUMNS" -le 94 || "$PSSHORT" = "1" ]]; then
+        _psvar=()
+    else
+        _psvar[user]='%n'
+        _psvar[at]="@"
+        _psvar[host]='%m'
+        _psvar[colon]=':'
+    fi
+
+    local -a changed_files
+    changed_files=( )
+    git diff --quiet 2>/dev/null || changed_files=( ${(f)"$( git diff --name-only 2>/dev/null )"} )
+    changed_files=( $^changed_files(N) )
+    if [[ "${#changed_files}" -gt 0 ]]; then
+        local basedir
+        basedir="$(git rev-parse --show-toplevel)/"
+        changed_files=( ${(f)"$( find "${basedir}${^changed_files[@]}" -mtime +2 )"} )
+    fi
+
+    if [[ "${#changed_files}" -eq 0 ]]; then
+        zstyle ':vcs_info:*' formats ' (%s)-[%b%u%c]'
+    else
+        zstyle ':vcs_info:*' formats ' (%s)-[%b%u%B%F{yellow}-OLD-%c%%b%f]'
+    fi
+
+    vcs_info
+}
+
+prompt_sprint2_preview () {
+    local -a colors_time_line colors_text
+    colors_time_line=(red yellow green blue magenta cyan)
+    colors_text=(red yellow green blue magenta cyan)
+
+    local ctime_line ctext i j
+
+    if (( ! $#* )); then
+        for (( i = 1; i <= ${#colors_time_line}; i++ )); do
+            ctime_line="${colors_time_line[$i]}"
+            for (( j = 1; j <= ${#colors_text}; j++ )); do
+                ctext="${colors_text[$j]}"
+                prompt_preview_theme sprint2 "$ctime_line" "red" "$ctext"
+                (( i != ${#colors_time_line} || j != ${#colors_text} )) && print
+            done
+        done
+    else
+        prompt_preview_theme sprint2 "$@"
+    fi
+}
+
+prompt_sprint2_setup "$@"
+
+# vim:ft=zsh
diff --git a/Functions/Prompts/promptinit b/Functions/Prompts/promptinit
index 20503d78b..0c06699e8 100644
--- a/Functions/Prompts/promptinit
+++ b/Functions/Prompts/promptinit
@@ -73,7 +73,7 @@ set_prompt() {
 Options:
     -c              Show currently selected theme and parameters
     -l              List currently available prompt themes
-    -p [<themes>]   Preview given themes (defaults to all)
+    -p [<themes>]   Preview given themes (defaults to all except current theme)
     -h [<theme>]    Display help (for given theme)
     -s <theme>      Set and save theme
     <theme>         Switch to new theme immediately (changes not saved)
@@ -120,10 +120,9 @@ Use prompt -h <theme> for help on specific themes.'
        print $prompt_themes
        return
        ;;
-    p) preview=( $prompt_themes )
+    p) preview=( ${prompt_themes:#$prompt_theme} )
        (( $#* > 1 )) && preview=( "$@[2,-1]" )
        for theme in $preview; do
-         [[ "$theme" == "$prompt_theme[*]" ]] && continue
          prompt_preview_safely "$=theme"
        done
        print -P "%b%f%k"
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
index eb04d4b41..9a608adab 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
@@ -132,7 +132,7 @@ VCS_INFO_git_handle_patches () {
     VCS_INFO_set-patch-format 'git_patches_applied' 'git_applied_s' \
                               'git_patches_unapplied' 'git_unapplied_s' \
                               ":vcs_info:${vcs}:${usercontext}:${rrn}" gitmsg \
-                              '' ''
+                              '' '' ''
     gitmisc=$REPLY
 }
 
@@ -184,18 +184,12 @@ fi
 VCS_INFO_adjust
 VCS_INFO_git_getaction ${gitdir}
 
-local patchdir=${gitdir}/patches/${gitbranch}
-if [[ -d $patchdir ]] && [[ -f $patchdir/applied ]] \
-   && [[ -f $patchdir/unapplied ]]
-then
-    # stgit
-    git_patches_applied=(${(f)"$(< "${patchdir}/applied")"})
-    git_patches_unapplied=(${(f)"$(< "${patchdir}/unapplied")"})
-    VCS_INFO_git_handle_patches
-elif [[ -d "${gitdir}/rebase-merge" ]]; then
+local patchdir
+if [[ -d "${gitdir}/rebase-merge" ]]; then
     # 'git rebase -i'
     patchdir="${gitdir}/rebase-merge"
     local p
+    (( ${+functions[VCS_INFO_git_map_rebase_line_to_hash_and_subject]} )) ||
     VCS_INFO_git_map_rebase_line_to_hash_and_subject() {
         local p=$1
         unset REPLY
@@ -207,7 +201,7 @@ elif [[ -d "${gitdir}/rebase-merge" ]]; then
                 # Comment line.  Skip.
                 return 0
                 ;; 
-            ((p|pick|e|edit|r|reword|f|fixup|s|squash)' '*)
+            (''(p|pick|e|edit|r|reword|f|fixup|s|squash)' '*)
                 # The line is of the form "pick $hash $subject".
                 # Just strip the verb and we're good to go.
                 p=${p#* }
@@ -230,7 +224,7 @@ elif [[ -d "${gitdir}/rebase-merge" ]]; then
                         p="${p%% *} ?"
                 fi
                 ;;
-            ((x|exec) *)
+            (''(x|exec) *)
                 # The line is of the form 'exec foo bar baz' where 'foo bar
                 # baz' is a shell command.  There's no way to map _that_ to
                 # "$hash $subject", but I hope this counts as making an effort.
@@ -250,7 +244,9 @@ elif [[ -d "${gitdir}/rebase-merge" ]]; then
             (( $+REPLY )) && git_patches_applied+=( "$REPLY" )
         done
     fi
-    if [[ -f "${patchdir}/git-rebase-todo" ]] ; then
+    if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied &&
+       [[ -f "${patchdir}/git-rebase-todo" ]]
+    then
         for p in ${(f)"$(< "${patchdir}/git-rebase-todo")"}; do
             VCS_INFO_git_map_rebase_line_to_hash_and_subject "$p"
             (( $+REPLY )) && git_patches_unapplied+=( "$REPLY" )
@@ -380,7 +376,9 @@ elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then
     # TODO: maybe read up to the first blank line
     IFS='' read -r subject < "${gitdir}/MERGE_MSG"
     git_patches_applied=( "$(<${gitdir}/CHERRY_PICK_HEAD) ${subject}" )
-    if [[ -f "${gitdir}/sequencer/todo" ]]; then
+    if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied &&
+       [[ -f "${gitdir}/sequencer/todo" ]]
+    then
         # Get the next patches, and remove the one that's in CHERRY_PICK_HEAD.
         git_patches_unapplied=( ${${(M)${(f)"$(<"${gitdir}/sequencer/todo")"}:#pick *}#pick } )
         git_patches_unapplied[1]=()
@@ -388,6 +386,31 @@ elif [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]]; then
         git_patches_unapplied=()
     fi
     VCS_INFO_git_handle_patches
+elif command -v stg >/dev/null &&
+        ${vcs_comm[cmd]} show-ref --quiet refs/stacks/${gitbranch} refs/heads/${gitbranch}.stgit 2>/dev/null &&
+        git_patches_applied=(${${(f)"$(stg series --noprefix --applied --description 2>/dev/null)"}/ #[#]})
+then
+    # Testing for StGit patches is done after testing for all git-proper
+    # patches/states. If a StGit user's repo is in one of those states, they
+    # will want to see that instead of the StGit patch info.
+
+    # Performance note: testing for the stg executable is done first because it
+    # is extremely cheap and there is nothing else to do if it isn't present.
+    # Using git to test whether a StGit stack is initialized is cheaper than
+    # running stg itself; especially for versions of StGit <= 2.0. Thus getting
+    # StGit patch info should only have a material runtime cost if StGit is
+    # installed and in-use for the current branch.
+
+    # In StGit >=1.2, the existence of refs/stacks/<branch> indicates StGit is
+    # initialized. In StGit >=0.15, it is refs/heads/<branch>.stgit.
+
+    # N.B. the "--noprefix" option is available in StGit 2.x as an alias for
+    # --no-prefix.  The former is compatible with StGit versions going back to
+    # 2008.
+    if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-unapplied; then
+        git_patches_unapplied=(${${(f)"$(stg series --noprefix --unapplied --description 2>/dev/null)"}/ #[#]})
+    fi
+    VCS_INFO_git_handle_patches
 else
     gitmisc=''
 fi
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
index 2806aee1d..ea3798b81 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
@@ -14,7 +14,7 @@ local hgbase bmfile branchfile topicfile rebasefile dirstatefile mqseriesfile \
 
 local -a hgid_args defrevformat defbranchformat \
     hgbmarks mqpatches mqguards mqunapplied hgmisc \
-    i_patchguards i_negguards i_posguards
+    i_patch i_patchguards i_negguards i_posguards
 
 local -A hook_com
 
@@ -56,7 +56,6 @@ if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then
         zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" \
             "check-for-changes" || hgid_args+=( -r. )
 
-        local HGPLAIN
         HGPLAIN=1 ${vcs_comm[cmd]} ${(z)hgid_args} 2> /dev/null \
             | read -r r_csetid r_lrev
     fi
@@ -184,6 +183,9 @@ if zstyle -T ":vcs_info:${vcs}:${usercontext}:${rrn}" get-mq \
             # Skip commented lines
             [[ ${i_patch} == [[:space:]]#"#"* ]] && continue
 
+            # Skip applied patches
+            (( ${+mqpatches[(re)${i_patch}]} )) && continue
+
             # Separate negative and positive guards to more easily find the
             # intersection of active guards with patch guards
             i_patchguards=( ${(s: :)i_patchguards} )
@@ -226,7 +228,7 @@ if zstyle -T ":vcs_info:${vcs}:${usercontext}:${rrn}" get-mq \
     VCS_INFO_set-patch-format 'mqpatches' 'applied_string' \
                               'mqunapplied' 'unapplied_string' \
                               ":vcs_info:${vcs}:${usercontext}:${rrn}" hgmqstring \
-                              extra_hook_com VCS_INFO_hg_extra_zformats
+                              extra_hook_com VCS_INFO_hg_extra_zformats ''
     hgmqstring=$REPLY
 fi
 
diff --git a/Functions/VCS_Info/VCS_INFO_formats b/Functions/VCS_Info/VCS_INFO_formats
index e0e1dc738..daf169f26 100644
--- a/Functions/VCS_Info/VCS_INFO_formats
+++ b/Functions/VCS_Info/VCS_INFO_formats
@@ -28,7 +28,7 @@ hook_com=(
     vcs_orig      "${vcs}"
 )
 hook_com[base-name]="${${hook_com[base]}:t}"
-hook_com[base-name_orig]="${hook_com[base_name]}"
+hook_com[base-name_orig]="${hook_com[base-name]}"
 hook_com[subdir]="$(VCS_INFO_reposub ${hook_com[base]})"
 hook_com[subdir_orig]="${hook_com[subdir]}"
 
diff --git a/Functions/VCS_Info/VCS_INFO_patch2subject b/Functions/VCS_Info/VCS_INFO_patch2subject
index a467edcdb..5aa9efd23 100644
--- a/Functions/VCS_Info/VCS_INFO_patch2subject
+++ b/Functions/VCS_Info/VCS_INFO_patch2subject
@@ -1,3 +1,5 @@
+## vim:ft=zsh
+#
 # This function takes as an argument a filename of a patch and sets $REPLY to
 # a single-line "subject", or unsets it if no subject could be extracted.
 {
diff --git a/Functions/VCS_Info/VCS_INFO_quilt b/Functions/VCS_Info/VCS_INFO_quilt
index 264dbed0e..ce5b41f24 100644
--- a/Functions/VCS_Info/VCS_INFO_quilt
+++ b/Functions/VCS_Info/VCS_INFO_quilt
@@ -92,7 +92,7 @@ function VCS_INFO_quilt-patch2subject() {
     emulate -L zsh
     setopt extendedglob
     local mode="$1"
-    local patches pc tmp qstring root
+    local patches pc qstring root
     local -i ret
     local context
     local -a applied unapplied applied_string unapplied_string quiltcommand quilt_env
@@ -113,9 +113,12 @@ function VCS_INFO_quilt-patch2subject() {
         ;;
     esac
 
-    VCS_INFO_quilt-dirfind .pc .version
-    ret=$? pc=$REPLY
-    if (( ret == 0 )); then
+    # Look for the patches directory.
+    #
+    # 1. Check if there's a .pc/.version file in a parent dir.  If so, use the
+    # patches dir from the corresponding .pc/.quilt_patches.
+    if VCS_INFO_quilt-dirfind .pc .version; then
+        pc=$REPLY
         [[ ${quiltmode} == 'standalone' ]] && root=${pc}
         pc=${pc}/.pc
         if [[ -e ${pc}/applied-patches ]]; then
@@ -128,25 +131,27 @@ function VCS_INFO_quilt-patch2subject() {
         fi
         patches=$(<$pc/.quilt_patches)
         patches=`builtin cd -q "${pc:h}" && print -r - ${patches:P}`
+    # 2. Else, locate a patches dir using the style settings.
+    else
+        zstyle -s "${context}" quilt-patch-dir patches || patches="${QUILT_PATCHES}"
+        : ${patches:="patches"}
+        if [[ "${patches}" != /* ]]; then
+            if VCS_INFO_quilt-dirfind "${patches}"; then
+                patches=$REPLY/$patches
+            else
+                return $?
+            fi
+        else
+            [[ -d ${patches} ]] || return 1
+        fi
+        quilt_env+=(QUILT_PATCHES="$patches")
     fi
+    # At this point, $patches is set and points to an existing directory.
+
     if zstyle -t "${context}" get-unapplied; then
         # This zstyle call needs to be moved further up if `quilt' needs
         # to be run in more places than this one.
         zstyle -s "${context}" quiltcommand quiltcommand || quiltcommand='quilt'
-        quilt_env=()
-        if [ -z "$patches" ]; then
-            zstyle -s "${context}" quilt-patch-dir patches || patches="${QUILT_PATCHES}"
-            if [[ "${patches}" != /* ]]; then
-                tmp=${patches:-patches}
-                VCS_INFO_quilt-dirfind "${tmp}"
-                ret=$? patches=$REPLY
-                (( ret )) && return ${ret}
-                patches=${patches}/${tmp}
-            else
-                [[ -d ${patches} ]] || return 1
-            fi
-            quilt_env+=(QUILT_PATCHES="$patches")
-        fi
         unapplied=( ${(f)"$(if (( $+quilt_env[1] )); then export ${quilt_env[@]}; fi
                             $quiltcommand --quiltrc /dev/null unapplied 2> /dev/null)"} )
         unapplied=( ${unapplied:#} )
@@ -154,8 +159,7 @@ function VCS_INFO_quilt-patch2subject() {
         unapplied=()
     fi
 
-    if [[ -n $patches ]]; then
-      () {
+    {
         local i
         for ((i=1; i<=$#applied; i++)); do
           if VCS_INFO_quilt-patch2subject "$patches/$applied[$i]" && (( $+REPLY ))
@@ -173,13 +177,17 @@ function VCS_INFO_quilt-patch2subject() {
             unapplied[$i]+=" ?"
           fi
         done
-      }
-    fi
+    }
+
+    typeset -A quilt_extra_info=(
+        quilt-patches-dir ${patches}
+        ${pc:+"quilt-pc-dir"} $pc
+    )
 
     VCS_INFO_set-patch-format 'applied' 'applied_string' \
                               'unapplied' 'unapplied_string' \
                               ${context} qstring \
-                              '' ''
+                              quilt_extra_info '' quilt_extra_info
     qstring=$REPLY
 
     case ${mode} in
diff --git a/Functions/VCS_Info/VCS_INFO_set-branch-format b/Functions/VCS_Info/VCS_INFO_set-branch-format
index 8cff51b9a..cbab60e29 100644
--- a/Functions/VCS_Info/VCS_INFO_set-branch-format
+++ b/Functions/VCS_Info/VCS_INFO_set-branch-format
@@ -1,3 +1,5 @@
+## vim:ft=zsh
+#
 # A function for calling the branch-format hook
 #
 # Return the value to use in REPLY
diff --git a/Functions/VCS_Info/VCS_INFO_set-patch-format b/Functions/VCS_Info/VCS_INFO_set-patch-format
index e387110a2..1c774a7f6 100644
--- a/Functions/VCS_Info/VCS_INFO_set-patch-format
+++ b/Functions/VCS_Info/VCS_INFO_set-patch-format
@@ -1,3 +1,5 @@
+## vim:ft=zsh
+#
 # This function is the common guts of the gen-applied-string /
 # gen-unapplied-string / set-patch-format dance of several backends.
 #
@@ -13,6 +15,8 @@
 # $7 - name of an assoc parameter with extra $hook_com key-value pairs for the
 #      set-patch-format hook invocation, or '' for none
 # $8 - name of a function that sets $reply to extra arguments for the patch-format zformat call, or '' for none
+# $9 - name of an assoc parameter with extra $hook_com key-value pairs for the
+#      gen-applied-string & gen-unapplied-string hook invocations, or '' for none
 #
 # The expanded patch-format string is returned in $REPLY.
 #
@@ -20,8 +24,10 @@
 # - $hook_com is overwritten and the keys 'applied', 'applied-n',
 #   'unapplied', 'unapplied-n', 'all-n' are set.
 {
+    hook_com=()
+
     local applied_needs_escaping='unknown'
-    local unapplied_needs_escaping='unknown'
+    hook_com+=( ${9:+"${(@kvP)9}"} )
     if VCS_INFO_hook 'gen-applied-string' "${(@P)1}"; then
         if (( ${(P)#1} )); then
             REPLY=${(P)1[1]}
@@ -35,6 +41,8 @@
     : ${(P)2::=$REPLY}
     hook_com=()
 
+    local unapplied_needs_escaping='unknown'
+    hook_com+=( ${9:+"${(@kvP)9}"} )
     if VCS_INFO_hook 'gen-unapplied-string' "${(@P)3}"; then
         REPLY=${(P)#3}
         unapplied_needs_escaping='yes'
diff --git a/Functions/VCS_Info/test-repo-git-rebase-apply b/Functions/VCS_Info/test-repo-git-rebase-apply
index cb4ea4f58..ce49690cd 100755
--- a/Functions/VCS_Info/test-repo-git-rebase-apply
+++ b/Functions/VCS_Info/test-repo-git-rebase-apply
@@ -44,6 +44,16 @@ append_lines 7 8 9
 # Specify a rebase that would create the history [1,3,4,5,6,7,8,9].
 # This will conflict because r7 depends on r2 which is not included.
 git checkout -b myref
-git rebase --onto=rebase_onto_this rebase_from_this myref
+case $0:P in
+    (*/test-repo-git-rebase-apply)
+        git rebase --onto=rebase_onto_this rebase_from_this myref
+        ;;
+    (*/test-repo-git-rebase-merge)
+        git -c core.editor=true rebase -i --onto=rebase_onto_this rebase_from_this myref
+        ;;
+    (*)
+        echo >&2 "$0: unrecognized basename"
+        ;;
+esac
 
 
diff --git a/Functions/VCS_Info/test-repo-git-rebase-merge b/Functions/VCS_Info/test-repo-git-rebase-merge
new file mode 120000
index 000000000..fce9e9178
--- /dev/null
+++ b/Functions/VCS_Info/test-repo-git-rebase-merge
@@ -0,0 +1 @@
+test-repo-git-rebase-apply
\ No newline at end of file
diff --git a/Functions/Zle/edit-command-line b/Functions/Zle/edit-command-line
index 5f7ea321f..d4b405eaf 100644
--- a/Functions/Zle/edit-command-line
+++ b/Functions/Zle/edit-command-line
@@ -11,15 +11,30 @@ local left right prebuffer buffer=$BUFFER lbuffer=$LBUFFER
 local TMPSUFFIX=.zsh
 # set up parameters depending on which context we are called from,
 # see below comment for more details
-if (( REGION_ACTIVE )); then
+if (( REGION_ACTIVE == 1 )); then
   if (( CURSOR < MARK )); then
     left=$CURSOR right=$MARK
-    lbuffer=
   else
     left=$MARK right=$CURSOR
-    lbuffer[right-left,-1]=
   fi
-  (( left++ ))
+  lbuffer=$lbuffer[++left,-1]
+  buffer=$BUFFER[left,++right]
+elif (( REGION_ACTIVE == 2 )); then
+  local nl=$'\n'
+  if (( CURSOR < MARK )); then
+    left=${${BUFFER[1,CURSOR]}[(I)$nl]}
+    right=${${BUFFER[MARK+1,-1]}[(i)$nl]}
+    (( right += MARK ))
+  else
+    left=${${BUFFER[1,MARK]}[(I)$nl]}
+    right=${${BUFFER[CURSOR+1,-1]}[(i)$nl]}
+    (( right += CURSOR ))
+  fi
+  lbuffer=$lbuffer[++left,-1]
+  if [[ $BUFFER[right] = $nl ]]; then
+    # Keep the newline because "$(<$1)" below trims it
+    (( --right ))
+  fi
   buffer=$BUFFER[left,right]
 elif (( ! ZLE_RECURSIVE )); then
   prebuffer=$PREBUFFER
diff --git a/Functions/Zle/incarg b/Functions/Zle/incarg
index cff0cfe4c..0cfaf9ff5 100644
--- a/Functions/Zle/incarg
+++ b/Functions/Zle/incarg
@@ -1,43 +1,303 @@
-# Shell function to increment an integer either under the cursor or just
-# to the left of it.  Use
+emulate -L zsh
+
+# A ZLE widget to increment an integer.
+#
+# In addition to decimals, it can handle hexadecimals prefixed with "0x",
+# binaries with "0b", and octals with "0o".
+#
+# By default, the target integer will be incremented by one. With a numeric
+# argument, the integer is incremented by the amount of the argument. The shell
+# parameter "incarg" may be set to change the default increment to something
+# other than one.
+#
+# The behavior of this widget changes depending on how it is named.
+#
+# - incarg / decarg
+#
+#   incarg will increment an integer either under the cursor or just to the left
+#   of it. decarg, on the other hand, will decrement it.
+#
+#   For example,
+#
+#       echo 41
+#            ^^^ cursor anywhere here
+#
+#   with incarg gives
+#
+#       echo 42
+#              ^ cursor will move here
+#
+# - sync-incarg / sync-decarg
+#
+#   The sync- variant is used for creating a sequence of numbers on split
+#   terminals with synchronized key input. The first pane won't be incremented
+#   at all, but each pane after that will have the number incremented once more
+#   than the previous pane.
+#
+#   Currently supports tmux and iTerm2.
+#
+# - vim-incarg / vim-decarg
+#
+#   This behaves like Vim's CTRL-A / CTRL-X. It moves the cursor to the nearest
+#   number after the cursor and increments or decrements it.
+#
+# - vim-backward-incarg / vim-backward-decarg
+#
+#   This behaves like vim-incarg & vim-decarg, but it searches backwards for a
+#   number.
+#
+# - vim-sync-incarg / vim-sync-decarg
+#
+#   This combines the behavior of the vim- and sync- variants. It's inspired by
+#   Vim's g_CTRL-A / g_CTRL-X.
+#
+# - vim-backward-sync-incarg / vim-backward-sync-decarg
+#
+#   This combines the behavior of the vim-backward- and sync- variants.
+#
+# Example Usage:
+#
 #   autoload -Uz incarg
-#   zle -N incarg
-#   bindkey "..." incarg
-# to define it.  For example,
-#   echo 41
-#        ^^^ cursor anywhere here
-# with incarg gives
-#   echo 42
-# with the cursor in the same place.
-#
-# A numeric argument gives a number other than 1 to add (may be negative).
-# If you're going to do it a lot with one particular number, you can set
-# the parameter incarg to that number (a numeric argument still takes
-# precedence).
+#   for widget in vim-{,sync-}{inc,dec}arg; do
+#     zle -N "$widget" incarg
+#   done
+#   bindkey -a \
+#     '^A' vim-incarg \
+#     '^X' vim-decarg \
+#     'g^A' vim-sync-incarg \
+#     'g^X' vim-sync-decarg
 
-emulate -L zsh
-setopt extendedglob
+zle -f vichange
 
-local rrest lrest num
+setopt localoptions extended_glob
+local match mbegin mend MATCH MBEGIN MEND i
 
-rrest=${RBUFFER##[0-9]#}
-if [[ $RBUFFER = [0-9]* ]]; then
-  if [[ -z $rrest ]]; then
-    num=$RBUFFER
-  else
-    num=${RBUFFER[1,-$#rrest-1]}
+[[ -z "$BUFFER" ]] && return 1
+
+# find the number and determine the base
+integer pos=$(( CURSOR + 1 )) base=0
+
+# avoid miscalculating positions when cursor is at the end of the line
+while (( pos > 0 )) && [[ "$BUFFER[pos]" == '' ]]; do
+  (( pos-- ))
+done
+
+# check for a prefix (e.g., 0x) before the cursor
+for (( i = 0; i < 2; i++ )); do
+  case "$BUFFER[1,pos]" in
+    *0[xX][0-9a-fA-F]##) base=16 ;;
+    *0[oO][0-7]##) base=8 ;;
+    *0[bB][01]##) base=2 ;;
+    *[1-9]) base=10 ;;
+    *0) ;; # there may be a prefix right after the cursor
+    *)
+      # the non-Vim variant looks right before the cursor too, but not after it
+      if [[ "$WIDGET" != vi* ]]; then
+        if (( i == 0 )); then
+          (( pos-- ))
+          continue
+        else
+          return 1
+        fi
+      fi
+      ;;
+  esac
+
+  break
+done
+
+# check for a prefix on the cursor
+if (( base == 0 && pos < $#BUFFER )); then
+  case "$BUFFER[1,pos+1]" in
+    *0[xX][0-9a-fA-F]) base=16; (( pos++ )) ;;
+    *0[oO][0-7]) base=8; (( pos++ )) ;;
+    *0[bB][01]) base=2; (( pos++ )) ;;
+  esac
+fi
+
+if (( base == 0 )); then
+  if [[ "$WIDGET" == vi* ]]; then
+    if [[ "$WIDGET" == *backward-* ]]; then
+      # search backwards for a number
+      while true; do
+        case "$BUFFER[1,pos]" in
+          *0[xX][0-9a-fA-F]##) base=16 ;;
+          *0[oO][0-7]##) base=8 ;;
+          *0[bB][01]##) base=2 ;;
+          *[0-9]) base=10 ;;
+          *-)
+            case "$BUFFER[pos,-1]" in
+              -0[xX][0-9a-fA-F]*) ;;
+              -0[oO][0-7]*) ;;
+              -0[bB][01]*) ;;
+              -[0-9]*) base=10 ;;
+            esac
+            ;;
+        esac
+        (( base != 0 )) && break
+
+        (( pos-- ))
+        (( pos <= 0 )) && return 1
+      done
+    else
+      # jump to the nearest number after the cursor
+      while [[ "$BUFFER[pos]" == [^0-9] ]]; do
+        (( pos++ ))
+        (( pos > $#BUFFER )) && return 1
+      done
+    fi
+  fi
+
+  # check for a prefix right after the cursor and jump right after it, if any
+  if (( pos <= 1 )) || [[ "$BUFFER[pos-1]" == [^0-9] ]]; then
+    case "$BUFFER[pos,-1]" in
+      0[xX][0-9a-fA-F]*) base=16; (( pos += 2 )) ;;
+      0[oO][0-7]*) base=8; (( pos += 2 )) ;;
+      0[bB][01]*) base=2; (( pos += 2 )) ;;
+    esac
   fi
 fi
 
-lrest=${LBUFFER%%[0-9]#}
-if [[ $LBUFFER = *[0-9] ]]; then
-  if [[ -z $lrest ]]; then
-    num="$LBUFFER$num"
+if (( base == 0 )); then
+  base=10
+fi
+
+# find the start of the number
+integer first="$pos"
+case "$base" in
+  10)
+    while [[ "$BUFFER[first-1]" == [0-9] ]]; do
+      (( first-- ))
+    done
+    if [[ $BUFFER[first-1] = - ]]; then
+      (( first-- ))
+    fi
+    ;;
+  2)
+    while [[ "$BUFFER[first-1]" == [01] ]]; do
+      (( first-- ))
+    done
+    ;;
+  8)
+    while [[ "$BUFFER[first-1]" == [0-7] ]]; do
+      (( first-- ))
+    done
+    ;;
+  16)
+    while [[ "$BUFFER[first-1]" == [0-9a-fA-F] ]]; do
+      (( first-- ))
+    done
+    ;;
+esac
+
+# find the end of the number
+integer last="$pos"
+case "$base" in
+  10)
+    while [[ "$BUFFER[last+1]" == [0-9] ]]; do
+      (( last++ ))
+    done
+    ;;
+  2)
+    while [[ "$BUFFER[last+1]" == [01] ]]; do
+      (( last++ ))
+    done
+    ;;
+  8)
+    while [[ "$BUFFER[last+1]" == [0-7] ]]; do
+      (( last++ ))
+    done
+    ;;
+  16)
+    while [[ "$BUFFER[last+1]" == [0-9a-fA-F] ]]; do
+      (( last++ ))
+    done
+    ;;
+esac
+
+# calculate the number of digits
+integer ndigits=0
+case "$BUFFER[first,first+1]" in
+  0*|-0) ndigits=$(( last - first + 1 )) ;;
+esac
+
+# determine the amount to increment
+integer delta=${NUMERIC:-${incarg:-1}}
+if [[ "$WIDGET" = *decarg ]]; then
+  (( delta = -delta ))
+fi
+if [[ "$WIDGET" = *sync-* ]]; then
+  integer pane_index=0
+  if [[ -n "$TMUX_PANE" ]]; then
+    pane_index="$(tmux display-message -pt "$TMUX_PANE" '#{pane_index}')"
+  elif [[ "$ITERM_SESSION_ID" =~ '^w[0-9]+t[0-9]+p([0-9]+)' ]]; then
+    pane_index="$match[1]"
   else
-    num="${LBUFFER[$#lrest+1,-1]}$num"
+    zle -M "[$WIDGET] unsupported terminal"
+    return 1
   fi
+  (( delta *= pane_index ))
 fi
 
-[[ -n $num ]] && (( num += ${NUMERIC:-${incarg:-1}} ))
+local old="$BUFFER[first,last]"
+integer oldlen=$#BUFFER
+integer oldnum="$base#$old" 2> /dev/null
+
+# -00 should increment to 01 instead of 001
+if [[ "$BUFFER[first]" == '-' ]] && (( oldnum == 0 )); then
+  (( ndigits-- ))
+fi
+
+local fmt1 fmt2
+case "$base" in
+  10) fmt1=d; fmt2='#10' ;;
+  2) fmt1=s; fmt2='##2' ;;
+  8) fmt1=s; fmt2='##8' ;;
+  16) fmt1="$BUFFER[first-1]"; fmt2='#16' ;;
+esac
+
+local raw_result padded
+# $(( )) outputs an error message to stderr when integer truncation occurs
+printf -v raw_result "%0$ndigits$fmt1" $(( [$fmt2] "$base#$old" + delta )) 2> /dev/null
+padded="${raw_result// /0}"
+integer newnum="$base#$padded" 2> /dev/null
+
+# try to detect integer truncation
+if (( base != 10 && newnum < 0
+        || delta > 0 && newnum < oldnum
+        || delta < 0 && newnum > oldnum  )); then
+  zle -M "[$WIDGET] The resulting number is either too big or too small."
+  return 1
+fi
+
+# adjust the number of leading zeros if the sign of the integer changed
+local new
+if (( base == 10 && ndigits == $#padded )); then
+  if (( oldnum < 0 && newnum >= 0 )); then
+    new="${padded#0}"
+  elif (( oldnum >= 0 && newnum < 0 )); then
+    new="-0${padded#-}"
+  fi
+fi
+if [[ -z "$new" ]]; then
+  new="$padded"
+fi
+
+if zstyle -t ":zle:$WIDGET" debug; then
+  zle -M "[$WIDGET] base: $base delta: $delta old: '$old' new: '$new'"
+fi
+
+if (( 0 < first && first <= last && last <= $#BUFFER )); then
+  BUFFER[first,last]="$new"
+else
+  zle -M "[$WIDGET] The detected location of the integer was invalid. [location=BUFFER[$first,$last]]"
+  return 1
+fi
+
+integer offset=0
+if [[ "$WIDGET" == vi* ]]; then
+  offset=-1
+fi
+(( CURSOR = last + $#BUFFER - oldlen + offset ))
 
-BUFFER="$lrest$num$rrest"
+return 0
diff --git a/Functions/Zle/keeper b/Functions/Zle/keeper
index a40125771..1570eb94a 100644
--- a/Functions/Zle/keeper
+++ b/Functions/Zle/keeper
@@ -73,6 +73,7 @@ zstyle ':completion:expand-kept-result:*' completer _insert_kept
 
 _expand_word_and_keep() {
     {
+        _shadow compadd
         function compadd {
             local -A args
             zparseopts -E -A args J:
@@ -85,7 +86,7 @@ _expand_word_and_keep() {
         }
         _expand_word
     } always {
-        unfunction compadd
+        _unshadow compadd
     }
 }