summaryrefslogtreecommitdiff
path: root/Functions
diff options
context:
space:
mode:
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Calendar/calendar_parse2
-rw-r--r--Functions/Chpwd/.distfiles1
-rw-r--r--Functions/Chpwd/cdr2
-rw-r--r--Functions/Chpwd/zsh_directory_name_cdr25
-rw-r--r--Functions/Misc/add-zsh-hook7
-rw-r--r--Functions/Misc/colors2
-rw-r--r--Functions/Misc/sticky-note2
-rw-r--r--Functions/Prompts/prompt_bigfade_setup2
-rw-r--r--Functions/TCP/tcp_read2
-rw-r--r--Functions/VCS_Info/.distfiles2
-rw-r--r--Functions/VCS_Info/Backends/.distfiles2
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_detect_fossil13
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_detect_hg2
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_detect_svn2
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil24
-rw-r--r--Functions/VCS_Info/Backends/VCS_INFO_get_data_hg2
-rw-r--r--Functions/VCS_Info/VCS_INFO_bydir_detect10
-rw-r--r--Functions/VCS_Info/VCS_INFO_hook18
-rw-r--r--Functions/VCS_Info/VCS_INFO_set6
-rw-r--r--Functions/VCS_Info/vcs_info7
-rw-r--r--Functions/VCS_Info/vcs_info_hookadd22
-rw-r--r--Functions/VCS_Info/vcs_info_hookdel45
-rw-r--r--Functions/Zftp/zfcput2
-rw-r--r--Functions/Zle/.distfiles1
-rw-r--r--Functions/Zle/modify-current-argument44
-rw-r--r--Functions/Zle/send-invisible85
-rw-r--r--Functions/Zle/split-shell-arguments2
27 files changed, 298 insertions, 36 deletions
diff --git a/Functions/Calendar/calendar_parse b/Functions/Calendar/calendar_parse
index 1025a9a25..fabaf7413 100644
--- a/Functions/Calendar/calendar_parse
+++ b/Functions/Calendar/calendar_parse
@@ -1,7 +1,7 @@
# Parse the line passed down in the first argument as a calendar entry.
# Sets the values parsed into the associative array reply, consisting of:
# time The time as an integer (as per EPOCHSECONDS) of the (next) event.
-# text1 The text from the the line not including the date/time, but
+# text1 The text from the line not including the date/time, but
# including any WARN or RPT text. This is useful for rescheduling
# events, since the keywords need to be retained in this case.
# warntime Any warning time (WARN keyword) as an integer, else an empty
diff --git a/Functions/Chpwd/.distfiles b/Functions/Chpwd/.distfiles
index 39ccd830c..89779a686 100644
--- a/Functions/Chpwd/.distfiles
+++ b/Functions/Chpwd/.distfiles
@@ -5,4 +5,5 @@ _cdr
chpwd_recent_add
chpwd_recent_dirs
chpwd_recent_filehandler
+zsh_directory_name_cdr
'
diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr
index 3025a9d5c..4f399106b 100644
--- a/Functions/Chpwd/cdr
+++ b/Functions/Chpwd/cdr
@@ -15,7 +15,7 @@
# changing directory permanently, see below.
#
# The argument to cdr is a number corresponding to the Nth most recently
-# changed-to directory starting at 1 for the immediately preceeding
+# changed-to directory starting at 1 for the immediately preceding
# directory (the current directory is remembered but is not offered as a
# destination). You can use directory arguments if you set the
# recent-dirs-default style, see below; however, it should be noted
diff --git a/Functions/Chpwd/zsh_directory_name_cdr b/Functions/Chpwd/zsh_directory_name_cdr
new file mode 100644
index 000000000..09aa35a93
--- /dev/null
+++ b/Functions/Chpwd/zsh_directory_name_cdr
@@ -0,0 +1,25 @@
+if [[ $1 = n ]]; then
+ if [[ $2 = <-> ]]; then
+ # Recent directory
+ typeset -ga reply
+ autoload -Uz cdr
+ cdr -r
+ if [[ -n ${reply[$2]} ]]; then
+ reply=(${reply[$2]})
+ return 0
+ else
+ reply=()
+ return 1
+ fi
+ fi
+elif [[ $1 = c ]]; then
+ if [[ $PREFIX = <-> || -z $PREFIX ]]; then
+ typeset -a keys values
+ values=(${${(f)"$(cdr -l)"}/ ##/:})
+ keys=(${values%%:*})
+ _describe -t dir-index 'recent directory index' \
+ values keys -V unsorted -S']'
+ return
+ fi
+fi
+return 1
diff --git a/Functions/Misc/add-zsh-hook b/Functions/Misc/add-zsh-hook
index aedc1e754..c49688643 100644
--- a/Functions/Misc/add-zsh-hook
+++ b/Functions/Misc/add-zsh-hook
@@ -1,6 +1,6 @@
# Add to HOOK the given FUNCTION.
# HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory,
-# zshexit (the _functions subscript is not required).
+# zshexit, zsh_directory_name (the _functions subscript is not required).
#
# With -d, remove the function from the hook instead; delete the hook
# variable if it is empty.
@@ -15,7 +15,10 @@
emulate -L zsh
local -a hooktypes
-hooktypes=(chpwd precmd preexec periodic zshaddhistory zshexit)
+hooktypes=(
+ chpwd precmd preexec periodic zshaddhistory zshexit
+ zsh_directory_name
+)
local opt
local -a autoopts
diff --git a/Functions/Misc/colors b/Functions/Misc/colors
index bef93c8c3..027ca9a14 100644
--- a/Functions/Misc/colors
+++ b/Functions/Misc/colors
@@ -1,6 +1,8 @@
# Put standard ANSI color codes in shell parameters for easy use.
# Note that some terminals do not support all combinations.
+emulate -L zsh
+
typeset -Ag color colour
color=(
diff --git a/Functions/Misc/sticky-note b/Functions/Misc/sticky-note
index cfe9ea684..efe5ec1eb 100644
--- a/Functions/Misc/sticky-note
+++ b/Functions/Misc/sticky-note
@@ -19,7 +19,7 @@
#
# Otherwise, invoke the line editor with the previous notes available
# as an editor history. Two quick taps on the return/enter key finish
-# the note, or you can use use ^X^W as usual (ZZ in vicmd mode).
+# the note, or you can use ^X^W as usual (ZZ in vicmd mode).
# The application is configured by three zstyles, all using the context
# ":sticky-note". The first two styles are "notefile" and "maxnotes"
diff --git a/Functions/Prompts/prompt_bigfade_setup b/Functions/Prompts/prompt_bigfade_setup
index 4e9aafdb1..2d95f3143 100644
--- a/Functions/Prompts/prompt_bigfade_setup
+++ b/Functions/Prompts/prompt_bigfade_setup
@@ -31,7 +31,7 @@ prompt_bigfade_setup () {
autoload -Uz prompt_special_chars
prompt_special_chars
- PS1="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$userhost}%K{$fadebar}%n@%m%b%k%f%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%b%f%k%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$date}%K{black} %D{%a %b %d} %D{%I:%M:%S%P}$prompt_newline%B%F{$cwd}%K{black}$PWD>%b%f%k "
+ PS1="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$userhost}%K{$fadebar}%n@%m%b%k%f%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%b%f%k%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$date}%K{black} %D{%a %b %d} %D{%I:%M:%S%P}$prompt_newline%B%F{$cwd}%K{black}%d>%b%f%k "
PS2="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%b%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$fadebar}>%b%f%k "
prompt_opts=(cr subst percent)
diff --git a/Functions/TCP/tcp_read b/Functions/TCP/tcp_read
index 7d8acf865..f880395dd 100644
--- a/Functions/TCP/tcp_read
+++ b/Functions/TCP/tcp_read
@@ -1,7 +1,7 @@
# Helper function for reading input from a TCP connection.
# Actually, the input doesn't need to be a TCP connection at all, it
# is simply an input file descriptor. However, it must be contained
-# in ${tcp_by_fd[$TCP_SESS]}. This is set set by tcp_open, but may be
+# in ${tcp_by_fd[$TCP_SESS]}. This is set by tcp_open, but may be
# set by hand. (Note, however, the blocking/timeout behaviour is usually
# not implemented for reading from regular files.)
#
diff --git a/Functions/VCS_Info/.distfiles b/Functions/VCS_Info/.distfiles
index 988e7ada4..b6e55d2fc 100644
--- a/Functions/VCS_Info/.distfiles
+++ b/Functions/VCS_Info/.distfiles
@@ -1,6 +1,8 @@
DISTFILES_SRC='
.distfiles
vcs_info
+vcs_info_hookadd
+vcs_info_hookdel
VCS_INFO_adjust
VCS_INFO_bydir_detect
VCS_INFO_check_com
diff --git a/Functions/VCS_Info/Backends/.distfiles b/Functions/VCS_Info/Backends/.distfiles
index 46e9d6e67..67fb06cda 100644
--- a/Functions/VCS_Info/Backends/.distfiles
+++ b/Functions/VCS_Info/Backends/.distfiles
@@ -4,6 +4,7 @@ VCS_INFO_detect_bzr
VCS_INFO_detect_cdv
VCS_INFO_detect_cvs
VCS_INFO_detect_darcs
+VCS_INFO_detect_fossil
VCS_INFO_detect_git
VCS_INFO_detect_hg
VCS_INFO_detect_mtn
@@ -15,6 +16,7 @@ VCS_INFO_get_data_bzr
VCS_INFO_get_data_cdv
VCS_INFO_get_data_cvs
VCS_INFO_get_data_darcs
+VCS_INFO_get_data_fossil
VCS_INFO_get_data_git
VCS_INFO_get_data_hg
VCS_INFO_get_data_mtn
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_fossil b/Functions/VCS_Info/Backends/VCS_INFO_detect_fossil
new file mode 100644
index 000000000..551528361
--- /dev/null
+++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_fossil
@@ -0,0 +1,13 @@
+## vim:ft=zsh
+## fossil support by: Mike Meyer <mwm@mired.org>
+## Distributed under the same BSD-ish license as zsh itself.
+
+setopt localoptions NO_shwordsplit
+
+[[ $1 == '--flavours' ]] && return 1
+
+VCS_INFO_check_com ${vcs_comm[cmd]} || return 1
+vcs_comm[detect_need_file]=_FOSSIL_
+VCS_INFO_bydir_detect . || return 1
+
+return 0
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_hg b/Functions/VCS_Info/Backends/VCS_INFO_detect_hg
index e2866afd5..a22c1ee0f 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_detect_hg
+++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_hg
@@ -7,7 +7,7 @@ setopt localoptions NO_shwordsplit
[[ $1 == '--flavours' ]] && { print -l hg-git hg-hgsubversion hg-hgsvn; return 0 }
VCS_INFO_check_com ${vcs_comm[cmd]} || return 1
-vcs_comm[detect_need_file]=store
+vcs_comm[detect_need_file]="store data"
VCS_INFO_bydir_detect '.hg' || return 1
if [[ -d ${vcs_comm[basedir]}/.hg/svn ]] ; then
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_svn b/Functions/VCS_Info/Backends/VCS_INFO_detect_svn
index bb9d083ac..a777ecc43 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_detect_svn
+++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_svn
@@ -7,5 +7,5 @@ setopt localoptions NO_shwordsplit
[[ $1 == '--flavours' ]] && return 1
VCS_INFO_check_com ${vcs_comm[cmd]} || return 1
-[[ -d ".svn" ]] && return 0
+{ [[ -f ".svn/entries" ]] || [[ -f ".svn/format" ]] } && return 0
return 1
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil b/Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil
new file mode 100644
index 000000000..fd0f8389e
--- /dev/null
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil
@@ -0,0 +1,24 @@
+## vim:ft=zsh
+## fossil support by: Mike Meyer (mwm@mired.org)
+## Distributed under the same BSD-ish license as zsh itself.
+
+setopt localoptions extendedglob
+local a b
+local -A fsinfo
+local fshash fsbranch changed merging action
+
+${vcs_comm[cmd]} status |
+ while IFS=: read a b; do
+ fsinfo[${a//-/_}]="${b## #}"
+ done
+
+fshash=${fsinfo[checkout]%% *}
+fsbranch=${fsinfo[tags]%%, *}
+changed=${(Mk)fsinfo:#(ADDED|EDITED|DELETED|UPDATED)*}
+merging=${(Mk)fsinfo:#*_BY_MERGE*}
+if [ -n "$merging" ]; then
+ action="merging"
+fi
+
+VCS_INFO_formats "$action" "${fsbranch}" "${fsinfo[local_root]}" '' "$changed" "${fshash}" "${fsinfo[repository]}"
+return 0
diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
index 8e91d2651..a1b87f59e 100644
--- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
+++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg
@@ -50,7 +50,7 @@ if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then
"check-for-changes" || hgid_args+=( -r. )
local HGRCPATH
- HGRCPATH="/dev/null" ${vcs_comm[cmd]} ${(z)hgid_args} \
+ HGRCPATH="/dev/null" ${vcs_comm[cmd]} ${(z)hgid_args} 2> /dev/null \
| read -r r_csetid r_lrev r_branch
fi
fi
diff --git a/Functions/VCS_Info/VCS_INFO_bydir_detect b/Functions/VCS_Info/VCS_INFO_bydir_detect
index 0b5996fd8..70b0fb6fa 100644
--- a/Functions/VCS_Info/VCS_INFO_bydir_detect
+++ b/Functions/VCS_Info/VCS_INFO_bydir_detect
@@ -4,15 +4,17 @@
setopt localoptions NO_shwordsplit
local dirname=$1
-local basedir="." realbasedir
+local basedir="." realbasedir file
realbasedir="$(VCS_INFO_realpath ${basedir})"
while [[ ${realbasedir} != '/' ]]; do
[[ -r ${realbasedir} ]] || return 1
if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
- [[ -d ${basedir}/${dirname} ]] && \
- [[ -e ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
- break
+ [[ -d ${basedir}/${dirname} ]] && {
+ for file in ${(s: :)${vcs_comm[detect_need_file]}}; do
+ [[ -e ${basedir}/${dirname}/${file} ]] && break 2
+ done
+ }
else
[[ -d ${basedir}/${dirname} ]] && break
fi
diff --git a/Functions/VCS_Info/VCS_INFO_hook b/Functions/VCS_Info/VCS_INFO_hook
index 7274d726f..479f5968b 100644
--- a/Functions/VCS_Info/VCS_INFO_hook
+++ b/Functions/VCS_Info/VCS_INFO_hook
@@ -2,24 +2,36 @@
## Written by Frank Terbeck <ft@bewatermyfriend.org>
## Distributed under the same BSD-ish license as zsh itself.
-local hook func
+local hook static func
local -x context hook_name
local -xi ret
-local -a hooks
+local -a hooks tmp
local -i debug
ret=0
hook_name="$1"
shift
context=":vcs_info:${vcs}+${hook_name}:${usercontext}:${rrn}"
+static=":vcs_info-static_hooks:${hook_name}"
zstyle -t "${context}" debug && debug=1 || debug=0
if (( debug )); then
printf 'VCS_INFO_hook: running hook: "%s"\n' "${hook_name}"
printf 'VCS_INFO_hook: current context: "%s"\n' "${context}"
+ printf 'VCS_INFO_hook: static context: "%s"\n' "${static}"
fi
-zstyle -a "${context}" hooks hooks || return 0
+zstyle -a "${static}" hooks hooks
+if (( debug )); then
+ printf '+ static hooks: %s\n' "${(j:, :)hooks}"
+fi
+zstyle -a "${context}" hooks tmp
+if (( debug )); then
+ printf '+ context hooks: %s\n' "${(j:, :)tmp}"
+fi
+hooks+=( "${tmp[@]}" )
+(( ${#hooks} == 0 )) && return 0
+
# Protect some internal variables in hooks. The `-g' parameter to
# typeset does *not* make the parameters global here (they are already
# "*-local-export). It prevents typeset from creating *new* *local*
diff --git a/Functions/VCS_Info/VCS_INFO_set b/Functions/VCS_Info/VCS_INFO_set
index a2b838cdb..5087be43f 100644
--- a/Functions/VCS_Info/VCS_INFO_set
+++ b/Functions/VCS_Info/VCS_INFO_set
@@ -5,17 +5,13 @@
setopt localoptions noksharrays NO_shwordsplit
local -i i j
-if [[ $1 == '--clear' ]] ; then
- for i in {0..9} ; do
- unset vcs_info_msg_${i}_
- done
-fi
if [[ $1 == '--nvcs' ]] ; then
[[ $2 == '-preinit-' ]] && (( maxexports == 0 )) && (( maxexports = 1 ))
for i in {0..$((maxexports - 1))} ; do
typeset -gx vcs_info_msg_${i}_=
done
VCS_INFO_nvcsformats $2
+ [[ $2 != '-preinit-' ]] && VCS_INFO_hook "no-vcs"
fi
(( ${#msgs} - 1 < 0 )) && return 0
diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
index 6ce1cd702..513489b70 100644
--- a/Functions/VCS_Info/vcs_info
+++ b/Functions/VCS_Info/vcs_info
@@ -26,6 +26,8 @@ static_functions=(
VCS_INFO_reposub
VCS_INFO_set
+ vcs_info_hookadd
+ vcs_info_hookdel
vcs_info_lastmsg
vcs_info_printsys
vcs_info_setsys
@@ -35,6 +37,7 @@ for func in ${static_functions} ; do
autoload -Uz ${func}
done
+[[ -n ${(Mk)parameters:#vcs_info_msg_<->_} ]] && unset ${parameters[(I)vcs_info_msg_<->_]}
VCS_INFO_set --nvcs '-preinit-'
vcs_info_setsys
@@ -75,7 +78,7 @@ vcs_info () {
(( ${#enabled} == 0 )) && enabled=( all )
if [[ -n ${(M)enabled:#(#i)none} ]] ; then
- [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --clear
+ [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --nvcs
return 0
fi
@@ -88,7 +91,7 @@ vcs_info () {
for pat in ${dps} ; do
if [[ ${PWD} == ${~pat} ]] ; then
- [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --clear
+ [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --nvcs
return 0
fi
done
diff --git a/Functions/VCS_Info/vcs_info_hookadd b/Functions/VCS_Info/vcs_info_hookadd
new file mode 100644
index 000000000..867f7e271
--- /dev/null
+++ b/Functions/VCS_Info/vcs_info_hookadd
@@ -0,0 +1,22 @@
+## vim:ft=zsh
+## Written by Frank Terbeck <ft@bewatermyfriend.org>
+## Distributed under the same BSD-ish license as zsh itself.
+
+emulate -L zsh
+setopt extendedglob
+
+if (( ${#argv} < 2 )); then
+ print 'usage: vcs_info_hookadd <HOOK> <FUNCTION(s)...>'
+ return 1
+fi
+
+local hook func context
+local -a old
+
+hook=$1
+shift
+context=":vcs_info-static_hooks:${hook}"
+
+zstyle -a "${context}" hooks old
+zstyle "${context}" hooks "${old[@]}" "$@"
+return $?
diff --git a/Functions/VCS_Info/vcs_info_hookdel b/Functions/VCS_Info/vcs_info_hookdel
new file mode 100644
index 000000000..e09a0575e
--- /dev/null
+++ b/Functions/VCS_Info/vcs_info_hookdel
@@ -0,0 +1,45 @@
+## vim:ft=zsh
+## Written by Frank Terbeck <ft@bewatermyfriend.org>
+## Distributed under the same BSD-ish license as zsh itself.
+
+emulate -L zsh
+setopt extendedglob
+
+local -i all
+
+if [[ "x$1" == 'x-a' ]]; then
+ all=1
+ shift
+else
+ all=0
+fi
+
+if (( ${#argv} < 2 )); then
+ print 'usage: vcs_info_hookdel [-a] <HOOK> <FUNCTION(s)...>'
+ return 1
+fi
+
+local hook func context
+local -a old
+
+hook=$1
+shift
+context=":vcs_info-static_hooks:${hook}"
+
+zstyle -a "${context}" hooks old || return 0
+for func in "$@"; do
+ if [[ -n ${(M)old:#$func} ]]; then
+ old[(Re)$func]=()
+ else
+ printf 'Not statically registered to `%s'\'': "%s"\n' \
+ "${hook}" "${func}"
+ continue
+ fi
+ if (( all )); then
+ while [[ -n ${(M)old:#$func} ]]; do
+ old[(Re)$func]=()
+ done
+ fi
+done
+zstyle "${context}" hooks "${old[@]}"
+return $?
diff --git a/Functions/Zftp/zfcput b/Functions/Zftp/zfcput
index d8a8a60a3..85141b68d 100644
--- a/Functions/Zftp/zfcput
+++ b/Functions/Zftp/zfcput
@@ -23,7 +23,7 @@ if [[ $(echo abcd | tail +2c) = bcd ]]; then
elif [[ $(echo abcd | tail --bytes=+2) = bcd ]]; then
tailtype=b
else
- print "I can't get your \`tail' to start from from arbitrary characters.\n" \
+ print "I can't get your \`tail' to start from arbitrary characters.\n" \
"If you know how to do this, let me know." 2>&1
return 1
fi
diff --git a/Functions/Zle/.distfiles b/Functions/Zle/.distfiles
index 2ec4adc22..22eef1e6e 100644
--- a/Functions/Zle/.distfiles
+++ b/Functions/Zle/.distfiles
@@ -33,6 +33,7 @@ read-from-minibuffer
replace-string
replace-string-again
select-word-style
+send-invisible
smart-insert-last-word
split-shell-arguments
transpose-lines
diff --git a/Functions/Zle/modify-current-argument b/Functions/Zle/modify-current-argument
index 92ca7bdab..92851d600 100644
--- a/Functions/Zle/modify-current-argument
+++ b/Functions/Zle/modify-current-argument
@@ -14,7 +14,7 @@
setopt localoptions noksharrays multibyte
local -a reply
-integer REPLY REPLY2
+integer REPLY REPLY2 fromend endoffset
autoload -Uz split-shell-arguments
split-shell-arguments
@@ -30,6 +30,13 @@ if (( REPLY & 1 )); then
(( REPLY2 = ${#reply[REPLY]} + 1 ))
fi
+# Work out offset from end of string
+(( fromend = $REPLY2 - ${#reply[REPLY]} - 1 ))
+if (( fromend >= -1 )); then
+ # Cursor is near the end of the word, we'll try to keep it there.
+ endoffset=1
+fi
+
# Length of all characters before current.
# Force use of character (not index) counting and join without IFS.
integer wordoff="${(cj..)#reply[1,REPLY-1]}"
@@ -37,15 +44,32 @@ integer wordoff="${(cj..)#reply[1,REPLY-1]}"
# Replacement for current word. This could do anything to ${reply[REPLY]}.
local ARG="${reply[REPLY]}" repl
eval repl=\"$1\"
+
+if (( !endoffset )) && [[ ${repl[fromend,-1]} = ${ARG[fromend,-1]} ]]; then
+ # If the part of the string from here to the end hasn't changed,
+ # leave the cursor this distance from the end instead of the beginning.
+ endoffset=1
+fi
+
# New line: all words before and after current word, with
# no additional spaces since we've already got the whitespace
# and the replacement word in the middle.
-BUFFER="${(j..)reply[1,REPLY-1]}${repl}${(j..)reply[REPLY+1,-1]}"
-
-# Keep cursor at same position in replaced word.
-# Redundant here, but useful if $repl changes the length.
-# Limit to the next position after the end of the word.
-integer repmax=$(( ${#repl} + 1 ))
-# Remember CURSOR starts from offset 0 for some reason, so
-# subtract 1 from positions.
-(( CURSOR = wordoff + (REPLY2 > repmax ? repmax : REPLY2) - 1 ))
+local left="${(j..)reply[1,REPLY-1]}${repl}"
+local right="${(j..)reply[REPLY+1,-1]}"
+
+if [[ endoffset -ne 0 && ${#repl} -ne 0 ]]; then
+ # Place cursor relative to end.
+ LBUFFER="$left"
+ RBUFFER="$right"
+ (( CURSOR += fromend ))
+else
+ BUFFER="$left$right"
+
+ # Keep cursor at same position in replaced word.
+ # Redundant here, but useful if $repl changes the length.
+ # Limit to the next position after the end of the word.
+ integer repmax=$(( ${#repl} + 1 ))
+ # Remember CURSOR starts from offset 0 for some reason, so
+ # subtract 1 from positions.
+ (( CURSOR = wordoff + (REPLY2 > repmax ? repmax : REPLY2) - 1 ))
+fi
diff --git a/Functions/Zle/send-invisible b/Functions/Zle/send-invisible
new file mode 100644
index 000000000..d31fc76ae
--- /dev/null
+++ b/Functions/Zle/send-invisible
@@ -0,0 +1,85 @@
+#autoload
+
+# send-invisible reads a line from the terminal, displaying an
+# asterisk for each character typed. It stores the line in the
+# global variable INVISIBLE, and when finished reading, inserts
+# the string ${INVISIBLE} into the original command buffer.
+
+# If one argument is given, it is the prompt. The default is
+# "Non-echoed text: "
+
+# If two or three arguments are given, they form the prefix and
+# suffix of the inserted INVISIBLE. Defaults are '${' and '}'
+# but these can be replaced, for example with '"${' and '}"' to
+# enclose the whole word in double quotes, or '${(z)' and '}' to
+# split the value of $INVISIBLE like the shell parser.
+
+# To use:
+# autoload -Uz send-invisible
+# zle -N send-invisible
+# bindkey '^X ' send-invisible
+# Or more elaborately:
+# hidden-command() { send-invisible '% ' '${(z)' '}' }
+# zle -N hidden-command
+# bindkey '^X%' hidden-command
+
+# Shamelessly cribbed from read-from-minibuffer.
+
+emulate -L zsh
+
+# Hide the value of INVISIBLE in any output of set and typeset
+typeset -g -H INVISIBLE=
+
+local pretext="$PREDISPLAY$LBUFFER$RBUFFER$POSTDISPLAY"$'\n'
+
+# Can't directly make these locals because send-invisible is
+# called as a widget, so these special variables are already
+# local at the current level and wouldn't get restored
+local save_lbuffer=$LBUFFER
+local save_rbuffer=$RBUFFER
+local save_predisplay=$PREDISPLAY
+local save_postdisplay=$POSTDISPLAY
+local -a save_region_highlight
+save_region_highlight=("${region_highlight[@]}")
+
+{
+ local lb rb opn=${2:-'${'} cls=${3:-'}'}
+ LBUFFER=
+ RBUFFER=
+ PREDISPLAY="$pretext${1:-Non-echoed text: }"
+ POSTDISPLAY=
+ region_highlight=("P${(m)#pretext} ${(m)#PREDISPLAY} bold")
+
+ while zle -R && zle .read-command
+ do
+ # There are probably more commands that should go into
+ # the first clause here to harmlessly beep, because ...
+ case $REPLY in
+ (send-invisible|run-help|undefined-key|where-is|which-command)
+ zle .beep;;
+ (push-*|send-break) INVISIBLE=;&
+ (accept-*) break;;
+ (*)
+ LBUFFER=$lb
+ RBUFFER=$rb
+ zle $REPLY # ... this could expose something
+ lb=$LBUFFER
+ rb=$RBUFFER
+ INVISIBLE=$BUFFER
+ LBUFFER=${(l:$#LBUFFER::*:):-}
+ RBUFFER=${(l:$#RBUFFER::*:):-}
+ ;;
+ esac
+ done
+} always {
+ LBUFFER=$save_lbuffer
+ RBUFFER=$save_rbuffer
+ PREDISPLAY=$save_predisplay
+ POSTDISPLAY=$save_postdisplay
+ region_highlight=("${save_region_highlight[@]}")
+ zle -R
+
+ # Now that the highlight has been restored with all the old
+ # text and cursor positioning, insert the new text.
+ LBUFFER+=${INVISIBLE:+${opn}INVISIBLE${cls}}
+}
diff --git a/Functions/Zle/split-shell-arguments b/Functions/Zle/split-shell-arguments
index ee737a067..32b04fcb5 100644
--- a/Functions/Zle/split-shell-arguments
+++ b/Functions/Zle/split-shell-arguments
@@ -15,7 +15,7 @@ local -a bufwords lbufwords
local word
integer pos=1 cpos=$((CURSOR+1)) opos iword ichar
-bufwords=(${(z)BUFFER})
+bufwords=(${(Z+n+)BUFFER})
reply=()
while [[ ${BUFFER[pos]} = [[:space:]] ]]; do