From 3d7263ff67534b5d533c1d78eca8d648b72bca93 Mon Sep 17 00:00:00 2001 From: Sven Wischnowsky Date: Mon, 2 Apr 2001 13:04:04 +0000 Subject: after-move cleanup --- Completion/Core/compaudit | 130 ------------------ Completion/Unix/Command/_dict | 21 +-- Completion/Unix/Type/.distfiles | 2 +- Completion/Zsh/Command/.distfiles | 12 +- Completion/compaudit | 10 +- Completion/compinit | 4 +- Completion/compinstall | 4 +- Config/installfns.sh | 12 +- Doc/Zsh/compsys.yo | 89 ++++++------- Doc/Zsh/zftpsys.yo | 2 +- Etc/completion-style-guide | 10 +- Functions/Misc/.distfiles | 3 + Functions/Misc/allopt | 28 ++++ Functions/Misc/checkmail | 26 ++++ Functions/Misc/colors | 79 +++++++++++ Functions/Misc/harden | 6 + Functions/Misc/is-at-least | 38 ++++++ Functions/Misc/mere | 83 ++++++++++++ Functions/Misc/nslookup | 48 +++++++ Functions/Misc/run-help | 88 +++++++++++++ Functions/Misc/zed | 70 ++++++++++ Functions/Misc/zkbd | 248 +++++++++++++++++++++++++++++++++++ Functions/Misc/zmv | 268 ++++++++++++++++++++++++++++++++++++++ Functions/Misc/zrecompile | 244 ++++++++++++++++++++++++++++++++++ Functions/Misc/zstyle+ | 35 +++++ INSTALL | 4 +- Src/Zle/complete.mdd | 2 +- Test/README | 13 ++ Test/ztst.zsh | 3 +- 29 files changed, 1357 insertions(+), 225 deletions(-) delete mode 100644 Completion/Core/compaudit create mode 100644 Functions/Misc/allopt create mode 100644 Functions/Misc/checkmail create mode 100644 Functions/Misc/colors create mode 100644 Functions/Misc/harden create mode 100644 Functions/Misc/is-at-least create mode 100644 Functions/Misc/mere create mode 100644 Functions/Misc/nslookup create mode 100644 Functions/Misc/run-help create mode 100644 Functions/Misc/zed create mode 100644 Functions/Misc/zkbd create mode 100644 Functions/Misc/zmv create mode 100644 Functions/Misc/zrecompile create mode 100644 Functions/Misc/zstyle+ create mode 100644 Test/README diff --git a/Completion/Core/compaudit b/Completion/Core/compaudit deleted file mode 100644 index 4ea31af58..000000000 --- a/Completion/Core/compaudit +++ /dev/null @@ -1,130 +0,0 @@ -# So that this file can also be read with `.' or `source' ... -compaudit() { # Define and then call - -# Audit the fpath to assure that it contains all the directories needed by -# the completion system, and that those directories are at least unlikely -# to contain dangerous files. This is far from perfect, as the modes or -# ownership of files or directories might change between the time of the -# audit and the time the function is executed. - -# This function is designed to be called from compinit, which assumes that -# it is in the same directory, i.e., it can be autoloaded from the initial -# fpath as compinit was. Most local parameter names in this function must -# therefore be the same as those used in compinit. - -emulate -L zsh -setopt extendedglob - -# The positional parameters are the directories to check, else fpath. -if (( $# )); then - local _compdir='' -elif (( $#fpath == 0 )); then - print 'compaudit: No directories in $fpath, cannot continue' 1>&2 - return 1 -else - set -- $fpath -fi - -# _i_check is defined by compinit; used here as a test for whether this -# function is running standalone or was called by compinit. If called -# by compinit, we use parameters that are defined in compinit's scope, -# otherwise we make them local here. -(( $+_i_check )) || { - local _i_q _i_line _i_file _i_fail=verbose - local -a _i_files _i_addfiles _i_wdirs _i_wfiles - local -a -U +h fpath -} - -fpath=( $* ) - -# _compdir may be defined by the user; see the compinit documentation. -# If it isn't defined, we want it to point somewhere sensible, but the -# user is allowed to set it to empty to bypass the check below. -(( $+_compdir )) || { - local _compdir=${fpath[(r)*/$ZSH_VERSION/*]} - [[ -z $_compdir ]] && _compdir=$fpath[1] - [[ -d $_compdir/../Core ]] && _compdir=${_compdir:h} -} - -_i_wdirs=() -_i_wfiles=() - -_i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N) ) -if [[ -n $_compdir ]]; then - if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then - # Too few files: we need some more directories, or we need to check - # that all directories (not just Core) are present. - _i_addfiles=() - if [[ $_compdir = */Core ]]; then - # Add all the Completion subdirectories - _i_addfiles=(${_compdir:h}/*(/)) - elif [[ -d $_compdir/Core ]]; then - # Likewise - _i_addfiles=(${_compdir}/*(/)) - fi - for _i_line in {1..$#i_addfiles}; do - _i_file=${_i_addfiles[$_i_line]} - [[ -d $_i_file && -z ${fpath[(r)$_i_file]} ]] || - _i_addfiles[$_i_line]= - done - fpath=($fpath $_i_addfiles) - _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N) ) - fi -fi - -[[ $_i_fail == use ]] && return 0 - -# RedHat Linux "per-user groups" check. This is tricky, because it's very -# difficult to tell whether the sysadmin has put someone else into your -# "private" group (e.g., via the default group field in /etc/passwd, or -# by NFS group sharing with an untrustworthy machine). So we must assume -# that this has not happened, and pick the best group. - -local GROUP GROUPMEM _i_pw _i_gid -while IFS=: read GROUP _i_pw _i_gid GROUPMEM; do - if (( UID == EUID )); then - [[ $GROUP == $LOGNAME ]] && break - else - (( _i_gid == EGID )) && break # Somewhat arbitrary - fi -done < /etc/group - -# We search for: -# - world/group-writable directories in fpath not owned by root and the user -# - parent-directories of directories in fpath that are world/group-writable -# and not owned by root and the user (that would allow someone to put a -# digest file for one of the directories into the parent directory) -# - digest files for one of the directories in fpath not owned by root and -# the user -# - and for files in directories from fpath not owned by root and the user -# (including zwc files) - -if [[ $GROUP == $LOGNAME && ( -z $GROUPMEM || $GROUPMEM == $LOGNAME ) ]]; then - _i_wdirs=( ${^fpath}(Nf:g+w:^g:${GROUP}:,f:o+w:,^u0u${EUID}) - ${^fpath}/..(Nf:g+w:^g:${GROUP}:,f:o+w:,^u0u${EUID}) ) -else - _i_wdirs=( ${^fpath}(Nf:g+w:,f:o+w:,^u0u${EUID}) - ${^fpath}/..(Nf:g+w:,f:o+w:,^u0u${EUID}) ) -fi -_i_wdirs=( $_i_wdirs ${^fpath}.zwc^([^_]*|*~)(N^u0u${EUID}) ) -_i_wfiles=( ${^fpath}/^([^_]*|*~)(N^u0u${EUID}) ) - -case "${#_i_wdirs}:${#_i_wfiles}" in -(0:0) _i_q= ;; -(0:*) _i_q=files ;; -(*:0) _i_q=directories ;; -(*:*) _i_q='directories and files' ;; -esac - -if [[ -n "$_i_q" ]]; then - [[ $_i_fail == verbose ]] && { - print There are insecure ${_i_q}: 1>&2 - print -l - $_i_wdirs $_i_wfiles - } - return 1 -fi -return 0 - -} # Define and then call - -compaudit "$@" diff --git a/Completion/Unix/Command/_dict b/Completion/Unix/Command/_dict index 228603dbe..31b89ee1c 100644 --- a/Completion/Unix/Command/_dict +++ b/Completion/Unix/Command/_dict @@ -1,24 +1,5 @@ #compdef dict -local expl dictresults dictwords j dict - -_dictwords() { - -[[ -z $words[CURRENT] ]] && return 1 - -dictresults=(${${(f)${"$(dict -m $words[CURRENT])":gs/ - / /}}:#[0-9]*matches found}) - -for j in ${dictresults} -do -dict=${j%%:*} -dictwords=(${(z)j#*:}) - -_wanted $dict expl "words from $dict" \ - compadd -M 'm:{a-zA-Z}={A-Za-z} r:|=*' -a "$@" - dictwords -done -} - _arguments \ '(--host)-h[host]:dict server:_hosts' \ '(-h)--host:dict server:_hosts' \ @@ -63,4 +44,4 @@ _arguments \ '--pipesize:buffer size:' \ '--client:client text:' \ '--debug:debug flag:(verbose raw scan parse pipe serial time)' \ - ':word:_dictwords' + ':word:_dict_words' diff --git a/Completion/Unix/Type/.distfiles b/Completion/Unix/Type/.distfiles index 1ae174230..2fa150d06 100644 --- a/Completion/Unix/Type/.distfiles +++ b/Completion/Unix/Type/.distfiles @@ -1,5 +1,6 @@ DISTFILES_SRC=' .distfiles +_dict_words _mailboxes _perl_modules _tex _diff_options _my_accounts _pids _texi _dir_list _newsgroups _ports _tilde_files _directories _other_accounts _printers _urls @@ -7,5 +8,4 @@ _domains _path_files _ps _user_at_host _files _pdf _pspdf _users _groups _perl_basepods _signals _users_on _hosts _perl_builtin_funcs _tar_archive -_mailboxes _perl_modules _tex ' diff --git a/Completion/Zsh/Command/.distfiles b/Completion/Zsh/Command/.distfiles index e77927278..66e1babd6 100644 --- a/Completion/Zsh/Command/.distfiles +++ b/Completion/Zsh/Command/.distfiles @@ -1,9 +1,9 @@ DISTFILES_SRC=' .distfiles -_autoload _disable _kill _sched _typeset _zftp -_bindkey _echotc _mere _set _unhash _zle -_builtin _emulate _precommand _setopt _unsetopt _zmodload -_cd _enable _print _source _wait _zpty -_command _fc _prompt _stat _which _zstyle -_compdef _hash _read _trap _zcompile _zed +_autoload _disable _kill _sched _typeset _zed +_bindkey _echotc _mere _set _unhash _zftp +_builtin _emulate _precommand _setopt _unsetopt _zle +_cd _enable _print _source _wait _zmodload +_command _fc _prompt _stat _which _zpty +_compdef _hash _read _trap _zcompile _zstyle ' diff --git a/Completion/compaudit b/Completion/compaudit index 4ea31af58..9cab88bbf 100644 --- a/Completion/compaudit +++ b/Completion/compaudit @@ -43,7 +43,7 @@ fpath=( $* ) (( $+_compdir )) || { local _compdir=${fpath[(r)*/$ZSH_VERSION/*]} [[ -z $_compdir ]] && _compdir=$fpath[1] - [[ -d $_compdir/../Core ]] && _compdir=${_compdir:h} + ### [[ -d $_compdir/../Base ]] && _compdir=${_compdir:h} } _i_wdirs=() @@ -51,14 +51,14 @@ _i_wfiles=() _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N) ) if [[ -n $_compdir ]]; then - if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then + if [[ $#_i_files -lt 20 || $_compdir = */Base || -d $_compdir/Base ]]; then # Too few files: we need some more directories, or we need to check - # that all directories (not just Core) are present. + # that all directories (not just Base) are present. _i_addfiles=() - if [[ $_compdir = */Core ]]; then + if [[ $_compdir = */Base ]]; then # Add all the Completion subdirectories _i_addfiles=(${_compdir:h}/*(/)) - elif [[ -d $_compdir/Core ]]; then + elif [[ -d $_compdir/Base ]]; then # Likewise _i_addfiles=(${_compdir}/*(/)) fi diff --git a/Completion/compinit b/Completion/compinit index 172fafc03..f846be42e 100644 --- a/Completion/compinit +++ b/Completion/compinit @@ -1,8 +1,8 @@ # Initialisation for new style completion. This mainly contains some helper -# functions and aliases. Everything else is split into different files that +# functions and setup. Everything else is split into different files that # will automatically be made autoloaded (see the end of this file). The # names of the files that will be considered for autoloading are those that -# begin with an underscores (like `_setopt'). +# begin with an underscores (like `_condition). # # The first line of each of these files is read and must indicate what # should be done with its contents: diff --git a/Completion/compinstall b/Completion/compinstall index ebae5bc43..971816ea8 100644 --- a/Completion/compinstall +++ b/Completion/compinstall @@ -190,9 +190,9 @@ __ci_set_compdir() { __ci_set_compdir $fpath -if [[ $compdir = */Core && -d $compdir/../Base ]]; then +if [[ -d $compdir/Base ]]; then subdirs=1 - compdir=${compdir:h} + ### compdir=${compdir:h} fi if [[ -z $compdir ]]; then diff --git a/Config/installfns.sh b/Config/installfns.sh index a0ef6a25b..90258c7dd 100755 --- a/Config/installfns.sh +++ b/Config/installfns.sh @@ -14,8 +14,16 @@ allfuncs="`cd $sdir_top; echo ${allfuncs}`" for file in $allfuncs; do if test -f $sdir_top/$file; then if test x$FUNCTIONS_SUBDIRS != x -a x$FUNCTIONS_SUBDIRS != xno; then - subdir="`echo $file | sed -e 's%/[^/]*$%%' -e 's%^Functions/%%'`" - instdir="$fndir/$subdir" + case "$file" in + Completion/*) + subdir="`echo $file | sed -e 's%/[^/]*/[^/]*$%%'`" + instdir="$fndir/$subdir" + ;; + *) + subdir="`echo $file | sed -e 's%/[^/]*$%%' -e 's%^Functions/%%'`" + instdir="$fndir/$subdir" + ;; + esac else instdir="$fndir" fi diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 85e1118f0..988b6be63 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -143,8 +143,8 @@ For incomplete installations, if tt(compinit) does not find enough files beginning with an underscore (fewer than twenty) in the search path, it will try to find more by adding the directory tt(_compdir) to the search path. Furthermore, if the directory in question ends in the path segment -tt(Core), or has a subdirectory named tt(Core), tt(compinit) will add all -subdirectories of the directory where tt(Core) is to the path: this allows +tt(Base), or has a subdirectory named tt(Base), tt(compinit) will add all +subdirectories of the directory where tt(Base) is to the path: this allows the functions to be in the same format as in the tt(zsh) source distribution. @@ -317,7 +317,7 @@ do: example(compdef _pids foo) using the tt(_pids) function from the distribution to generate the -process identifiers. Not also the tt(_use_lo) function described +process identifiers. Not also the tt(_gnu_generic) function described below, which can be used to complete options for commands that understand the `tt(-)tt(-help)' option. @@ -823,7 +823,7 @@ values) ) kindex(version, completion tag) item(tt(version))( -used by tt(_call) to look up the command to run to determine the installed +used by tt(_call_program) to look up the command to run to determine the installed version of various other commands (such as tt(diff) and tt(make)). ) kindex(warnings, completion tag) @@ -2800,7 +2800,7 @@ cindex(completion system, utility functions) Descriptions follow for utility functions that may be useful when writing completion functions. Most of these reside in the -tt(Core) subdirectory. Like the example +tt(Base) subdirectory. Like the example functions for commands in the distribution, the utility functions generating matches all follow the convention of returning zero if they generated completions and non-zero if no matching completions could be @@ -3344,14 +3344,14 @@ example(_example_caching_policy () { (( $#oldp )) }) ) -findex(_call) -item(tt(_call) var(tag) var(string) ...)( +findex(_call_program) +item(tt(_call-program) var(tag) var(string) ...)( This function is used in places where a command is called, making it possible for the user to override the default command call. It looks up the tt(command) style with the supplied var(tag). If the style is set, its value is used as the command to execute. -In any case, the var(string)s from the call to tt(_call) or from the +In any case, the var(string)s from the call to tt(_call_program) or from the style are concatenated with spaces between them and the resulting string is evaluated. The return value is the return value of the command called. @@ -3396,13 +3396,13 @@ All arguments after the requested field name are passed to tt(compadd) when generating matches from the style value, or to the functions for the fields if they are called. ) -findex(_compalso) -item(tt(_compalso) var(names) ...)( +findex(_contexts) +item(tt(_contexts) var(names) ...)( This function looks up the definitions for the context and command names given as arguments and calls the handler functions for them if there is a definition (given with the tt(compdef) function). For example, the function completing inside subscripts might use -`tt(_compalso -math-)' to include the completions generated for +`tt(_contexts -math-)' to include the completions generated for mathematical environments. ) findex(_describe) @@ -3483,13 +3483,13 @@ tt(file-patterns) style. See tt(_path_files) below for a description of the full set of options accepted by tt(_files). ) -findex(_funcall) -item(tt(_funcall) var(return) var(name) [ var(args) ... ])( +findex(_call_function) +item(tt(_call_function) var(return) var(name) [ var(args) ... ])( If a function var(name) exists, it is called with the arguments var(args). Unless it is the empty string or a single hyphen, var(return) is taken as the name of a parameter and the return status from the called function is stored in it. -The return value of tt(_funcall) itself is zero if the function +The return value of tt(_call_function) itself is zero if the function var(name) exists and was called and non-zero otherwise. ) findex(_message) @@ -3601,6 +3601,18 @@ allows the user to type upper-case letters which will match their lower-case counterparts. All arguments passed to this function are propagated unchanged to the tt(compadd) builtin. ) +findex(_options_set) +findex(_options_unset) +item(tt(_options_set) and tt(_options_unset))( +These functions complete only set or unset options, with the same +matching specification used in the tt(_options) function. + +Note that you need to uncomment a few lines in the tt(_main_complete) +function for these functions to work properly. The lines in question +are used to store the option settings in effect before the completion +widget locally sets the options it needs. Hence these options are not +generally used by the completion system. +) findex(_parameters) item(tt(_parameters))( This should be used to complete parameter names. tt(_parameters) can @@ -3781,18 +3793,6 @@ This function passes the `tt(-V)', `tt(-J)', `tt(-1)', `tt(-2)', and `tt(-q)' options and their arguments to the tt(compadd) builtin used to add the matches. ) -findex(_set_options) -findex(_unset_options) -item(tt(_set_options) and tt(_unset_options))( -These functions complete only set or unset options, with the same -matching specification used in the tt(_options) function. - -Note that you need to uncomment a few lines in the tt(_main_complete) -function for these functions to work properly. The lines in question -are used to store the option settings in effect before the completion -widget locally sets the options it needs. Hence these options are not -generally used by the completion system. -) findex(_setup) item(tt(_setup) var(tag) [ var(group) ])( This function expects a tag as its argument and sets up the special @@ -3857,17 +3857,17 @@ tt(curcontext) parameter. This allows tt(_tags) to be made to use a more specific context name without having to change and reset the tt(curcontext) parameter (which would otherwise have the same effect). ) -findex(_use_lo) -item(tt(_use_lo))( +findex(_gnu_generic) +item(tt(_gnu_generic))( This function is a simple wrapper around the tt(_arguments) function described above. It can be used to automatically complete long -options for commands that understand the `tt(-)tt(-help)' option -(`tt(_use_lo)' is for `use long options'). It is not intended to be -used from completion functions but as a top-level completion function -in its own right. For example, to enable option completion for the -commands tt(foo) and tt(bar), one would call: +options for commands that understand the `tt(-)tt(-help)' option. +It is not intended to be used from completion functions but as a +top-level completion function in its own right. For example, to +enable option completion for the commands tt(foo) and tt(bar), one +would call: -example(compdef _use_lo foo bar) +example(compdef _gnu_generic foo bar) in one of the initialization files after the call to tt(compinit). @@ -3989,21 +3989,17 @@ it to some directory which appears earlier in your tt(fpath) than the standard directory where it appears. startitem() -item(tt(Core))( -The core scripts and functions. You will certainly need these, though will -probably not need to alter them. Many of these are documented above. -) item(tt(Base))( -Other functions you will almost certainly want if you are going to use -any of the standard completion functions. You may want to edit some of -these files. +The core functions and special completion widgets automatically bound +to keys. You will certainly need most of these, though will +probably not need to alter them. Many of these are documented above. ) -item(tt(Builtins))( +item(tt(Zsh))( Functions for completing arguments of shell builtin commands and utility functions for this. Some of these are also used by functions from -the tt(User) directory. +the tt(Unix) directory. ) -item(tt(User))( +item(tt(Unix))( Functions for completing arguments of external commands and suites of commands. They may need modifying for your system, although in many cases some attempt is made to decide which version of a command is present. For @@ -4012,8 +4008,7 @@ it is running on, while completion for many other utilities try to decide whether the GNU version of the command is in use, and hence whether the tt(--help) option is supported.. ) -item(tt(Commands))( -Functions which implement special types of completion to be bound to -keystrokes rather than called by context. +item(tt(X), tt(AIX), tt(BSD), ...)( +Completion and utility function for commands available only on some systems. ) enditem() diff --git a/Doc/Zsh/zftpsys.yo b/Doc/Zsh/zftpsys.yo index ae1be1fdc..53c18be46 100644 --- a/Doc/Zsh/zftpsys.yo +++ b/Doc/Zsh/zftpsys.yo @@ -657,6 +657,6 @@ subsect(Completion) Completion of local and remote files, directories, sessions and bookmarks is supported. The older, tt(compctl)-style completion is defined when tt(zfinit) is called; support for the new widget-based completion system is -provided in the function tt(Completion/Builtins/_zftp), which should be +provided in the function tt(Completion/Zsh/Command/_zftp), which should be installed with the other functions of the completion system and hence should automatically be available. diff --git a/Etc/completion-style-guide b/Etc/completion-style-guide index 663899799..61b8b6bb4 100644 --- a/Etc/completion-style-guide +++ b/Etc/completion-style-guide @@ -401,13 +401,13 @@ Misc. remarks completely different modes), it should allow users to define functions that separately override the behavior for these different types. This can easily be achieved by using the - `_funcall' utility function, as in: + `_call_function' utility function, as in: - _funcall ret _command_$subcommand && return ret + _call_function ret _command_$subcommand && return ret This will try to call the function `_command_$subcommand' and if it exists, it will be called and the completion function exits - with its exit status. After this call to `funcall' the completion - function would contain the code for the default way to generate - the matches. + with its exit status. After this call to `call_function' the + completion function would contain the code for the default way to + generate the matches. See the `_rpm' and `_nslookup' files for examples. 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)" = " ') + +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 </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 <' '' +# is a globbing pattern, so it should be quoted to prevent it from +# immediate expansion, while is a string that will be +# re-evaluated and hence may contain parameter substitutions, which should +# also be quoted. Each set of parentheses in (apart from those +# around glob qualifiers, if you use the -Q option, and globbing flags) may +# be referred to by a positional parameter in , 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 `*', `?', `' +# (<->, <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 +# 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 +# Call instead of cp, ln or mv. Whatever it does, it should +# at least understand the form ' -- ', +# where and 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 diff --git a/INSTALL b/INSTALL index f20577f53..bf3319422 100644 --- a/INSTALL +++ b/INSTALL @@ -293,11 +293,11 @@ to install them. For other modules, the functions will be installed if and only if the module itself is installed. This will usually be what you want; in particular, the zsh/complete and zsh/zftp modules are of much less use without the associated functions. The functions listed with zsh/zle -are optional. however. +are optional, however. You can also use the configure option --enable-function-subdirs to allow shell functions to be installed into subdirectories of the function -directory, i.e. `Core/*' files will be installed into `FNDIR/Core', and so +directory, i.e. `Base/*' files will be installed into `FNDIR/Base, and so on. This also initialises $fpath/$FPATH appropriately. The option --enable-site-fndir controls whether to create and initialise diff --git a/Src/Zle/complete.mdd b/Src/Zle/complete.mdd index 95c6e99a0..3de97404e 100644 --- a/Src/Zle/complete.mdd +++ b/Src/Zle/complete.mdd @@ -1,7 +1,7 @@ name=zsh/complete link=either load=yes -functions='Completion/Core/* Completion/Base/* Completion/Builtins/* Completion/User/* Completion/Commands/* Completion/Debian/* Completion/Linux/* Completion/Bsd/* Completion/AIX/* Completion/X/*' +functions='Completion/comp* Completion/*/*/*' moddeps="zsh/zle" diff --git a/Test/README b/Test/README new file mode 100644 index 000000000..c5815dc87 --- /dev/null +++ b/Test/README @@ -0,0 +1,13 @@ +There are now different sections, expressed by the first letter in the +scripts names: + + A: basic command parsing and execution + B: builtins + C: shell commands with special syntax + D: substititution + E: options + V: modules + W: builtin interactive commands and constructs + X: line editing + Y: completion + Z: separate systems and user contributions diff --git a/Test/ztst.zsh b/Test/ztst.zsh index a4166f955..3e8bdef18 100755 --- a/Test/ztst.zsh +++ b/Test/ztst.zsh @@ -63,7 +63,8 @@ fi [[ $ZTST_srcdir = /* ]] || ZTST_srcdir="$ZTST_testdir/$ZTST_srcdir" # Set the function autoload paths to correspond to this build of zsh. -fpath=( $ZTST_srcdir/../(Completion|Functions)/*~*/CVS(/) ) +fpath=( $ZTST_srcdir/../Functions/*~*/CVS(/) + $ZTST_srcdir/../Completion/*/*~*/CVS(/) ) : ${TMPPREFIX:=/tmp/zsh} # Temporary files for redirection inside tests. -- cgit 1.4.1