summaryrefslogtreecommitdiff
path: root/Functions
diff options
context:
space:
mode:
Diffstat (limited to 'Functions')
-rw-r--r--Functions/Misc/.distfiles3
-rw-r--r--Functions/Misc/allopt28
-rw-r--r--Functions/Misc/checkmail26
-rw-r--r--Functions/Misc/colors79
-rw-r--r--Functions/Misc/harden6
-rw-r--r--Functions/Misc/is-at-least38
-rw-r--r--Functions/Misc/mere83
-rw-r--r--Functions/Misc/nslookup48
-rw-r--r--Functions/Misc/run-help88
-rw-r--r--Functions/Misc/zed70
-rw-r--r--Functions/Misc/zkbd248
-rw-r--r--Functions/Misc/zmv268
-rw-r--r--Functions/Misc/zrecompile244
-rw-r--r--Functions/Misc/zstyle+35
14 files changed, 1264 insertions, 0 deletions
diff --git a/Functions/Misc/.distfiles b/Functions/Misc/.distfiles
index 9e276f99b..414abad59 100644
--- a/Functions/Misc/.distfiles
+++ b/Functions/Misc/.distfiles
@@ -1,3 +1,6 @@
DISTFILES_SRC='
.distfiles
+allopt harden nslookup zkbd zstyle+
+checkmail is-at-least run-help zmv
+colors mere zed zrecompile
'
diff --git a/Functions/Misc/allopt b/Functions/Misc/allopt
new file mode 100644
index 000000000..0d59fa3e9
--- /dev/null
+++ b/Functions/Misc/allopt
@@ -0,0 +1,28 @@
+# This function lists options with the no's in front removed for
+# improved comprehension, i.e. `norcs off' becomes `rcs on'.
+# The format is otherwise like that with `kshoptionprint' set,
+# i.e. you can see all options whether on or off.
+# It can take a list of option names or parts thereof to search for
+# via egrep.
+#
+# Written by Sweth Chandramouli with hacks by Bart Schaefer.
+
+listalloptions () {
+ builtin setopt localoptions kshoptionprint
+ local OPT_NAME OPT_PAIR OPT_VALUE
+ for OPT_PAIR in "${(f)$(builtin setopt)}" ; do
+ OPT_VALUE=${OPT_PAIR##* }
+ OPT_NAME=${OPT_PAIR%% *}
+ if [[ ${OPT_NAME#no} != ${OPT_NAME} ]] ; then
+ OPT_VALUE=${(L)${${OPT_VALUE:s/on/OFF}:s/off/on}}
+ OPT_NAME=${OPT_NAME#no}
+ fi
+ echo "${(r:21:)OPT_NAME} ${OPT_VALUE}"
+ done
+}
+
+if [[ -n $@ ]]; then
+ listalloptions | egrep "${(j.|.)@}"
+else
+ listalloptions
+fi
diff --git a/Functions/Misc/checkmail b/Functions/Misc/checkmail
new file mode 100644
index 000000000..9cc743db4
--- /dev/null
+++ b/Functions/Misc/checkmail
@@ -0,0 +1,26 @@
+#! /usr/local/bin/zsh
+#
+# This autoloadable function checks the folders specified as arguments
+# for new mails. The arguments are interpeted in exactly the same way
+# as the mailpath special zsh parameter (see zshparam(1)).
+#
+# If no arguments are given mailpath is used. If mailpath is empty, $MAIL
+# is used and if that is also empty, /var/spool/mail/$LOGNAME is used.
+# This function requires zsh-3.0.1 or newer.
+#
+
+local file message
+
+for file in "${@:-${mailpath[@]:-${MAIL:-/var/spool/mail/$LOGNAME}}}"
+do
+ message="${${(M)file%%\?*}#\?}"
+ file="${file%%\?*}"
+ if [[ -d "$file" ]] then
+ file=( "$file"/**/*(.ND) )
+ if (($#file)) then
+ checkmail "${^file}\?$message"
+ fi
+ elif test -s "$file" -a -N "$file"; then # this also sets $_ to $file
+ print -r -- "${(e)message:-You have new mail.}"
+ fi
+done
diff --git a/Functions/Misc/colors b/Functions/Misc/colors
new file mode 100644
index 000000000..6778cbd49
--- /dev/null
+++ b/Functions/Misc/colors
@@ -0,0 +1,79 @@
+# Put standard ANSI color codes in shell parameters for easy use.
+# Note that some terminals do not support all combinations.
+
+typeset -Ag color colour
+
+color=(
+# Attribute codes:
+ 00 none
+ 01 bold
+ 02 faint 22 normal
+ 03 standout 23 no-standout
+ 04 underline 24 no-underline
+ 05 blink 25 no-blink
+ 07 reverse 27 no-reverse
+ 08 conceal
+
+# Text color codes:
+ 30 black 40 bg-black
+ 31 red 41 bg-red
+ 32 green 42 bg-green
+ 33 yellow 43 bg-yellow
+ 34 blue 44 bg-blue
+ 35 magenta 45 bg-magenta
+ 36 cyan 46 bg-cyan
+ 37 white 47 bg-white
+ 39 default 49 bg-default
+)
+
+# A word about black and white: The "normal" shade of white is really a
+# very pale grey on many terminals; to get truly white text, you have to
+# use bold white, and to get a truly white background you have to use
+# bold reverse white bg-xxx where xxx is your desired foreground color
+# (and which means the foreground is also bold).
+
+# Map in both directions; could do this with e.g. ${(k)colors[(i)normal]},
+# but it's clearer to include them all both ways.
+
+local k
+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
+
+# 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]}
+
+# Assistance for the color-blind.
+
+colour=(${(kv)color}) # A case where ksh namerefs would be useful ...
+
+# The following are terminal escape sequences used by colored prompt themes.
+
+local lc=$'\e[' rc=m # Standard ANSI terminal escape values
+
+typeset -Hg reset_color bold_color
+reset_color="$lc${color[none]}$rc"
+bold_color="$lc${color[bold]}$rc"
+
+# Foreground
+
+typeset -AHg fg fg_bold fg_no_bold
+for k in ${(k)color[(I)fg-*]}; do
+ fg[${k#fg-}]="$lc${color[$k]}$rc"
+ fg_bold[${k#fg-}]="$lc${color[bold]};${color[$k]}$rc"
+ fg_no_bold[${k#fg-}]="$lc${color[normal]};${color[$k]}$rc"
+done
+
+# Background
+
+typeset -AHg bg bg_bold bg_no_bold
+for k in ${(k)color[(I)bg-*]}; do
+ bg[${k#bg-}]="$lc${color[$k]}$rc"
+ bg_bold[${k#bg-}]="$lc${color[bold]};${color[$k]}$rc"
+ bg_no_bold[${k#bg-}]="$lc${color[normal]};${color[$k]}$rc"
+done
diff --git a/Functions/Misc/harden b/Functions/Misc/harden
new file mode 100644
index 000000000..c02689362
--- /dev/null
+++ b/Functions/Misc/harden
@@ -0,0 +1,6 @@
+#! /bin/sh
+# harden a link (convert it to a singly linked file)
+cp $1 $1.foo
+rm $1
+mv $1.foo $1
+
diff --git a/Functions/Misc/is-at-least b/Functions/Misc/is-at-least
new file mode 100644
index 000000000..6debe4c5a
--- /dev/null
+++ b/Functions/Misc/is-at-least
@@ -0,0 +1,38 @@
+#
+# Test whether $ZSH_VERSION (or some value of your choice, if a second argument
+# is provided) is greater than or equal to x.y.z-r (in argument one). In fact,
+# it'll accept any dot/dash-separated string of numbers as its second argument
+# and compare it to the dot/dash-separated first argument. Leading non-number
+# parts of a segment (such as the "zefram" in 3.1.2-zefram4) are not considered
+# when the comparison is done; only the numbers matter. Any left-out segments
+# in the first argument that are present in the version string compared are
+# considered as zeroes, eg 3 == 3.0 == 3.0.0 == 3.0.0.0 and so on.
+#
+# Usage examples:
+# is-at-least 3.1.6-15 && setopt NO_GLOBAL_RCS
+# is-at-least 3.1.0 && setopt HIST_REDUCE_BLANKS
+# is-at-least 586 $MACHTYPE && echo 'You could be running Mandrake!'
+# is-at-least $ZSH_VERSION || print 'Something fishy here.'
+
+emulate zsh ; setopt LOCAL_OPTIONS
+
+local IFS=".-" min_cnt=0 ver_cnt=0 part min_ver version
+
+min_ver=(${=1})
+version=(${=2:-$ZSH_VERSION} 0)
+
+while (( $min_cnt <= ${#min_ver} )); do
+ while [[ "$part" != <-> ]]; do
+ (( ++ver_cnt > ${#version} )) && return 0
+ part=${version[ver_cnt]##*[^0-9]}
+ done
+
+ while true; do
+ (( ++min_cnt > ${#min_ver} )) && return 0
+ [[ ${min_ver[min_cnt]} = <-> ]] && break
+ done
+
+ (( part > min_ver[min_cnt] )) && return 0
+ (( part < min_ver[min_cnt] )) && return 1
+ part=''
+done
diff --git a/Functions/Misc/mere b/Functions/Misc/mere
new file mode 100644
index 000000000..a9beb2c10
--- /dev/null
+++ b/Functions/Misc/mere
@@ -0,0 +1,83 @@
+# read a man page
+
+setopt localoptions extendedglob
+
+local manual="$1" col=col terminal=man magic line
+
+# /usr/bin/col on SunOS 4 doesn't support -x.
+if [[ -x /usr/5bin/col ]]; then
+ col=/usr/5bin/col;
+fi
+
+# SunOS 5 has no `man' terminal.
+if [[ -d /usr/share/lib/nterm &&
+ ! -e /usr/share/lib/nterm/tab.$terminal ]]; then
+ terminal=lp;
+fi
+
+# HP-UX has no `man' terminal.
+if [[ -d /usr/share/lib/term &&
+ ! -e /usr/share/lib/term/tab$terminal ]]; then
+ terminal=lp;
+fi
+
+# Unixware has no `man' terminal.
+if [[ -d /usr/ucblib/doctools/nterm &&
+ ! -e /usr/ucblib/doctools/nterm/tab.$terminal ]]; then
+ terminal=lp;
+fi
+
+# Solaris has SGML manuals.
+if [[ -f /usr/lib/sgml/sgml2roff ]] &&
+ [[ "$(read -er < $manual)" = "<!DOCTYPE"* ]]; then
+ /usr/lib/sgml/sgml2roff $manual | {
+ read -r line
+ if [[ $line = ".so "* ]]; then
+ # There is no cascading .so directive.
+ # On Solaris 7, at least.
+ /usr/lib/sgml/sgml2roff ${line#.so }
+ else
+ print -lr - "$line"
+ cat
+ fi
+ }
+else
+ read -u0 -k 2 magic < $manual
+ case $magic in
+ $'\037\235') zcat $manual;;
+ $'\037\213') gzip -dc $manual;;
+ *) cat $manual;;
+ esac
+fi | (
+ # cd is required to work soelim called by nroff.
+ case $manual in
+ */man/man*/*) cd ${manual:h:h};;
+ */man/sman*/*) cd ${manual:h:h};;
+ esac
+ read -r line
+ # The first line beginning with '\" shows preprocessors.
+ # Unknown preprocessors is ignored.
+ if [[ $line = "'\\\" "* ]]; then
+ typeset -A filter
+ filter=(
+ e neqn
+ g grap
+ p pic
+ r refer
+ t tbl
+ v vgrind
+ )
+ eval ${(j:|:)${${(s::)line#\'\\\" }//(#m)?/$filter[$MATCH]}}
+ elif [[ $line = "'\\\"! "* ]]; then
+ typeset -A filter
+ filter=(
+ eqn neqn
+ )
+ eval ${(j:|:)${${${${(s:|:)line#\'\\\"! }# ##}% ##}//(#m)*/$filter[$MATCH]}}
+ else
+ print -lr - "$line"
+ cat
+ fi |
+ nroff -T$terminal -man | $col -x
+) |
+${=MANPAGER:-${PAGER:-more}} -s
diff --git a/Functions/Misc/nslookup b/Functions/Misc/nslookup
new file mode 100644
index 000000000..5b49ae9d2
--- /dev/null
+++ b/Functions/Misc/nslookup
@@ -0,0 +1,48 @@
+# Simple wrapper function for `nslookup'. With completion if you are using
+# the function based completion system.
+
+if [[ $argv[(I)-] -eq 0 && $argv[(I)[^-]*] -ne 0 ]]; then
+ command nslookup "$@"
+ return
+fi
+
+setopt localoptions localtraps completealiases
+
+local tmp line compcontext=nslookup curcontext='nslookup:::' pmpt
+local pager opager="$PAGER"
+typeset +g -x PAGER=cat
+
+zmodload -e zsh/zpty || zmodload -i zsh/zpty
+
+trap 'return 130' INT
+trap 'zpty -d nslookup' EXIT
+
+pmpt=()
+zstyle -s ':nslookup' prompt tmp && pmpt=(-p "$tmp")
+zstyle -s ':nslookup' rprompt tmp && pmpt=("$pmpt[@]" -r "$tmp")
+zstyle -s ':nslookup' pager tmp &&
+ [[ -z "$pager" ]] && pager="${opager:-more}"
+(( $#pmpt )) || pmpt=(-p '> ')
+
+zpty nslookup command nslookup "${(q)@}"
+
+zpty -r nslookup line '*
+> '
+print -nr "$line"
+
+while line=''; vared -he "$pmpt[@]" line; do
+ print -s "$line"
+ [[ "$line" = exit ]] && break
+
+ zpty -w nslookup "$line"
+
+ zpty -r nslookup line '*
+> '
+ if [[ -n "$pager" && ${#${(f)line}} -gt LINES ]]; then
+ print -nr "$line" | eval "$pager"
+ else
+ print -nr "$line"
+ fi
+done
+
+zpty -w nslookup 'exit'
diff --git a/Functions/Misc/run-help b/Functions/Misc/run-help
new file mode 100644
index 000000000..4f447b9f0
--- /dev/null
+++ b/Functions/Misc/run-help
@@ -0,0 +1,88 @@
+#!/usr/local/bin/zsh
+#
+# Figure out where to get the best help, and get it.
+#
+# Install this function by placing it in your FPATH and then
+# adding to your .zshrc the lines:
+# unalias run-help
+# autoload run-help
+#
+
+emulate -R zsh
+setopt localoptions
+
+[[ $1 == "." ]] && 1="dot"
+[[ $1 == ":" ]] && 1="colon"
+
+# Check whether Util/helpfiles has been used to generate zsh help
+if [[ $# == 0 || $1 == "-l" ]]
+then
+ if [[ -n "${HELPDIR:-}" && -d $HELPDIR ]]
+ then
+ echo "Here is a list of topics for which special help is available:"
+ echo ""
+ print -rc $HELPDIR/*(:t)
+ else
+ echo "There is no list of special help topics available at this time."
+ fi
+ return 0
+elif [[ -n "${HELPDIR:-}" && -r $HELPDIR/$1 && $1 != compctl ]]
+then
+ ${=PAGER:-more} $HELPDIR/$1
+ return $?
+fi
+
+# No zsh help; use "whence" to figure out where else we might look
+local what places newline='
+'
+integer i=0 didman=0
+
+places=( "${(@f)$(builtin whence -va $1)}" )
+
+while ((i++ < $#places))
+do
+ what=$places[$i]
+ builtin print -r $what
+ case $what in
+ (*( is an alias)*)
+ [[ ${what[(w)6]:t} != ${what[(w)1]} ]] && run-help ${what[(w)6]:t}
+ ;;
+ (*( is a * function))
+ case ${what[(w)1]} in
+ (comp*) man zshcompsys;;
+ (zf*) man zshftpsys;;
+ (*) builtin functions ${what[(w)1]} | ${=PAGER:-more};;
+ esac;;
+ (*( is a * builtin))
+ case ${what[(w)1]} in
+ (compctl) man zshcompctl;;
+ (comp*) man zshcompwid;;
+ (bindkey|vared|zle) man zshzle;;
+ (*setopt) man zshoptions;;
+ (cap|getcap|setcap) ;&
+ (clone) ;&
+ (ln|mkdir|mv|rm|rmdir|sync) ;&
+ (sched) ;&
+ (stat) man zshmodules;;
+ (zftp) man zshftpsys;;
+ (*) man zshbuiltins;;
+ esac
+ ;;
+ (*( is hashed to *))
+ man ${what[(w)-1]:t}
+ ;;
+ (*( is a reserved word))
+ man zshmisc
+ ;;
+ (*)
+ ((! didman++)) && man $@
+ ;;
+ esac
+ if ((i < $#places && ! didman))
+ then
+ builtin print -nP "%SPress any key for more help or q to quit%s"
+ builtin read -k what
+ [[ $what != $newline ]] && echo
+ [[ $what == [qQ] ]] && break
+ fi
+done
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
new file mode 100644
index 000000000..3cee176a1
--- /dev/null
+++ b/Functions/Misc/zed
@@ -0,0 +1,70 @@
+#
+# zed
+#
+# No other shell could do this.
+# Edit small files with the command line editor.
+# Use ^X^W to save, ^C to abort.
+# Option -f: edit shell functions. (Also if called as fned.)
+#
+# Completion: use
+# compctl -f -x 'w[1,-f]' -F -- zed
+#
+
+local var fun cleanup
+# We do not want timeout while we are editing a file
+integer TMOUT=0
+
+[[ $1 = -f || $0 = fned ]] && fun=1
+[[ $1 = -(|-|f) ]] && shift
+
+[[ -z "$1" ]] && echo 'Usage: "zed filename" or "zed -f function"' && return 1
+
+local curcontext=zed:::
+
+zstyle -m ":completion:zed:*" insert-tab '*' ||
+ zstyle ":completion:zed:*" insert-tab yes
+
+# catch interrupts
+cleanup="$(bindkey -L "^M"; bindkey -L -M emacs "^X^W"; bindkey -aL "ZZ"
+ echo "trap - INT EXIT"; trap)"
+trap "return 130" INT
+trap "$cleanup" EXIT
+
+# don't mangle !'s
+setopt localoptions nobanghist
+
+bindkey "^M" self-insert-unmeta
+# Depending on your stty's, you may be able to use ^J as accept-line, else:
+bindkey -M emacs "^X^W" accept-line
+bindkey -a "ZZ" accept-line
+
+if ((fun)) then
+ var="$(functions $1)"
+ # If function is undefined but autoloadable, load it
+ if [[ $var = *\#\ undefined* ]] then
+ local dir
+ for dir in $fpath; do
+ if [[ -f $dir/$1 ]] then
+ var="$1() {
+$(<$dir/$1)
+}"
+ break
+ fi
+ done
+ elif [[ -z $var ]] then
+ var="$1() {
+}"
+ fi
+ vared var && eval "$cleanup ;" function "$var"
+else
+ [[ -f $1 ]] && var="$(<$1)"
+ while vared var
+ do
+ (print -r -- "$var" >| $1) && break
+ echo -n -e '\a'
+ done
+fi
+
+return 0
+
+# End of zed
diff --git a/Functions/Misc/zkbd b/Functions/Misc/zkbd
new file mode 100644
index 000000000..30cb4a248
--- /dev/null
+++ b/Functions/Misc/zkbd
@@ -0,0 +1,248 @@
+#! /bin/zsh -f
+
+[[ -o interactive ]] && {
+ local -i ARGC
+ (ARGC=0) 2>/dev/null || {
+ print -u2 ${0}: must be run as a function or shell script, not sourced
+ return 1
+ }
+}
+
+emulate -RL zsh
+local zkbd term key seq
+
+zkbd=${ZDOTDIR:-$HOME}/.zkbd
+[[ -d $zkbd ]] || mkdir $zkbd || return 1
+
+print 'typeset -g -A key\n' > $zkbd/$TERM.tmp || return 1
+trap "unfunction getkey getseq; command rm -f $zkbd/$TERM.tmp" 0
+trap "return 1" 1 2 15
+
+getkey () {
+ local k='' i
+ for ((i=10; i>0; --i))
+ do
+ read -t -k 1 k && break
+ sleep 1
+ done
+ [[ -n $k ]] || return 1
+ [[ $k = $'\012' || $k = $'\015' || $k = ' ' ]] && return 0
+ print -Rn $k
+}
+
+getseq () {
+ trap "stty ${$(stty -g 2>/dev/null):-echo -raw}" 0 1 2 15
+ stty raw -echo
+ local k='' seq='' i
+ for ((i=10; i>0; --i))
+ do
+ read -t -k 1 k && break
+ sleep 1
+ done
+ [[ -n $k ]] || return 1
+ [[ $k = $'\012' || $k = $'\015' || $k = ' ' ]] && return 0
+ seq=$k
+ while read -t -k 1 k
+ do
+ seq=$seq$k
+ done
+ print -Rn ${(V)seq}
+}
+
+read term"?Enter current terminal type: [$TERM] "
+[[ -n $term ]] && TERM=$term
+
+cat <<\EOF
+
+We will now test some features of your keyboard and terminal.
+
+If you do not press the requested keys within 10 seconds, key reading will
+abort. If your keyboard does not have a requested key, press Space to
+skip to the next key.
+
+EOF
+
+local ctrl alt meta
+
+print -n "Hold down Ctrl and press X: "
+ctrl=$(getkey) || return 1
+print
+
+if [[ $ctrl != $'\030' ]]
+then
+ print "Your keyboard does not have a working Ctrl key?"
+ print "Giving up ..."
+ return 1
+else
+ print
+fi
+
+print "Your Meta key may have a Microsoft Windows logo on the cap."
+print -n "Hold down Meta and press X: "
+meta=$(getkey) || return 1
+print
+
+if [[ $meta == x ]]
+then
+ print "Your keyboard or terminal does not recognize the Meta key."
+ unset meta
+elif [[ $meta > $'\177' ]]
+then
+ print "Your keyboard uses the Meta key to send high-order characters."
+else
+ unset meta
+fi
+print
+
+print -n "Hold down Alt and press X: "
+alt=$(getkey) || return 1
+print
+
+if [[ $alt == x ]]
+then
+ print "Your keyboard or terminal does not recognize the Alt key."
+ unset alt
+elif [[ $alt == $meta ]]
+then
+ print "Your keyboard does not distinguish Alt from Meta."
+elif [[ $alt > $'\177' ]]
+then
+ print "Your keyboard uses the Alt key to send high-order characters."
+else
+ unset alt
+fi
+
+(( $+alt + $+meta == 0 )) && cat <<EOF
+
+---------
+
+Your current terminal and keyboard configuration does not appear to use
+high-order characters. You may be able to enable the Meta or Alt keys
+with a command such as
+
+ stty pass8
+
+If you want to use these extra keys with zsh, try adding the above command
+to your ${ZDOTDIR:-$HOME}/.zshrc file.
+
+See also "man stty" or the documentation for your terminal or emulator.
+EOF
+
+(( $+alt || $+meta )) && cat <<EOF
+
+---------
+
+You may enable keybindings that use the \
+${meta:+Meta}${meta:+${alt:+ and }}${alt:+Alt} key${meta:+${alt:+s}} \
+by adding
+
+ bindkey -m
+
+to your ${ZDOTDIR:-$HOME}/.zshrc file.
+EOF
+
+cat <<\EOF
+
+---------
+
+You will now be asked to press in turn each of the 12 function keys, then
+the Backspace key, the 6 common keypad keys found on typical PC keyboards,
+plus the 4 arrow keys, and finally the Menu key (near Ctrl on the right).
+If your keyboard does not have the requested key, press Space to skip to
+the next key.
+
+Do not type ahead! Wait at least one second after pressing each key for
+zsh to read the entire sequence and prompt for the next key. If a key
+sequence does not echo within 2 seconds after you press it, that key may
+not be sending any sequence at all. In this case zsh is not able to make
+use of that key. Press Space to skip to the next key.
+
+EOF
+
+read -k 1 key"?Press any key when ready to begin: "
+[[ $key != $'\n' ]] && print
+
+cat <<\EOF
+
+If you do not press a key within 10 seconds, key reading will abort.
+If you make a mistake, stop typing and wait, then run this program again.
+
+EOF
+
+# There are 509 combinations of the following three arrays that represent
+# possible keystrokes. (Actually, Sun keyboards don't have Meta or Menu,
+# though some have R{1..12} keys as well, so really there are either 433
+# or 517 combinations; but some X11 apps map Shift-F{1..11} to emulate the
+# unmodified Sun keys, so really only the 345 PC combinations are usable.
+# Let's not even get into distinguishing Left and Right Shift/Alt/Meta.)
+# No one would ever want to type them all into this program (would they?),
+# so by default ask for the 23 unmodified PC keys. If you uncomment more,
+# you should fix the introductory text above.
+
+local -a pckeys sunkeys modifiers
+pckeys=(F{1..12}
+ Backspace Insert Home PageUp
+ Delete End PageDown
+ Up
+ Left Down Right
+ Menu
+ )
+sunkeys=(Stop Again
+ Props Undo
+ Front Copy
+ Open Paste
+ Find Cut
+ Help
+ )
+modifiers=(Shift- # Control- Alt- Meta-
+ # Control-Shift- Alt-Shift- Meta-Shift-
+ # Control-Alt- Control-Meta- Alt-Meta-
+ # Control-Alt-Shift- Control-Meta-Shift-
+ # Alt-Meta-Shift- Control-Alt-Meta-Shift-
+ )
+
+exec 3>/dev/tty
+
+for key in $pckeys # $^modifiers$^pckeys $sunkeys $^modifiers$^sunkeys
+do
+ print -u3 -Rn "Press $key: "
+ seq="$(getseq)" || return 1
+ print "key[$key]='${(q)seq}'"
+ print -u3 -R $seq
+done >> $zkbd/$TERM.tmp
+
+source $zkbd/$TERM.tmp || return 1
+if [[ "${key[Delete]}" == "${key[Backspace]}" ]]
+then
+ print
+ print Warning: Backspace and Delete key both send "${(q)key[Delete]}"
+else
+ if [[ "${key[Delete]}" != "^?" ]]
+ then
+ print
+ print Warning: Delete key sends "${(q)key[Delete]}" '(not ^?)'
+ fi
+ if [[ "${key[Backspace]}" != "^H" ]]
+ then
+ print
+ print Warning: Backspace sends "${(q)key[Backspace]}"
+ fi
+fi
+
+command mv $zkbd/$TERM.tmp $zkbd/$TERM-$VENDOR-$OSTYPE
+
+cat <<EOF
+
+Parameter assignments for the keys you typed have been written to the file:
+$zkbd/$TERM-$VENDOR-$OSTYPE
+
+You may read this file into ${ZDOTDIR:-$HOME}/.zshrc or another startup
+file with the "source" or "." commands, then reference the \$key parameter
+in bindkey commands, like this:
+
+ source ${zkbd/$HOME/~}/\$TERM-\$VENDOR-\$OSTYPE
+ [[ -n \${key[Left]} ]] && bindkey "\${key[Left]}" backward-char
+ [[ -n \${key[Right]} ]] && bindkey "\${key[Right]}" forward-char
+ # etc.
+
+EOF
diff --git a/Functions/Misc/zmv b/Functions/Misc/zmv
new file mode 100644
index 000000000..b4f9b94ba
--- /dev/null
+++ b/Functions/Misc/zmv
@@ -0,0 +1,268 @@
+# function zmv {
+# zmv, zcp, zln:
+#
+# This is a multiple move based on zsh pattern matching. To get the full
+# power of it, you need a postgraduate degree in zsh. However, simple
+# tasks work OK, so if that's all you need, here are some basic examples:
+# zmv '(*).txt' '$1.lis'
+# Rename foo.txt to foo.lis, etc. The parenthesis is the thing that
+# gets replaced by the $1 (not the `*', as happens in mmv, and note the
+# `$', not `=', so that you need to quote both words).
+# zmv '(**/)(*).txt '$1$2.lis'
+# The same, but scanning through subdirectories. The $1 becomes the full
+# path. Note that you need to write it like this; you can't get away with
+# '(**/*).txt'.
+# zmv -w '**/*.txt' '$1$2.lis'
+# This is the lazy version of the one above; zsh picks out the patterns
+# for you. The catch here is that you don't need the / in the replacement
+# pattern. (It's not really a catch, since $1 can be empty.)
+# zmv -C '**/(*).txt' ~/save/'$1'.lis
+# Copy, instead of move, all .txt files in subdirectories to .lis files
+# in the single directory `~/save'. Note that the ~ was not quoted.
+# You can test things safely by using the `-n' (no, not now) option.
+# Clashes, where multiple files are renamed or copied to the same one, are
+# picked up.
+#
+# Here's a more detailed description.
+#
+# Use zsh pattern matching to move, copy or link files, depending on
+# the last two characters of the function name. The general syntax is
+# zmv '<inpat>' '<outstring>'
+# <inpat> is a globbing pattern, so it should be quoted to prevent it from
+# immediate expansion, while <outstring> is a string that will be
+# re-evaluated and hence may contain parameter substitutions, which should
+# also be quoted. Each set of parentheses in <inpat> (apart from those
+# around glob qualifiers, if you use the -Q option, and globbing flags) may
+# be referred to by a positional parameter in <outstring>, i.e. the first
+# (...) matched is given by $1, and so on. For example,
+# zmv '([a-z])(*).txt' '${(C)1}$2.txt'
+# renames algernon.txt to Algernon.txt, boris.txt to Boris.txt and so on.
+# The original file matched can be referred to as $f in the second
+# argument; accidental or deliberate use of other parameters is at owner's
+# risk and is not covered by the (non-existent) guarantee.
+#
+# As usual in zsh, /'s don't work inside parentheses. There is a special
+# case for (**/) and (***/): these have the expected effect that the
+# entire relevant path will be substituted by the appropriate positional
+# parameter.
+#
+# There is a shortcut avoiding the use of parenthesis with the option -w
+# (with wildcards), which picks out any expressions `*', `?', `<range>'
+# (<->, <1-10>, etc.), `[...]', possibly followed by `#'s, `**/', `***/', and
+# automatically parenthesises them. (You should quote any ['s or ]'s which
+# appear inside [...] and which do not come from ranges of the form
+# `[:alpha:]'.) So for example, in
+# zmv -w '[[:upper:]]*' '${(L)1}$2'
+# the $1 refers to the expression `[[:upper:]]' and the $2 refers to
+# `*'. Thus this finds any file with an upper case first character and
+# renames it to one with a lowercase first character. Note that any
+# existing parentheses are active, too, so you must count accordingly.
+# Furthermore, an expression like '(?)' will be rewritten as '((?))' --- in
+# other words, parenthesising of wildcards is independent of any existing
+# parentheses.
+#
+# Any file whose name is not changed by the substitution is simply ignored.
+# Any error --- a substitution resulted in an empty string, two
+# substitutions gave the same result, the destination was an existing
+# regular file and -f was not given --- causes the entire function to abort
+# without doing anything.
+#
+# Options:
+# -f force overwriting of destination files. Not currently passed
+# down to the mv/cp/ln command due to vagaries of implementations
+# (but you can use -o-f to do that).
+# -i interactive: show each line to be executed and ask the user whether
+# to execute it. Y or y will execute it, anything else will skip it.
+# Note that you just need to type one character.
+# -n no execution: print what would happen, but don't do it.
+# -q Turn bare glob qualifiers off: now assumed by default, so this
+# has no effect.
+# -Q Force bare glob qualifiers on. Don't turn this on unless you are
+# actually using glob qualifiers in a pattern (see below).
+# -s symbolic, passed down to ln; only works with zln or z?? -L.
+# -v verbose: print line as it's being executed.
+# -o <optstring>
+# <optstring> will be split into words and passed down verbatim
+# to the cp, ln or mv called to perform the work. It will probably
+# begin with a `-'.
+# -p <program>
+# Call <program> instead of cp, ln or mv. Whatever it does, it should
+# at least understand the form '<program> -- <oldname> <newname>',
+# where <oldname> and <newname> are filenames generated.
+# -w Pick out wildcard parts of the pattern, as described above, and
+# implicitly add parentheses for referring to them.
+# -C
+# -L
+# -M Force cp, ln or mv, respectively, regardless of the name of the
+# function.
+#
+# Bugs:
+# Parenthesised expressions can be confused with glob qualifiers, for
+# example a trailing '(*)' would be treated as a glob qualifier in
+# ordinary globbing. This has proved so annoying that glob qualifiers
+# are now turned off by default. To force the use of glob qualifiers,
+# give the flag -Q.
+#
+# The second argument is re-evaluated in order to expand the parameters,
+# so quoting may be a bit haphazard. In particular, a double quote
+# will need an extra level of quoting.
+#
+# The pattern is always treated as an extendedglob pattern. This
+# can also be interpreted as a feature.
+#
+# Unbugs:
+# You don't need braces around the 1 in expressions like '$1t' as
+# non-positional parameters may not start with a number, although
+# paranoiacs like the author will probably put them there anyway.
+
+emulate -RL zsh
+setopt extendedglob
+
+local f g args match mbegin mend files action myname tmpf opt exec
+local opt_f opt_i opt_n opt_q opt_Q opt_s opt_M opt_C opt_L
+local opt_o opt_p opt_v opt_w MATCH MBEGIN MEND
+local pat repl errstr fpat hasglobqual opat
+typeset -A from to
+integer stat
+
+while getopts ":o:p:MCLfinqQsvw" opt; do
+ if [[ $opt = "?" ]]; then
+ print -P "%N: unrecognized option: -$OPTARG" >&2
+ return 1
+ fi
+ eval "opt_$opt=${OPTARG:--$opt}"
+done
+(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
+
+[[ -z $opt_Q ]] && setopt nobareglobqual
+[[ -n $opt_M ]] && action=mv
+[[ -n $opt_C ]] && action=cp
+[[ -n $opt_L ]] && action=ln
+[[ -n $opt_p ]] && action=$opt_p
+
+if (( $# != 2 )); then
+ print -P "Usage:
+ %N oldpattern newpattern
+where oldpattern contains parenthesis surrounding patterns which will
+be replaced in turn by $1, $2, ... in newpattern. For example,
+ %N '(*).lis' '\$1.txt'
+renames 'foo.lis' to 'foo.txt', 'my.old.stuff.lis' to 'my.old.stuff.txt',
+and so on." >&2
+ return 1
+fi
+
+pat=$1
+repl=$2
+
+if [[ -z $action ]]; then
+ # We can't necessarily get the name of the function directly, because
+ # of no_function_argzero stupidity.
+ tmpf=${TMPPREFIX}zmv$$
+ print -P %N >$tmpf
+ myname=$(<$tmpf)
+ rm -f $tmpf
+
+ action=$myname[-2,-1]
+
+ if [[ $action != (cp|mv|ln) ]]; then
+ print "Action $action not recognised: must be cp, mv or ln." >&2
+ return 1
+ fi
+fi
+
+
+if [[ -n $opt_s && $action != ln ]]; then
+ print -P "%N: invalid option: -s" >&2
+ return 1
+fi
+
+if [[ -n $opt_w ]]; then
+ # Parenthesise all wildcards.
+ local newpat
+ # Well, this seems to work.
+ # The tricky bit is getting all forms of [...] correct, but as long
+ # as we require inactive bits to be backslashed its not so bad.
+ newpat="${pat//\
+(#m)(\*\*#\/|[*?]|\<[0-9]#-[0-9]#\>|\[(\[:[a-z]##:\]|\\\[|\\\]|[^\[\]]##)##\])\##\
+/($MATCH)}"
+ if [[ $newpat = $pat ]]; then
+ print -P "%N: warning: no wildcards were found" >&2
+ else
+ pat=$newpat
+ fi
+fi
+
+if [[ -n $opt_Q && $pat = (#b)(*)\([^\)\|\~]##\) ]]; then
+ hasglobqual=q
+ # strip off qualifiers for use as ordinary pattern
+ opat=$match[1]
+fi
+
+if [[ $pat = (#b)(*)\((\*\*##/)\)(*) ]]; then
+ fpat="$match[1]$match[2]$match[3]"
+ # Now make sure we do depth-first searching.
+ # This is so that the names of any files are altered before the
+ # names of the directories they are in.
+ if [[ -n $opt_Q && -n $hasglobqual ]]; then
+ fpat[-1]="odon)"
+ else
+ setopt bareglobqual
+ fpat="${fpat}(odon)"
+ fi
+else
+ fpat=$pat
+fi
+files=(${~fpat})
+
+[[ -n $hasglobqual ]] && pat=$opat
+
+errs=()
+
+for f in $files; do
+ if [[ $pat = (#b)(*)\(\*\*##/\)(*) ]]; then
+ # This looks like a recursive glob. This isn't good enough,
+ # because we should really enforce that $match[1] and $match[2]
+ # don't match slashes unless they were explicitly given. But
+ # it's a start. It's fine for the classic case where (**/) is
+ # at the start of the pattern.
+ pat="$match[1](*/|)$match[2]"
+ fi
+ [[ -e $f && $f = (#b)${~pat} ]] || continue
+ set -- "$match[@]"
+ eval g=\"$repl\"
+ if [[ -z $g ]]; then
+ errs=($errs "$f expanded to empty string")
+ elif [[ $f = $g ]]; then
+ # don't cause error: more useful just to skip
+ # errs=($errs "$f not altered by substitution")
+ [[ -n $opt_v ]] && print "$f not altered, ignored"
+ continue
+ elif [[ -n $from[$g] && ! -d $g ]]; then
+ errs=($errs "$f and $from[$g] both map to $g")
+ elif [[ -f $g && -z $opt_f ]]; then
+ errs=($errs "file exists: $g")
+ fi
+ from[$g]=$f
+ to[$f]=$g
+done
+
+if (( $#errs )); then
+ print -P "%N: error(s) in substitution:" >&2
+ print -l $errs >&2
+ return 1
+fi
+
+for f in $files; do
+ [[ -z $to[$f] ]] && continue
+ exec=($action ${=opt_o} $opt_s -- $f $to[$f])
+ [[ -n $opt_i$opt_n$opt_v ]] && print -- $exec
+ if [[ -n $opt_i ]]; then
+ read -q 'opt?Execute? ' || continue
+ fi
+ if [[ -z $opt_n ]]; then
+ $exec || stat=1
+ fi
+done
+
+return $stat
+# }
diff --git a/Functions/Misc/zrecompile b/Functions/Misc/zrecompile
new file mode 100644
index 000000000..abebbbd9e
--- /dev/null
+++ b/Functions/Misc/zrecompile
@@ -0,0 +1,244 @@
+# This tries to find wordcode files and automatically re-compile them if
+# at least one of the original files is newer than the wordcode file.
+# This will only work if the original files were added with their full
+# paths or if the names stored in the wordcode files are relative to the
+# directory where the wordcode file is.
+#
+# Arguments are the names of wordcode files and directories containing
+# wordcode files that should be checked. If no arguments are given, the
+# directories and wordcode files in $fpath are used.
+#
+# And then there are two options:
+# -t: Only check if there are wordcode files that have to be
+# re-compiled. The return status is zero if there are files
+# that need to be re-compiled and non-zero otherwise.
+# -q: Be quiet, i.e.: only set the return status.
+# -p: If this is given, the arguments are interpreted differently:
+# they should form one or more sets of arguments for zcompile,
+# seperated by `--'. For example:
+#
+# zrecompile -p \
+# -R ~/.zshrc -- \
+# -M ~/.zcompdump -- \
+# ~/zsh/comp.zwc ~/zsh/Completion/*/_* \
+#
+# This makes ~/.zshrc be compiled into ~/.zshrc.zwc if that doesn't
+# exist or if it is older than ~/.zshrc. The wordcode file will be
+# marked for reading instead of mapping. The same is done for
+# ~/.zcompdump and ~/.zcompdump.zwc, but the wordcode file is marked
+# for mapping. The last line re-creates the file ~/zsh/comp.zwc if
+# any of the files matching the given pattern is newer than it.
+#
+# Without the -t option, the return status is zero if all wordcode files
+# that needed re-compilation could be compiled and non-zero if compilation
+# for at least one of the files failed.
+
+setopt localoptions extendedglob noshwordsplit noksharrays
+
+local opt check quiet zwc files re file pre ret map tmp mesg pats
+
+tmp=()
+while getopts ":tqp" opt; do
+ case $opt in
+ t) check=yes ;;
+ q) quiet=yes ;;
+ p) pats=yes ;;
+ *)
+ if [[ -n $pats ]]; then
+ tmp=( $tmp $OPTARG )
+ else
+ print -u2 zrecompile: bad option: -$OPTARG
+ return 1
+ fi
+ esac
+done
+shift OPTIND-${#tmp:-1}
+
+if [[ -n $check ]]; then
+ ret=1
+else
+ ret=0
+fi
+
+if [[ -n $pats ]]; then
+ local end num
+
+ while (( $# )); do
+ end=$argv[(i)--]
+
+ if [[ end -le $# ]]; then
+ files=( $argv[1,end-1] )
+ shift end
+ else
+ files=( $argv )
+ argv=()
+ fi
+
+ tmp=()
+ map=()
+ OPTIND=1
+ while getopts :MR opt $files; do
+ case $opt in
+ [MR]) map=( -$opt ) ;;
+ *) tmp=( $tmp $files[OPTIND] );;
+ esac
+ done
+ shift OPTIND-1 files
+ (( $#files )) || continue
+
+ files=( $files[1] ${files[2,-1]:#*(.zwc|~)} )
+
+ (( $#files )) || continue
+
+ zwc=${files[1]%.zwc}.zwc
+ shift 1 files
+
+ (( $#files )) || files=( ${zwc%.zwc} )
+
+ if [[ -f $zwc ]]; then
+ num=$(zcompile -t $zwc | wc -l)
+ if [[ num-1 -ne $#files ]]; then
+ re=yes
+ else
+ re=
+ for file in $files; do
+ if [[ $file -nt $zwc ]]; then
+ re=yes
+ break
+ fi
+ done
+ fi
+ else
+ re=yes
+ fi
+
+ if [[ -n $re ]]; then
+ if [[ -n $check ]]; then
+
+ # ... say so.
+
+ [[ -z $quiet ]] && print $zwc needs re-compilation
+ ret=0
+ else
+
+ # ... or do it.
+
+ [[ -z $quiet ]] && print -n "re-compiling ${zwc}: "
+
+ # If the file is mapped, it might be mapped right now, so keep the
+ # old file by renaming it.
+
+ if { [[ ! -f $zwc ]] || mv $zwc ${zwc}.old } &&
+ zcompile $map $tmp $zwc $files 2> /dev/null; then
+ [[ -z $quiet ]] && print succeeded
+ else
+ [[ -z $quiet ]] && print failed
+ ret=1
+ fi
+ fi
+ fi
+ done
+
+ return ret
+fi
+
+# Get the names of wordcode files.
+
+if (( $# )); then
+ argv=( ${^argv}/*.zwc(ND) ${^argv}.zwc(ND) ${(M)argv:#*.zwc} )
+else
+ argv=( ${^fpath}/*.zwc(ND) ${^fpath}.zwc(ND) ${(M)fpath:#*.zwc} )
+fi
+
+# We only handle *.zwc files. zcompile only handles *.zwc files. Everybody
+# seems to handle only *.zwc files.
+
+argv=( ${^argv%.zwc}.zwc )
+
+for zwc; do
+
+ # Get the files in the wordcode file.
+
+ files=( ${(f)"$(zcompile -t $zwc)"} )
+
+ # See if the wordcode file will be mapped.
+
+ if [[ $files[1] = *\(mapped\)* ]]; then
+ map=-M
+ mesg='succeeded (old saved)'
+ else
+ map=-R
+ mesg=succeeded
+ fi
+
+ # Get the path prefix of the wordcode file to prepend it to names of
+ # original files that are relative pathnames.
+
+ if [[ $zwc = */* ]]; then
+ pre=${zwc%/*}/
+ else
+ pre=
+ fi
+
+ # Maybe this is even for an older version of the shell?
+
+ if [[ $files[1] != *$ZSH_VERSION ]]; then
+ re=yes
+ else
+ re=
+ fi
+
+ files=( ${pre}${^files[2,-1]:#/*} ${(M)files[2,-1]:#/*} )
+
+ # If the version is correct, compare the age of every original file
+ # to the age of the wordcode file.
+
+ [[ -z $re ]] &&
+ for file in $files; do
+ if [[ $file -nt $zwc ]]; then
+ re=yes
+ break
+ fi
+ done
+
+ if [[ -n $re ]]; then
+
+ # The wordcode files needs re-compilation...
+
+ if [[ -n $check ]]; then
+
+ # ... say so.
+
+ [[ -z $quiet ]] && print $zwc needs re-compilation
+ ret=0
+ else
+
+ # ... or do it.
+
+ [[ -z $quiet ]] && print -n "re-compiling ${zwc}: "
+
+ tmp=( ${^files}(N) )
+
+ # Here is the call to zcompile, but if we can't find all the original
+ # files, we don't try compilation.
+
+ if [[ $#tmp -ne $#files ]]; then
+ [[ -z $quiet ]] && print 'failed (missing files)'
+ ret=1
+ else
+
+ # If the file is mapped, it might be mapped right now, so keep the
+ # old file by renaming it.
+
+ if mv $zwc ${zwc}.old && zcompile $map $zwc $files 2> /dev/null; then
+ [[ -z $quiet ]] && print $mesg
+ else
+ [[ -z $quiet ]] && print failed
+ ret=1
+ fi
+ fi
+ fi
+ fi
+done
+
+return ret
diff --git a/Functions/Misc/zstyle+ b/Functions/Misc/zstyle+
new file mode 100644
index 000000000..eb3c14df5
--- /dev/null
+++ b/Functions/Misc/zstyle+
@@ -0,0 +1,35 @@
+# This makes defining styles a bit simpler by using a single `+' as a
+# special token that allows to append a context name to the previously
+# used context name. Like this:
+#
+# zstyle+ ':foo:bar' style1 value1 \
+# + ':baz' style2 value2 \
+# + ':frob' style3 value3
+#
+# This defines style1 with value1 for the context :foo:bar as usual.
+# But it also defines styles2 with value2 for the context :foo:bar:baz
+# and style3 with value3 for :foo:bar:frob.
+# Of course, any of the sub-contexts after the plus signs may be
+# empty strings to re-use the previous context unchanged.
+#
+# If you don't want to change all your calls to `zstyle' to use
+# `zstyle+' you can use an alias `alias zstyle=zstyle+' and make sure
+# the completion functions are autoloaded without alias expansion (the
+# -U option to the autoload builtin). The completion system normally
+# loads its functions with without alias expansion.
+
+case "$1" in
+-*) zstyle "$@";;
+
+*) setopt localoptions noksharrays
+ integer i
+ local context="$1"
+ 1=''
+ for ((i=2; $#; ++i)); do
+ if [[ $i -gt $# || "$argv[i]" == '+' ]]; then
+ zstyle "$context${(@)argv[1,i-1]}"
+ shift "i > $# ? $# : i" # Stupid shift error on i > $#
+ i=1
+ fi
+ done;;
+esac