summaryrefslogtreecommitdiff
path: root/Functions
diff options
context:
space:
mode:
Diffstat (limited to 'Functions')
-rw-r--r--Functions/MIME/zsh-mime-handler2
-rw-r--r--Functions/Math/.distfiles2
-rw-r--r--Functions/Math/zmathfunc34
-rw-r--r--Functions/Misc/add-zle-hook-widget186
-rw-r--r--Functions/Misc/add-zsh-hook2
-rw-r--r--Functions/Misc/run-help-ip2
-rw-r--r--Functions/Misc/zcalc345
-rw-r--r--Functions/Misc/zed2
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_git8
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_hg7
-rw-r--r--Functions/VCS_Info/VCS_INFO_hexdump16
-rw-r--r--Functions/VCS_Info/VCS_INFO_patch2subject50
-rw-r--r--Functions/VCS_Info/VCS_INFO_quilt24
-rw-r--r--Functions/VCS_Info/vcs_info2
-rw-r--r--Functions/Zle/bracketed-paste-magic54
-rw-r--r--Functions/Zle/bracketed-paste-url-magic4
-rw-r--r--Functions/Zle/delete-whole-word-match15
-rw-r--r--Functions/Zle/expand-absolute-path2
-rw-r--r--Functions/Zle/history-beginning-search-menu2
-rw-r--r--Functions/Zle/match-words-by-style53
-rw-r--r--Functions/Zle/select-bracketed2
-rw-r--r--Functions/Zle/select-word-match120
-rw-r--r--Functions/Zle/surround7
-rw-r--r--Functions/Zle/vi-pipe39
-rw-r--r--Functions/Zle/zcalc-auto-insert3
25 files changed, 817 insertions, 166 deletions
diff --git a/Functions/MIME/zsh-mime-handler b/Functions/MIME/zsh-mime-handler
index 24e5184fc..288a0796d 100644
--- a/Functions/MIME/zsh-mime-handler
+++ b/Functions/MIME/zsh-mime-handler
@@ -127,7 +127,7 @@ for pattern in $exec_asis; do
files=(${dirpref}${~pattern})
if [[ -n ${files[(r)$1]} ]]; then
for pattern in $exec_never; do
- [[ ${1:A} = ${~pattern} ]] && break 2
+ [[ ${1:P} = ${~pattern} ]] && break 2
done
if (( list )); then
for (( i = 1; i <= $#; i++ )); do
diff --git a/Functions/Math/.distfiles b/Functions/Math/.distfiles
new file mode 100644
index 000000000..f03668b3a
--- /dev/null
+++ b/Functions/Math/.distfiles
@@ -0,0 +1,2 @@
+DISTFILES_SRC='
+'
diff --git a/Functions/Math/zmathfunc b/Functions/Math/zmathfunc
new file mode 100644
index 000000000..4ff40700d
--- /dev/null
+++ b/Functions/Math/zmathfunc
@@ -0,0 +1,34 @@
+#autoload
+
+zsh_math_func_min() {
+ local result=$1
+ shift
+ local arg
+ for arg ; do
+ (( $arg < result )) && result=$arg
+ done
+ (( result )) # return
+}
+functions -M min 1 -1 zsh_math_func_min # at least one argument
+
+zsh_math_func_max() {
+ local result=$1
+ shift
+ local arg
+ for arg ; do
+ (( $arg > result )) && result=$arg
+ done
+ (( result )) # return
+}
+functions -M max 1 -1 zsh_math_func_max # at least one argument
+
+zsh_math_func_sum() {
+ local sum
+ local arg
+ for arg ; do
+ (( sum += $arg ))
+ done
+ (( sum ))
+}
+functions -M sum 0 -1 zsh_math_func_sum
+
diff --git a/Functions/Misc/add-zle-hook-widget b/Functions/Misc/add-zle-hook-widget
new file mode 100644
index 000000000..d8a3950fb
--- /dev/null
+++ b/Functions/Misc/add-zle-hook-widget
@@ -0,0 +1,186 @@
+# Add to HOOK the given WIDGET
+#
+# HOOK is one of isearch-exit, isearch-update, line-pre-redraw, line-init,
+# line-finish, history-line-set, keymap-select (the zle- prefix is allowed
+# but not required). If a widget corresponding to HOOK already exists, it
+# is preserved and called first in the new set of HOOK widgets.
+#
+# With -d, remove the WIDGET from the hook instead; deletes the hook
+# linkage if it is empty.
+#
+# -D behaves like -d, but pattern characters are active in WIDGET, so
+# any matching widget will be deleted from the hook.
+#
+# Without -d, if the WIDGET is not already defined, a function having the
+# same name is marked for autoload; -U is passed down to autoload if that
+# is given, as are -z and -k. (This is harmless if the function is
+# already defined.) The WIDGET is then created with zle -N.
+#
+# The -L option lists the hooks and their associated widgets.
+
+# This is probably more safeguarding than necessary
+zmodload -e zsh/zle || return 1
+{ zmodload zsh/parameter && zmodload zsh/zleparameter } || {
+ print -u2 "add-zle-hook-widget: Need parameter modules for zle hooks"
+ return 1
+}
+
+() { # Preserve caller global option settings
+
+emulate -L zsh
+
+# Setup - create the base functions for hook widgets that call the others
+
+local -a hooktypes=( zle-isearch-exit zle-isearch-update
+ zle-line-pre-redraw zle-line-init zle-line-finish
+ zle-history-line-set zle-keymap-select )
+# Stash in zstyle to make it global
+zstyle zle-hook types ${hooktypes#zle-}
+
+# Relying on multifuncdef option here
+function azhw:${^hooktypes} {
+ local -a hook_widgets
+ local hook
+ # Values of these styles look like number:name
+ # and we run them in number order
+ zstyle -a $WIDGET widgets hook_widgets
+ for hook in "${(@)${(@on)hook_widgets[@]}#<->:}"; do
+ if [[ "$hook" = user:* ]]; then
+ # Preserve $WIDGET within the renamed widget
+ zle "$hook" -N -- "$@"
+ else
+ zle "$hook" -Nw -- "$@"
+ fi || return
+ done
+ return 0
+}
+
+# Redefine ourself with the setup left out
+
+function add-zle-hook-widget {
+ local -a hooktypes
+ zstyle -a zle-hook types hooktypes
+
+ # This part copied from add-zsh-hook
+ local usage="Usage: $funcstack[1] hook widgetname\nValid hooks are:\n $hooktypes"
+
+ local opt
+ local -a autoopts
+ integer del list help
+
+ while getopts "dDhLUzk" opt; do
+ case $opt in
+ (d)
+ del=1
+ ;;
+
+ (D)
+ del=2
+ ;;
+
+ (h)
+ help=1
+ ;;
+
+ (L)
+ list=1
+ ;;
+
+ ([Uzk])
+ autoopts+=(-$opt)
+ ;;
+
+ (*)
+ return 1
+ ;;
+ esac
+ done
+ shift $(( OPTIND - 1 ))
+
+ 1=${1#zle-} # Strip prefix not stored in zle-hook types style
+
+ if (( list )); then
+ zstyle -L "zle-(${1:-${(@j:|:)hooktypes[@]}})" widgets
+ return $?
+ elif (( help || $# != 2 || ${hooktypes[(I)$1]} == 0 )); then
+ print -u$(( 2 - help )) $usage
+ return $(( 1 - help ))
+ fi
+
+ local -aU extant_hooks
+ local hook="zle-$1"
+ local fn="$2"
+
+ if (( del )); then
+ # delete, if hook is set
+ if zstyle -g extant_hooks "$hook" widgets; then
+ if (( del == 2 )); then
+ set -A extant_hooks ${extant_hooks[@]:#(<->:|)${~fn}}
+ else
+ set -A extant_hooks ${extant_hooks[@]:#(<->:|)$fn}
+ fi
+ # unset if no remaining entries
+ if (( ${#extant_hooks} )); then
+ zstyle "$hook" widgets "${extant_hooks[@]}"
+ else
+ zstyle -d "$hook" widgets
+ fi
+ fi
+ else
+ # Check whether attempting to add a widget named for the hook
+ if [[ "$fn" = "$hook" ]]; then
+ if [[ -n "${widgets[$fn]}" ]]; then
+ print -u2 "$funcstack[1]: Cannot hook $fn to itself"
+ return 1
+ fi
+ # No point in building the array until another is added
+ autoload "${autoopts[@]}" -- "$fn"
+ zle -N "$fn"
+ return 0
+ fi
+ integer i=${#options[ksharrays]}-2
+ zstyle -g extant_hooks "$hook" widgets
+ # Check for an existing widget, add it as the first hook
+ if [[ ${widgets[$hook]} != "user:azhw:$hook" ]]; then
+ if [[ -n ${widgets[$hook]} ]]; then
+ zle -A "$hook" "${widgets[$hook]}"
+ extant_hooks=(0:"${widgets[$hook]}" "${extant_hooks[@]}")
+ fi
+ zle -N "$hook" azhw:"$hook"
+ fi
+ # Add new widget only if not already in the hook list
+ if [[ -z ${(M)extant_hooks[@]:#(<->:|)$fn} ]]; then
+ # no index and not already hooked
+ # assign largest existing index plus 1
+ i=${${(On@)${(@M)extant_hooks[@]#<->:}%:}[i]}+1
+ else
+ return 0
+ fi
+ extant_hooks+=("${i}:${fn}")
+ zstyle -- "$hook" widgets "${extant_hooks[@]}"
+ if [[ -z "${widgets[$fn]}" ]]; then
+ autoload "${autoopts[@]}" -- "$fn"
+ zle -N -- "$fn"
+ fi
+ if [[ -z "${widgets[$hook]}" ]]; then
+ zle -N "$hook" azhw:"$hook"
+ fi
+ fi
+}
+
+} "$@" # Resume caller global options
+
+# Handle zsh autoloading conventions:
+# - "file" appears last in zsh_eval_context when "source"-ing
+# - "evalautofunc" appears with kshautoload set or autoload -k
+# - "loadautofunc" appears with kshautoload unset or autoload -z
+# - use of autoload +X cannot reliably be detected, use best guess
+case "$zsh_eval_context" in
+*file) ;;
+*evalautofunc) ;;
+*loadautofunc) add-zle-hook-widget "$@";;
+*) [[ -o kshautoload ]] || add-zle-hook-widget "$@";;
+esac
+# Note fallback here is equivalent to the usual best-guess used by
+# functions written for zsh before $zsh_eval_context was available
+# so this case-statement is backward-compatible.
diff --git a/Functions/Misc/add-zsh-hook b/Functions/Misc/add-zsh-hook
index fc39659ae..3bc952e2f 100644
--- a/Functions/Misc/add-zsh-hook
+++ b/Functions/Misc/add-zsh-hook
@@ -19,7 +19,7 @@ hooktypes=(
chpwd precmd preexec periodic zshaddhistory zshexit
zsh_directory_name
)
-local usage="Usage: $0 hook function\nValid hooks are:\n $hooktypes"
+local usage="Usage: add-zsh-hook hook function\nValid hooks are:\n $hooktypes"
local opt
local -a autoopts
diff --git a/Functions/Misc/run-help-ip b/Functions/Misc/run-help-ip
index 3f15b01fb..740af52b5 100644
--- a/Functions/Misc/run-help-ip
+++ b/Functions/Misc/run-help-ip
@@ -1,4 +1,4 @@
-#! zsh -f
+#!/bin/zsh -f
#
# Install this function by placing it in your FPATH and then
# adding to your .zshrc the line if you use run-help function:
diff --git a/Functions/Misc/zcalc b/Functions/Misc/zcalc
index 857007a94..480373345 100644
--- a/Functions/Misc/zcalc
+++ b/Functions/Misc/zcalc
@@ -94,24 +94,53 @@
# sequentially just as if read automatically.
emulate -L zsh
-setopt extendedglob
+setopt extendedglob typesetsilent
+
+zcalc_show_value() {
+ if [[ -n $_base ]]; then
+ print -- $(( $_base $1 ))
+ elif [[ $1 = *.* ]] || (( _outdigits )); then
+ # With normal output, ensure trailing "." doesn't get lost.
+ if [[ -z $_forms[_outform] || ($_outform -eq 1 && $1 = *.) ]]; then
+ print -- $(( $1 ))
+ else
+ printf "$_forms[_outform]\n" $_outdigits $1
+ fi
+ else
+ printf "%d\n" $1
+ fi
+}
# For testing in ZLE functions.
local ZCALC_ACTIVE=1
# TODO: make local variables that shouldn't be visible in expressions
# begin with _.
-local line ans base defbase forms match mbegin mend psvar optlist opt arg
+local _line ans _base _defbase _forms match mbegin mend
+local psvar _optlist _opt _arg _tmp
local compcontext="-zcalc-line-"
-integer num outdigits outform=1 expression_mode
-local -a expressions
+integer _num _outdigits _outform=1 _expression_mode
+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"
-forms=( '%2$g' '%.*g' '%.*f' '%.*E' '')
+_forms=( '%2$g' '%.*g' '%.*f' '%.*E' '')
-zmodload -i zsh/mathfunc 2>/dev/null
+local _mathfuncs
+if zmodload -i zsh/mathfunc 2>/dev/null; then
+ zmodload -P _mathfuncs -FL zsh/mathfunc
+ _mathfuncs="("${(j.|.)${_mathfuncs##f:}}")"
+fi
+local -A _userfuncs
+for _line in ${(f)"$(functions -M)"}; do
+ match=(${=_line})
+ # get minimum number of arguments
+ _userfuncs[${match[3]}]=${match[4]}
+done
+_line=
autoload -Uz zmathfuncdef
if (( ! ${+ZCALCPROMPT} )); then
@@ -127,111 +156,119 @@ if [[ -f "${ZDOTDIR:-$HOME}/.zcalcrc" ]]; then
fi
# Process command line
-while [[ -n $1 && $1 = -(|[#-]*|f|e) ]]; do
- optlist=${1[2,-1]}
+while [[ -n $1 && $1 = -(|[#-]*|f|e|r(<->|)) ]]; do
+ _optlist=${1[2,-1]}
shift
- [[ $optlist = (|-) ]] && break
- while [[ -n $optlist ]]; do
- opt=${optlist[1]}
- optlist=${optlist[2,-1]}
- case $opt in
+ [[ $_optlist = (|-) ]] && break
+ while [[ -n $_optlist ]]; do
+ _opt=${_optlist[1]}
+ _optlist=${_optlist[2,-1]}
+ case $_opt in
('#') # Default base
- if [[ -n $optlist ]]; then
- arg=$optlist
- optlist=
+ if [[ -n $_optlist ]]; then
+ _arg=$_optlist
+ _optlist=
elif [[ -n $1 ]]; then
- arg=$1
+ _arg=$1
shift
else
print -- "-# requires an argument" >&2
return 1
fi
- if [[ $arg != (|\#)[[:digit:]]## ]]; then
+ if [[ $_arg != (|\#)[[:digit:]]## ]]; then
print -- "-# requires a decimal number as an argument" >&2
return 1
fi
- defbase="[#${arg}]"
+ _defbase="[#${_arg}]"
;;
(f) # Force floating point operation
setopt forcefloat
;;
(e) # Arguments are expressions
- (( expression_mode = 1 ));
+ (( _expression_mode = 1 ));
+ ;;
+ (r) # RPN mode.
+ (( _rpn_mode = 1 ))
+ ZCALC_ACTIVE=rpn
+ if [[ $_optlist = (#b)(<->)* ]]; then
+ (( _show_stack = ${match[1]} ))
+ _optlist=${_optlist[${#match[1]}+1,-2]}
+ fi
;;
esac
done
done
-if (( expression_mode )); then
- expressions=("$@")
+if (( _expression_mode )); then
+ _expressions=("$@")
argv=()
fi
-for (( num = 1; num <= $#; num++ )); do
+for (( _num = 1; _num <= $#; _num++ )); do
# Make sure all arguments have been evaluated.
# The `$' before the second argv forces string rather than numeric
# substitution.
- (( argv[$num] = $argv[$num] ))
- print "$num> $argv[$num]"
+ (( argv[$_num] = $argv[$_num] ))
+ print "$_num> $argv[$_num]"
done
-psvar[1]=$num
-local prev_line cont_prompt
-while (( expression_mode )) ||
- vared -cehp "${cont_prompt}${ZCALCPROMPT}" line; do
- if (( expression_mode )); then
- (( ${#expressions} )) || break
- line=$expressions[1]
- shift expressions
+psvar[1]=$_num
+local _prev_line _cont_prompt
+while (( _expression_mode )) ||
+ vared -cehp "${_cont_prompt}${ZCALCPROMPT}" _line; do
+ if (( _expression_mode )); then
+ (( ${#_expressions} )) || break
+ _line=$_expressions[1]
+ shift _expressions
fi
- if [[ $line = (|*[^\\])('\\')#'\' ]]; then
- prev_line+=$line[1,-2]
- cont_prompt="..."
- line=
+ if [[ $_line = (|*[^\\])('\\')#'\' ]]; then
+ _prev_line+=$_line[1,-2]
+ _cont_prompt="..."
+ _line=
continue
fi
- line="$prev_line$line"
- prev_line=
- cont_prompt=
+ _line="$_prev_line$_line"
+ _prev_line=
+ _cont_prompt=
# Test whether there are as many open as close
- # parentheses in the line so far.
- if [[ ${#line//[^\(]} -gt ${#line//[^\)]} ]]; then
- prev_line+=$line
- cont_prompt="..."
- line=
+ # parentheses in the _line so far.
+ if [[ ${#_line//[^\(]} -gt ${#_line//[^\)]} ]]; then
+ _prev_line+=$_line
+ _cont_prompt="..."
+ _line=
continue
fi
- [[ -z $line ]] && break
+ [[ -z $_line ]] && break
# special cases
# Set default base if `[#16]' or `[##16]' etc. on its own.
# Unset it if `[#]' or `[##]'.
- if [[ $line = (#b)[[:blank:]]#('[#'(\#|)((<->|)(|_|_<->))']')[[:blank:]]#(*) ]]; then
+ if [[ $_line = (#b)[[:blank:]]#('[#'(\#|)((<->|)(|_|_<->))']')[[:blank:]]#(*) ]]; then
if [[ -z $match[6] ]]; then
if [[ -z $match[3] ]]; then
- defbase=
+ _defbase=
else
- defbase=$match[1]
+ _defbase=$match[1]
fi
- print -s -- $line
- print -- $(( ${defbase} ans ))
- line=
+ print -s -- $_line
+ print -- $(( ${_defbase} ans ))
+ _line=
continue
else
- base=$match[1]
+ _base=$match[1]
fi
else
- base=$defbase
+ _base=$_defbase
fi
- print -s -- $line
+ print -s -- $_line
- line="${${line##[[:blank:]]#}%%[[:blank:]]#}"
- case "$line" in
+ _line="${${_line##[[:blank:]]#}%%[[:blank:]]#}"
+ case "$_line" in
# Escapes begin with a colon
(:(\\|)\!*)
# shell escape: handle completion's habit of quoting the !
- eval ${line##:(\\|)\![[:blank:]]#}
- line=
+ eval ${_line##:(\\|)\![[:blank:]]#}
+ _line=
continue
;;
@@ -241,72 +278,196 @@ while (( expression_mode )) ||
;;
((:|)norm) # restore output format to default
- outform=1
+ _outform=1
;;
((:|)sci[[:blank:]]#(#b)(<->)(#B))
- outdigits=$match[1]
- outform=2
+ _outdigits=$match[1]
+ _outform=2
;;
((:|)fix[[:blank:]]#(#b)(<->)(#B))
- outdigits=$match[1]
- outform=3
+ _outdigits=$match[1]
+ _outform=3
;;
((:|)eng[[:blank:]]#(#b)(<->)(#B))
- outdigits=$match[1]
- outform=4
+ _outdigits=$match[1]
+ _outform=4
;;
(:raw)
- outform=5
+ _outform=5
;;
((:|)local([[:blank:]]##*|))
- eval $line
- line=
+ eval ${_line##:}
+ _line=
continue
;;
((function|:f(unc(tion|)|))[[:blank:]]##(#b)([^[:blank:]]##)(|[[:blank:]]##([^[:blank:]]*)))
zmathfuncdef $match[1] $match[3]
- line=
+ _userfuncs[$match[1]]=${$(functions -Mm $match[1])[4]}
+ _line=
continue
;;
(:*)
print "Unrecognised escape"
- line=
+ _line=
+ continue
+ ;;
+
+ (\$[[:IDENT:]]##)
+ # Display only, no calculation
+ _line=${_line##\$}
+ print -r -- ${(P)_line}
+ _line=
continue
;;
(*)
- # Latest value is stored as a string, because it might be floating
- # point or integer --- we don't know till after the evaluation, and
- # arrays always store scalars anyway.
- #
- # Since it's a string, we'd better make sure we know which
- # base it's in, so don't change that until we actually print it.
- eval "ans=\$(( $line ))"
- # on error $ans is not set; let user re-edit line
- [[ -n $ans ]] || continue
- argv[num++]=$ans
- psvar[1]=$num
+ _line=${${_line##[[:blank:]]##}%%[[:blank:]]##}
+ if [[ _rpn_mode -ne 0 && $_line != '' ]]; then
+ _push=1
+ _matched=1
+ case $_line in
+ (\<[[:IDENT:]]##)
+ ans=${(P)${_line##\<}}
+ ;;
+
+ (\=|pop|\>[[:IDENT:]]#)
+ if (( ${#stack} < 1 )); then
+ print -r -- "${_line}: not enough values on stack" >&2
+ _line=
+ continue
+ fi
+ case $_line in
+ (=)
+ ans=${stack[1]}
+ ;;
+ (pop|\>)
+ _push=0
+ shift stack
+ ;;
+ (\>[[:IDENT:]]##)
+ if [[ ${_line##\>} = (_*|stack|ans|PI|E) ]]; then
+ print "${_line##\>}: reserved variable" >&2
+ _line=
+ continue
+ fi
+ local ${_line##\>}
+ (( ${_line##\>} = ${stack[1]} ))
+ _push=0
+ shift stack
+ ;;
+ (*)
+ print "BUG in special RPN functions" >&2
+ _line=
+ continue
+ ;;
+ esac
+ ;;
+
+ (+|-|\^|\||\&|\*|/|\*\*|\>\>|\<\</)
+ # Operators with two arguments
+ if (( ${#stack} < 2 )); then
+ print -r -- "${_line}: not enough values on stack" >&2
+ _line=
+ continue
+ fi
+ eval "(( ans = \${stack[2]} $_line \${stack[1]} ))"
+ shift 2 stack
+ ;;
+
+ (ldexp|jn|yn|scalb|xy|\<\>)
+ # Functions with two arguments
+ if (( ${#stack} < 2 )); then
+ print -r -- "${_line}: not enough values on stack" >&2
+ _line=
+ continue
+ fi
+ if [[ $_line = (xy|\<\>) ]]; then
+ _tmp=${stack[1]}
+ stack[1]=${stack[2]}
+ stack[2]=$_tmp
+ _push=0
+ else
+ eval "(( ans = ${_line}(\${stack[2]},\${stack[1]}) ))"
+ shift 2 stack
+ fi
+ ;;
+
+ (${~_mathfuncs})
+ # Functions with a single argument.
+ # This is actually a superset, but we should have matched
+ # any that shouldn't be in it in previous cases.
+ if (( ${#stack} < 1 )); then
+ print -r -- "${_line}: not enough values on stack" >&2
+ _line=
+ continue
+ fi
+ eval "(( ans = ${_line}(\${stack[1]}) ))"
+ shift stack
+ ;;
+
+ (${(kj.|.)~_userfuncs})
+ # Get minimum number of arguments to user function
+ _n=${_userfuncs[$_line]}
+ if (( ${#stack} < n_ )); then
+ print -r -- "${_line}: not enough values ($_n) on stack" >&2
+ _line=
+ continue
+ fi
+ _line+="("
+ # least recent elements on stack are earlier arguments
+ for (( _i = _n; _i > 0; _i-- )); do
+ _line+=${stack[_i]}
+ (( _i > 1 )) && _line+=","
+ done
+ _line+=")"
+ shift $_n stack
+ eval "(( ans = $_line ))"
+ ;;
+
+ (*)
+ # Treat as expression evaluating to new value to go on stack.
+ _matched=0
+ ;;
+ esac
+ else
+ _matched=0
+ fi
+ if (( ! _matched )); then
+ # Latest value is stored` as a string, because it might be floating
+ # point or integer --- we don't know till after the evaluation, and
+ # arrays always store scalars anyway.
+ #
+ # Since it's a string, we'd better make sure we know which
+ # base it's in, so don't change that until we actually print it.
+ if ! eval "ans=\$(( $_line ))"; then
+ _line=
+ continue
+ fi
+ # on error $ans is not set; let user re-edit _line
+ [[ -n $ans ]] || continue
+ fi
+ argv[_num++]=$ans
+ psvar[1]=$_num
+ (( _push )) && stack=($ans $stack)
;;
esac
- if [[ -n $base ]]; then
- print -- $(( $base $ans ))
- elif [[ $ans = *.* ]] || (( outdigits )); then
- if [[ -z $forms[outform] ]]; then
- print -- $(( $ans ))
- else
- printf "$forms[outform]\n" $outdigits $ans
- fi
+ if (( _show_stack )); then
+ (( _max_stack = (_show_stack > ${#stack}) ? ${#stack} : _show_stack ))
+ for (( _i = _max_stack; _i > 0; _i-- )); do
+ printf "%3d: " $_i
+ zcalc_show_value ${stack[_i]}
+ done
else
- printf "%d\n" $ans
+ zcalc_show_value $ans
fi
- line=
+ _line=
done
return 0
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
index eb8f557ea..0ea90c7df 100644
--- a/Functions/Misc/zed
+++ b/Functions/Misc/zed
@@ -6,6 +6,8 @@
# Use ^X^W to save, ^C to abort.
# Option -f: edit shell functions. (Also if called as fned.)
+setopt localoptions noksharrays
+
local var opts zed_file_name
# We do not want timeout while we are editing a file
integer TMOUT=0 okargs=1 fun bind
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
index 472c10d5d..18ba89a9a 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git
@@ -213,8 +213,12 @@ elif [[ -d "${gitdir}/rebase-merge" ]]; then
local p
[[ -f "${patchdir}/done" ]] &&
for p in ${(f)"$(< "${patchdir}/done")"}; do
- # remove action
- git_patches_applied+=("${${(s: :)p}[2,-1]}")
+ # pick/edit/fixup/squash/reword: Add "$hash $subject" to $git_patches_applied.
+ # exec: Add "exec ${command}" to $git_patches_applied.
+ # (anything else): As 'exec'.
+ p=${p/(#s)(p|pick|e|edit|r|reword|f|fixup|s|squash) /}
+ p=${p/(#s)x /exec }
+ git_patches_applied+=("$p")
done
if [[ -f "${patchdir}/git-rebase-todo" ]] ; then
git_patches_unapplied=(${(f)"$(grep -v '^$' "${patchdir}/git-rebase-todo" | grep -v '^#')"})
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
index f35ad5965..69b7db304 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
@@ -40,9 +40,10 @@ VCS_INFO_adjust
# Disabled by default anyway, so no harm done.
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then
if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" use-simple \
- && ( VCS_INFO_check_com hexdump ) && [[ -r ${dirstatefile} ]] ; then
- # Calling hexdump is (much) faster than hg but doesn't get the local rev
- r_csetid=$(hexdump -n 20 -e '1/1 "%02x"' ${dirstatefile})
+ && VCS_INFO_hexdump ${dirstatefile} 20 ; then
+ # Calling VCS_INFO_hexdump is (much) faster than hg but doesn't get
+ # the local rev
+ r_csetid=$REPLY
else
# Settling for a short (but unique!) hash because getting the full
# 40-char hash in addition to all the other info we want isn't
diff --git a/Functions/VCS_Info/VCS_INFO_hexdump b/Functions/VCS_Info/VCS_INFO_hexdump
new file mode 100644
index 000000000..11f1c1a50
--- /dev/null
+++ b/Functions/VCS_Info/VCS_INFO_hexdump
@@ -0,0 +1,16 @@
+## vim:ft=zsh
+
+# VCS_INFO_hexdump FILENAME BYTECOUNT
+#
+# Return in $REPLY a hexadecimal representation (lowercase, no whitespace)
+# of the first BYTECOUNT bytes of FILENAME.
+
+if [[ -r $1 ]]; then
+ setopt localoptions nomultibyte extendedglob
+ local val
+ read -k $2 -u 0 val <$1
+ REPLY=${(Lj::)${(l:2::0:)${(@s//)val}//(#m)*/$(( [##16] ##$MATCH ))}}
+else
+ return 1
+fi
+
diff --git a/Functions/VCS_Info/VCS_INFO_patch2subject b/Functions/VCS_Info/VCS_INFO_patch2subject
new file mode 100644
index 000000000..583467bc8
--- /dev/null
+++ b/Functions/VCS_Info/VCS_INFO_patch2subject
@@ -0,0 +1,50 @@
+# 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.
+{
+ integer i
+ integer -r LIMIT=10
+ local -a lines
+ local needle
+ if [[ -f "$1" ]]; then
+ # Extract the first LIMIT lines, or up to the first empty line or the start of the unidiffs,
+ # whichever comes first.
+ while (( i++ < LIMIT )); do
+ IFS= read -r "lines[$i]"
+ if [[ -z ${lines[$i]} ]] || [[ ${lines[$i]} == (#b)(---|Index:)* ]]; then
+ lines[$i]=()
+ break
+ fi
+ done < "$1"
+
+ if needle=${lines[(i)Subject:*]}; (( needle <= $#lines )); then
+ # "Subject: foo" line, plus rfc822 whitespace unfolding.
+ #
+ # Example: 'git format-patch' patches.
+ REPLY=${lines[needle]}
+ REPLY=${REPLY#*: }
+ REPLY=${REPLY#\[PATCH\] }
+ while [[ ${${lines[++needle]}[1]} == ' ' ]]; do
+ REPLY+=${lines[needle]}
+ done
+ elif needle=${lines[(r)Description:*]}; [[ -n $needle ]]; then
+ # "Description: foo" line.
+ #
+ # Example: DEP-3 patches.
+ REPLY=${needle#*: }
+ elif [[ ${lines[1]} == '# HG changeset patch' ]] && { needle=${${lines:#([#]*)}[1]}; [[ -n $needle ]] }; then
+ # Mercurial patch
+ REPLY=$needle
+ elif (( ${+lines[1]} )); then
+ # The first line of the file is not part of the diff.
+ REPLY=${lines[1]}
+ else
+ # The patch has no subject.
+ unset REPLY
+ return 0
+ fi
+ else
+ # The patch cannot be examined, or invalid arguments.
+ unset REPLY
+ return 1
+ fi
+}
diff --git a/Functions/VCS_Info/VCS_INFO_quilt b/Functions/VCS_Info/VCS_INFO_quilt
index c3c3d864d..4c61506cd 100644
--- a/Functions/VCS_Info/VCS_INFO_quilt
+++ b/Functions/VCS_Info/VCS_INFO_quilt
@@ -80,6 +80,10 @@ function VCS_INFO_quilt-dirfind() {
return ${ret}
}
+function VCS_INFO_quilt-patch2subject() {
+ VCS_INFO_patch2subject "$@"
+}
+
function VCS_INFO_quilt() {
emulate -L zsh
setopt extendedglob
@@ -119,7 +123,7 @@ function VCS_INFO_quilt() {
applied=()
fi
patches=$(<$pc/.quilt_patches)
- patches=`builtin cd -q "${pc:h}" && print -r - ${patches:A}`
+ patches=`builtin cd -q "${pc:h}" && print -r - ${patches:P}`
fi
if zstyle -t "${context}" get-unapplied; then
# This zstyle call needs to be moved further up if `quilt' needs
@@ -147,27 +151,19 @@ function VCS_INFO_quilt() {
if [[ -n $patches ]]; then
() {
- local i line
+ local i
for ((i=1; i<=$#applied; i++)); do
- if [[ -f "$patches/$applied[$i]" ]] &&
- read -r line < "$patches/$applied[$i]" &&
- [[ $line != (#b)(---|Index:)* ]] &&
- true
- ;
+ if VCS_INFO_quilt-patch2subject "$patches/$applied[$i]" && (( $+REPLY ))
then
- applied[$i]+=" $line"
+ applied[$i]+=" $REPLY"
else
applied[$i]+=" ?"
fi
done
for ((i=1; i<=$#unapplied; i++)); do
- if [[ -f "$patches/$unapplied[$i]" ]] &&
- read -r line < "$patches/$unapplied[$i]" &&
- [[ $line != (#b)(---|Index:)* ]] &&
- true
- ;
+ if VCS_INFO_quilt-patch2subject "$patches/$unapplied[$i]" && (( $+REPLY ))
then
- unapplied[$i]+=" $line"
+ unapplied[$i]+=" $REPLY"
else
unapplied[$i]+=" ?"
fi
diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
index f13f6b501..24ae98e52 100644
--- a/Functions/VCS_Info/vcs_info
+++ b/Functions/VCS_Info/vcs_info
@@ -19,9 +19,11 @@ static_functions=(
VCS_INFO_check_com
VCS_INFO_formats
VCS_INFO_get_cmd
+ VCS_INFO_hexdump
VCS_INFO_hook
VCS_INFO_maxexports
VCS_INFO_nvcsformats
+ VCS_INFO_patch2subject
VCS_INFO_quilt
VCS_INFO_realpath
VCS_INFO_reposub
diff --git a/Functions/Zle/bracketed-paste-magic b/Functions/Zle/bracketed-paste-magic
index 2b2bc630d..fb584d595 100644
--- a/Functions/Zle/bracketed-paste-magic
+++ b/Functions/Zle/bracketed-paste-magic
@@ -20,7 +20,7 @@
# active-widgets
# Looked up in the context :bracketed-paste-magic to obtain a list of
# patterns that match widget names that should be activated during the
-# paste. All other key sequences are processed as self-insert-unmeta.
+# paste. All other key sequences are processed as "zle .self-insert".
# The default is 'self-*' so any user-defined widgets named with that
# prefix are active along with the builtin self-insert. If this style is
# not set (note: it must be explicitly deleted after loading this
@@ -31,7 +31,7 @@
#
# inactive-keys
# This is the inverse of active-widgets, it lists key sequences that
-# always use self-insert-unmeta even when bound to an active-widget.
+# always use "zle .self-insert" even when bound to an active-widget.
# Note that this is a list of literal key sequences, not patterns.
# This style is in context :bracketed-paste-magic and has no default.
#
@@ -145,27 +145,26 @@ bracketed-paste-magic() {
done
fi
- # Save context, create a clean slate for the paste
- integer bpm_mark=$MARK bpm_cursor=$CURSOR bpm_region=$REGION_ACTIVE
- integer bpm_numeric=${NUMERIC:-1}
- local bpm_buffer=$BUFFER
- fc -p -a /dev/null 0 0
- BUFFER=
-
zstyle -a :bracketed-paste-magic inactive-keys bpm_inactive
if zstyle -s :bracketed-paste-magic active-widgets bpm_active '|'; then
- # There are active widgets. Reprocess $PASTED as keystrokes.
- NUMERIC=1
- zle -U - $PASTED
-
+ # Save context, create a clean slate for the paste
+ integer bpm_mark=$MARK bpm_region=$REGION_ACTIVE
+ integer bpm_numeric=${NUMERIC:-1}
+ integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO
+ BUFFER=
+ CURSOR=1
+ zle .split-undo
+ UNDO_LIMIT_NO=$UNDO_CHANGE_NO
+ fc -p -a /dev/null 0 0
if [[ $bmp_keymap = vicmd ]]; then
zle -K viins
fi
+ # There are active widgets. Reprocess $PASTED as keystrokes.
+ NUMERIC=1
+ zle -U - "$PASTED"
+
# Just in case there are active undo widgets
- zle .split-undo
- integer bpm_limit=$UNDO_LIMIT_NO bpm_undo=$UNDO_CHANGE_NO
- UNDO_LIMIT_NO=$UNDO_CHANGE_NO
while [[ -n $PASTED ]] && zle .read-command; do
PASTED=${PASTED#$KEYS}
@@ -175,7 +174,7 @@ bracketed-paste-magic() {
case $REPLY in
(${~bpm_active}) function () {
emulate -L $bpm_emulate; set -$bpm_opts
- zle $REPLY
+ zle $REPLY -w
};;
(*) zle .self-insert;;
esac
@@ -183,21 +182,16 @@ bracketed-paste-magic() {
done
PASTED=$BUFFER
- # Reset the undo state
- zle undo $bpm_undo
- UNDO_LIMIT_NO=$bpm_limit
-
+ # Restore state
zle -K $bpm_keymap
+ fc -P
+ MARK=$bpm_mark
+ REGION_ACTIVE=$bpm_region
+ NUMERIC=$bpm_numeric
+ zle .undo $bpm_undo
+ UNDO_LIMIT_NO=$bpm_limit
fi
- # Restore state
- BUFFER=$bpm_buffer
- MARK=$bpm_mark
- CURSOR=$bpm_cursor
- REGION_ACTIVE=$bpm_region
- NUMERIC=$bpm_numeric
- fc -P
-
# PASTED has been updated, run the paste-finish functions
if zstyle -a :bracketed-paste-magic paste-finish bpm_hooks; then
for bpm_func in $bpm_hooks; do
@@ -212,7 +206,7 @@ bracketed-paste-magic() {
# Reprocess $PASTED as an actual paste this time
zle -U - $PASTED$'\e[201~' # append paste-end marker
- zle .bracketed-paste
+ zle .bracketed-paste -- "$@"
zle .split-undo
# Arrange to display highlighting if necessary
diff --git a/Functions/Zle/bracketed-paste-url-magic b/Functions/Zle/bracketed-paste-url-magic
index 06dee2657..b894696bb 100644
--- a/Functions/Zle/bracketed-paste-url-magic
+++ b/Functions/Zle/bracketed-paste-url-magic
@@ -19,7 +19,7 @@
# The default can be seen just below.
local -a schema
-zstyle -a :bracketed-paste-url-magic schema schema || schema=(http https ftp ftps file ssh sftp)
+zstyle -a :bracketed-paste-url-magic schema schema || schema=(http:// https:// ftp:// ftps:// file:// ssh:// sftp:// magnet:)
local wantquote=${NUMERIC:-0}
local content
@@ -28,7 +28,7 @@ local start=$#LBUFFER
zle .$WIDGET -N content
if (( $wantquote == 0 )); then
- if [[ $content = (${(~j:|:)schema})://* ]]; then
+ if [[ $content = (${(~j:|:)schema})* ]]; then
wantquote=1
fi
fi
diff --git a/Functions/Zle/delete-whole-word-match b/Functions/Zle/delete-whole-word-match
index aece86065..3d52dd3d7 100644
--- a/Functions/Zle/delete-whole-word-match
+++ b/Functions/Zle/delete-whole-word-match
@@ -12,30 +12,29 @@ emulate -L zsh
setopt extendedglob
local curcontext=:zle:$WIDGET
-local -a matched_words
+local -A matched_words
# Start and end of range of characters to remove.
integer pos1 pos2
autoload -Uz match-words-by-style
match-words-by-style
-if [[ -n "${matched_words[3]}" ]]; then
- # There's whitespace before the cursor, so the word we are deleting
- # starts at the cursor position.
+if (( ${matched_words[is-word-start]} )); then
+ # The word we are deleting starts at the cursor position.
pos1=$CURSOR
else
- # No whitespace before us, so delete any wordcharacters there.
- pos1="${#matched_words[1]}"
+ # Not, so delete any wordcharacters before, too
+ pos1="${#matched_words[start]}"
fi
-if [[ -n "${matched_words[4]}" ]]; then
+if [[ -n "${matched_words[ws-after-cursor]}" ]]; then
# There's whitespace at the cursor position, so only delete
# up to the cursor position.
(( pos2 = CURSOR + 1 ))
else
# No whitespace at the cursor position, so delete the
# current character and any following wordcharacters.
- (( pos2 = CURSOR + ${#matched_words[5]} + 1 ))
+ (( pos2 = CURSOR + ${#matched_words[word-after-cursor]} + 1 ))
fi
# Move the cursor then delete the block in one go for the
diff --git a/Functions/Zle/expand-absolute-path b/Functions/Zle/expand-absolute-path
index b85757600..4887f3c60 100644
--- a/Functions/Zle/expand-absolute-path
+++ b/Functions/Zle/expand-absolute-path
@@ -10,7 +10,7 @@ autoload -Uz modify-current-argument
if (( ! ${+functions[glob-expand-absolute-path]} )); then
glob-expand-absolute-path() {
local -a files
- files=(${~1}(N:A))
+ files=(${~1}(N:P))
(( ${#files} )) || return
REPLY=${(D)files[1]}
}
diff --git a/Functions/Zle/history-beginning-search-menu b/Functions/Zle/history-beginning-search-menu
index 105518102..0e1bbc734 100644
--- a/Functions/Zle/history-beginning-search-menu
+++ b/Functions/Zle/history-beginning-search-menu
@@ -112,7 +112,7 @@ fi
# go to the last one. This allows accept-line-and-down-history etc.
# to work.
local -a lines
-local matchq=${matches[$chars]//(#m)[\][()\\*?#<>~^]/\\$MATCH}
+local matchq=${matches[$chars]//(#m)[\][|()\\*?#<>~^]/\\$MATCH}
lines=(${(kon)history[(R)$matchq]})
HISTNO=$lines[-1]
diff --git a/Functions/Zle/match-words-by-style b/Functions/Zle/match-words-by-style
index 54e019d23..fc59c2764 100644
--- a/Functions/Zle/match-words-by-style
+++ b/Functions/Zle/match-words-by-style
@@ -5,8 +5,16 @@
# <whitespace-after-cursor> <word-after-cursor> <whitespace-after-word>
# <stuff-at-end>
# where the cursor position is always after the third item and `after'
-# is to be interpreted as `after or on'. Some
-# of the array elements will be empty; this depends on the style.
+# is to be interpreted as `after or on'.
+#
+# matched_words may be an associative array, in which case the
+# values above are now given by the elements named start, word-before-cursor,
+# ws-before-cursor, ws-after-cursor, word-after-cursor, ws-after-word,
+# end. In addition, the element is-word-start is 1 if the cursor
+# is on the start of a word; this is non-trivial in the case of subword
+# (camel case) matching as there may be no white space to test.
+#
+# Some of the array elements will be empty; this depends on the style.
# For example
# foo bar rod stick
# ^
@@ -202,7 +210,7 @@ if [[ $wordstyle = *subword* ]]; then
# followed by a lower case letter, or an upper case letter at
# the start of a group of upper case letters. To make
# it easier to be consistent, we just use anything that
- # isn't an upper case characer instead of a lower case
+ # isn't an upper case character instead of a lower case
# character.
# Here the initial "*" will match greedily, so we get the
# last such match, as we want.
@@ -224,11 +232,18 @@ charskip=${(l:skip::?:)}
eval pat2='${RBUFFER##(#b)('${charskip}${spacepat}')('\
${wordpat2}')('${spacepat}')}'
+if [[ -n $match[2] ]]; then
+ ws2=$match[1]
+ word2=$match[2]
+ ws3=$match[3]
+else
+ # No more words, so anything left is white space after cursor.
+ ws2=$RBUFFER
+ pat2=
+fi
-ws2=$match[1]
-word2=$match[2]
-ws3=$match[3]
-
+integer wordstart
+[[ ( -n $ws1 || -n $ws2 ) && -n $word2 ]] && wordstart=1
if [[ $wordstyle = *subword* ]]; then
# Do we have a group of upper case characters at the start
# of word2 (that don't form the entire word)?
@@ -237,12 +252,19 @@ if [[ $wordstyle = *subword* ]]; then
-n $match[2] ]]; then
# Yes, so the last one is new word boundary.
(( epos = ${#match[1]} - 1 ))
+ # Otherwise, are we in the middle of a word?
+ # In other, er, words, we've got something on the left with no
+ # white space following and something that doesn't start a word here.
+ elif [[ -n $word1 && -z $ws1 && -z $ws2 && \
+ $word2 = (#b)([^${~subwordrange}]##)* ]]; then
+ (( epos = ${#match[1]} ))
# Otherwise, do we have upper followed by non-upper not
# at the start? Ignore the initial character, we already
# know it's a word boundary so it can be an upper case character
# if it wants.
elif [[ $word2 = (#b)(?[^${~subwordrange}]##)[${~subwordrange}]* ]]; then
(( epos = ${#match[1]} ))
+ (( wordstart = 1 ))
else
(( epos = 0 ))
fi
@@ -256,4 +278,19 @@ if [[ $wordstyle = *subword* ]]; then
fi
fi
-matched_words=("$pat1" "$word1" "$ws1" "$ws2" "$word2" "$ws3" "$pat2")
+# matched_words should be local to caller.
+# Just fix type here.
+if [[ ${(t)matched_words} = *association* ]]; then
+ matched_words=(
+ start "$pat1"
+ word-before-cursor "$word1"
+ ws-before-cursor "$ws1"
+ ws-after-cursor "$ws2"
+ word-after-cursor "$word2"
+ ws-after-word "$ws3"
+ end "$pat2"
+ is-word-start $wordstart
+ )
+else
+ matched_words=("$pat1" "$word1" "$ws1" "$ws2" "$word2" "$ws3" "$pat2")
+fi
diff --git a/Functions/Zle/select-bracketed b/Functions/Zle/select-bracketed
index 00f51be2c..d467bb804 100644
--- a/Functions/Zle/select-bracketed
+++ b/Functions/Zle/select-bracketed
@@ -12,6 +12,8 @@
# done
# done
+setopt localoptions noksharrays
+
local style=${${1:-$KEYS}[1]} matching="(){}[]<>bbBB"
local -i find=${NUMERIC:-1} idx=${matching[(I)[${${1:-$KEYS}[2]}]]}%9
(( idx )) || return 1 # no corresponding closing bracket
diff --git a/Functions/Zle/select-word-match b/Functions/Zle/select-word-match
new file mode 100644
index 000000000..8440852ab
--- /dev/null
+++ b/Functions/Zle/select-word-match
@@ -0,0 +1,120 @@
+# Select the entire word around the cursor. Intended for use as
+# a vim-style text object in vi mode but with customisable
+# word boundaries.
+#
+# For example:
+# autoload -U select-word-match
+# zle -N select-in-camel select-word-match
+# bindkey -M viopp ic select-in-camel
+# zstyle ':zle:*-camel' word-style normal-subword
+
+emulate -L zsh
+setopt extendedglob
+
+local curcontext=:zle:$WIDGET
+local -A matched_words
+# Start and end of range of characters
+integer pos1 pos2 num=${NUMERIC:-1}
+local style word
+
+# choose between inner word or a word style of widget
+for style in $1 ${${WIDGET#*-}[1]} $KEYS[1] "i"; do
+ [[ $style = [ai] ]] && break
+done
+
+autoload -Uz match-words-by-style
+
+while (( num-- )); do
+ if (( MARK > CURSOR )); then
+ # if cursor is at the start of the selection, just move back a word
+ match-words-by-style
+ if [[ $style = i && -n $matched_words[ws-before-cursor] ]]; then
+ word=$matched_words[ws-before-cursor]
+ else
+ word=$matched_words[word-before-cursor]$matched_words[ws-before-cursor]
+ fi
+ if [[ -n $word ]]; then
+ (( CURSOR -= ${#word} ))
+ else
+ return 1
+ fi
+ elif (( MARK >= 0 && MARK < CURSOR )); then
+ # cursor at the end, move forward a word
+ (( CURSOR+1 == $#BUFFER )) && return 1
+ (( CURSOR++ ))
+ match-words-by-style
+ if [[ -n $matched_words[ws-after-cursor] ]]; then
+ if [[ $style = i ]]; then
+ # just skip the whitespace
+ word=$matched_words[ws-after-cursor]
+ else
+ # skip the whitespace plus word
+ word=$matched_words[ws-after-cursor]$matched_words[word-after-cursor]
+ fi
+ else
+ if [[ $style = i ]]; then
+ # skip the word
+ word=$matched_words[word-after-cursor]
+ else
+ # skip word and following whitespace
+ word=$matched_words[word-after-cursor]$matched_words[ws-after-word]
+ fi
+ fi
+ (( CURSOR += ${#word} - 1 ))
+ else
+ match-words-by-style
+
+ if (( ${matched_words[is-word-start]} )); then
+ # The word we are selecting starts at the cursor position.
+ pos1=$CURSOR
+ else
+ # No whitespace before us, so select any wordcharacters there.
+ pos1="${#matched_words[start]}"
+ fi
+
+ if [[ -n "${matched_words[ws-after-cursor]}" ]]; then
+ if [[ -n "${matched_words[ws-before-cursor]}" ]] || (( CURSOR == 0 )); then
+ # whitespace either side, select it
+ (( pos1 = CURSOR - ${#matched_words[ws-before-cursor]} ))
+ (( pos2 = CURSOR + ${#matched_words[ws-after-cursor]} ))
+ else
+ # There's whitespace at the cursor position, so only select
+ # up to the cursor position.
+ (( pos2 = CURSOR + 1 ))
+ fi
+ else
+ # No whitespace at the cursor position, so select the
+ # current character and any following wordcharacters.
+ (( pos2 = CURSOR + ${#matched_words[word-after-cursor]} ))
+ fi
+
+ if [[ $style = a ]]; then
+ if [[ -n "${matched_words[ws-after-cursor]}" && ( -n "${matched_words[ws-before-cursor]}" || CURSOR -eq 0 ) ]]; then
+ # in the middle of whitespace so grab a word
+ if [[ -n "${matched_words[word-after-cursor]}" ]]; then
+ (( pos2 += ${#matched_words[word-after-cursor]} )) # preferably the one after
+ else
+ (( pos1 -= ${#matched_words[word-before-cursor]} )) # otherwise the one before
+ fi
+ elif [[ -n "${matched_words[ws-after-word]}" ]]; then
+ (( pos2 += ${#matched_words[ws-after-word]} ))
+ elif [[ -n "${matched_words[ws-before-cursor]}" ]]; then
+ # couldn't grab whitespace forwards so try backwards
+ (( pos1 -= ${#matched_words[ws-before-cursor]} ))
+ elif (( pos1 > 0 )); then
+ # There might have been whitespace before the word
+ (( CURSOR = pos1 ))
+ match-words-by-style
+ if [[ -n "${matched_words[ws-before-cursor]}" ]]; then
+ (( pos1 -= ${#matched_words[ws-before-cursor]} ))
+ fi
+ fi
+ fi
+
+ (( MARK = pos1, CURSOR = pos2-1 ))
+ fi
+done
+
+if [[ $KEYMAP == vicmd ]] && (( !REGION_ACTIVE )); then
+ (( CURSOR++ )) # Need to include cursor position for operators
+fi
diff --git a/Functions/Zle/surround b/Functions/Zle/surround
index b7be30b75..b51b77c04 100644
--- a/Functions/Zle/surround
+++ b/Functions/Zle/surround
@@ -19,6 +19,7 @@ local before after
local -A matching
matching=( \( \) \{ \} \< \> \[ \] )
+zle -f vichange
case $WIDGET in
change-*)
local MARK="$MARK" CURSOR="$CURSOR" call
@@ -69,7 +70,11 @@ case $WIDGET in
before="${(k)matching[(r)[$before:q]]}"
fi
CUTBUFFER="$before$CUTBUFFER$after"
- zle .vi-put-after -n 1
+ if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then
+ zle .vi-put-before -n 1
+ else
+ zle .vi-put-after -n 1
+ fi
CUTBUFFER="$save_cut" CURSOR="$save_cur"
;;
esac
diff --git a/Functions/Zle/vi-pipe b/Functions/Zle/vi-pipe
new file mode 100644
index 000000000..1729cb6e1
--- /dev/null
+++ b/Functions/Zle/vi-pipe
@@ -0,0 +1,39 @@
+# Example of a widget that takes a vi motion
+
+# Filter part of buffer corresponding to a vi motion through an external
+# program.
+
+# To enable with vi compatible bindings use:
+# autoload -Uz vi-pipe
+# bindkey -a '!' vi-pipe
+
+setopt localoptions noksharrays
+
+autoload -Uz read-from-minibuffer
+local _save_cut="$CUTBUFFER" REPLY
+
+# mark this widget as a vi change so it can be repeated as a whole
+zle -f vichange
+
+# force movement to default to line mode
+(( REGION_ACTIVE )) || zle -U V
+# Use the standard vi-change to accept a vi motion.
+zle .vi-change || return
+read-from-minibuffer "!"
+zle .vi-cmd-mode
+local _save_cur=$CURSOR
+
+# cut buffer contains the deleted text and can be modified
+CUTBUFFER=$(eval "$REPLY" <<<"$CUTBUFFER")
+
+# put the modified text back in position.
+if [[ CURSOR -eq 0 || $BUFFER[CURSOR] = $'\n' ]]; then
+ # at the beginning of a line, vi-delete won't have moved the cursor
+ # back to a previous line
+ zle .vi-put-before -n 1
+else
+ zle .vi-put-after -n 1
+fi
+
+# restore cut buffer and cursor to the start of the range
+CUTBUFFER="$_save_cut" CURSOR="$_save_cur"
diff --git a/Functions/Zle/zcalc-auto-insert b/Functions/Zle/zcalc-auto-insert
index c9a5c8867..e1affd1c3 100644
--- a/Functions/Zle/zcalc-auto-insert
+++ b/Functions/Zle/zcalc-auto-insert
@@ -1,6 +1,7 @@
# Bind to a binary operator keystroke for use with zcalc
+# Not useful in RPN mode.
-if [[ -n $ZCALC_ACTIVE ]]; then
+if [[ -n $ZCALC_ACTIVE && $ZCALC_ACTIVE != rpn ]]; then
if [[ $CURSOR -eq 0 || $LBUFFER[-1] = "(" ]]; then
LBUFFER+=${ZCALC_AUTO_INSERT_PREFIX:-"ans "}
fi