diff options
Diffstat (limited to 'Misc')
-rw-r--r-- | Misc/.distfiles | 4 | ||||
-rw-r--r-- | Misc/.lastloc | 2 | ||||
-rwxr-xr-x | Misc/c2z | 128 | ||||
-rw-r--r-- | Misc/compctl-examples | 716 | ||||
-rwxr-xr-x | Misc/globtests | 107 | ||||
-rwxr-xr-x | Misc/globtests.ksh | 91 | ||||
-rwxr-xr-x | Misc/lete2ctl | 301 |
7 files changed, 1349 insertions, 0 deletions
diff --git a/Misc/.distfiles b/Misc/.distfiles new file mode 100644 index 000000000..a02614511 --- /dev/null +++ b/Misc/.distfiles @@ -0,0 +1,4 @@ +DISTFILES_SRC=' + .distfiles + c2z compctl-examples globtests globtests.ksh lete2ctl +' diff --git a/Misc/.lastloc b/Misc/.lastloc new file mode 100644 index 000000000..8ba7dd946 --- /dev/null +++ b/Misc/.lastloc @@ -0,0 +1,2 @@ +(("/home/user2/pws/src/zsh-3.1.5/Misc/globtests.ksh" . 2763) + ("/home/user2/pws/src/zsh-3.1.5/Misc/globtests" . 3123)) diff --git a/Misc/c2z b/Misc/c2z new file mode 100755 index 000000000..8a90d5fd8 --- /dev/null +++ b/Misc/c2z @@ -0,0 +1,128 @@ +#! /bin/sh +# +# c2z - environment conversion tool +# Contributed by Bart Schaefer +# (Tweaked a bit by Paul Falstad) +# +# This is a quick script to convert csh aliases to zsh aliases/functions. +# It also converts the csh environment and local variables to zsh. c2z +# uses the csh to parse its own dot-files, then processes csh output to +# convert the csh settings to zsh. +# +# When run as a zsh fuction, c2z runs csh as if it were an interactive +# shell whenever the parent zsh is interactive. When run as a shell +# script, the -i switch can be used to force this behavior. +# +# The -l (login) switch causes csh to run as if it were a login shell. +# This is done "properly" if c2z is used as a zsh function, otherwise +# it's faked by explicitly sourcing .login. Use with caution if your +# .login initializes an X server or does other one-time-only startup +# procedures. +# +# usage: +# c2z [-i | -l | filename] +# +# You can use this script in your .zshrc or .zlogin files to load your +# regular csh environment into zsh; for example, in .zlogin: +# +# . =(c2z -l) +# +# This is not perfect, but it gets most common aliases and variables. +# It's also rather time-consuming to do this every time you log in. +# However, if you're moving from csh to zsh for the first time, this +# can get you started with a familiar environment right away. +# +# In case your mailer eats tabs, $T is set to expand to a tab. +# +T="`echo x | tr x '\011'`" + +# If we're zsh, we can run "- csh" to get the complete environment. +# +MINUS="" +LOADFILE="" +INTERACT="" +CSH=csh +case "$ZSH_NAME$ZSH_VERSION$VERSION" in +zsh*) + case $1 in + -l*) MINUS="-" ;; + -i*) INTERACT="-i" ;; + *) LOADFILE="source $1" CSH="csh -f";; + esac + if [[ -o INTERACTIVE ]]; then INTERACT="-i"; fi + setopt nobanghist + ;; +*) + case $1 in + -l*) LOADFILE="source ~/.login" ;; + -i*) INTERACT="-i" ;; + *) LOADFILE="source $1" CSH="csh -f";; + esac + ;; +esac + +( eval $MINUS $CSH $INTERACT ) <<EOF 2>&1 >/dev/null +$LOADFILE +alias >! /tmp/cz$$.a +setenv >! /tmp/cz$$.e +set >! /tmp/cz$$.v +EOF + +# save stdin +exec 9<&0 + +# First convert aliases +exec < /tmp/cz$$.a + +# Taken straight from ctoz except for $T and "alias --" +sed -e 's/'"$T"'(\(.*\))/'"$T"'\1/' >/tmp/cz$$.1 +grep ! /tmp/cz$$.1 >/tmp/cz$$.2 +grep -v ! /tmp/cz$$.1 >/tmp/cz$$.3 +sed -e "s/'/'"\\\\"''"/g \ + -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \ + /tmp/cz$$.3 +sed -e 's/![:#]*/$/g' \ + -e 's/\$cwd/$PWD/' \ + -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \ + /tmp/cz$$.2 + +# Next, convert environment variables +exec < /tmp/cz$$.e + +# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ... +sed -e '/^SHLVL/d' \ + -e '/^PWD/d' \ + -e "s/'/'"\\\\"''"/g \ + -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \ + -e "s/$/'/" + +# Finally, convert local variables +exec < /tmp/cz$$.v + +sed -e 's/'"$T"'/=/' \ + -e "s/'/'"\\\\"''"/g \ + -e '/^[A-Za-z0-9_]*=[^(]/{ + s/=/='"'/"' + s/$/'"'/"' + }' | +sed -e '/^argv=/d' -e '/^cwd=/d' -e '/^filec=/d' -e '/^status=/d' \ + -e '/^autolist=/s/.*/setopt autolist/' \ + -e '/^correct=all/s//setopt correctall/' \ + -e '/^correct=/s//setopt correct/' \ + -e '/^histchars=/s//HISTCHARS=/' \ + -e '/^history=/s//HISTSIZE=/' \ + -e '/^home=/s//HOME=/' \ + -e '/^ignoreeof=/s/.*/setopt ignoreeof/' \ + -e '/^noclobber=/s/.*/setopt noclobber/' \ + -e '/^notify=/d' \ + -e '/^prompt=/s/!/%h/' \ + -e 's/^prompt/PROMPT/' \ + -e '/^showdots=/s/.*/setopt globdots/' \ + -e '/^savehist=/s//HISTFILE=\~\/.zhistory SAVEHIST=/' \ + -e '/^who=/s//WATCHFMT=/' + + +exec 0<&9 + +rm /tmp/cz$$.? +exit diff --git a/Misc/compctl-examples b/Misc/compctl-examples new file mode 100644 index 000000000..e84a37fbb --- /dev/null +++ b/Misc/compctl-examples @@ -0,0 +1,716 @@ +# +# This file gives examples of possible programmable completions (compctl). +# You can either put the compctl commands in your .zshrc file, or put them +# in a separate file (say .zcompctl) and source it from your .zshrc file. +# +# These are just examples. Use and modify to personal taste. Copying +# this file without thought will needlessly increase zsh's memory usage +# and startup time. +# +# For a detailed description of how these work, check the zshcompctl man +# page. +# +#------------------------------------------------------------------------------ +hosts=("${${(s: :)${(s: :)${${(f)$(</etc/hosts)}%%\#*}#*[ ]*}}:#}") +ports=( "${${${(f)$(</etc/services)}:#\#*}%%[ ]*}" ) + +# groups=( $(cut -d: -f1 /etc/group) ) +# groups=( $(ypcat group.byname | cut -d: -f1) ) # if you use NIS + +# It can be done without forking, but it used too much memory in old zsh's: +groups=( "${${(f)$(</etc/group)}%%:*}" ) +#groups=( "${${(f)$(ypcat groups)}%%:*}" ) # if you use NIS + +# Completion for zsh builtins. +compctl -z -P '%' bg +compctl -j -P '%' fg jobs disown +compctl -j -P '%' + -s '`ps -x | tail +2 | cut -c1-5`' wait +compctl -A shift +compctl -c type whence where which +compctl -m -x 'W[1,-*d*]' -n - 'W[1,-*a*]' -a - 'W[1,-*f*]' -F -- unhash +compctl -m -q -S '=' -x 'W[1,-*d*] n[1,=]' -/ - \ + 'W[1,-*d*]' -n -q -S '=' - 'n[1,=]' -/g '*(*)' -- hash +compctl -F functions unfunction +compctl -k '(al dc dl do le up al bl cd ce cl cr + dc dl do ho is le ma nd nl se so up)' echotc +compctl -a unalias +compctl -v getln getopts read unset vared +compctl -v -S '=' -q declare export integer local readonly typeset +compctl -eB -x 'p[1] s[-]' -k '(a f m r)' - \ + 'C[1,-*a*]' -ea - 'C[1,-*f*]' -eF - 'C[-1,-*r*]' -ew -- disable +compctl -dB -x 'p[1] s[-]' -k '(a f m r)' - \ + 'C[1,-*a*]' -da - 'C[1,-*f*]' -dF - 'C[-1,-*r*]' -dw -- enable +compctl -k "(${(j: :)${(f)$(limit)}%% *})" limit unlimit +compctl -l '' -x 'p[1]' -f -- . source +# Redirection below makes zsh silent when completing unsetopt xtrace +compctl -s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)' + -o + -x 's[no]' -o -- unsetopt +compctl -s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)' + -o + -x 's[no]' -o -- setopt +compctl -s '${^fpath}/*(N:t)' autoload +compctl -b -x 'W[1,-*[DAN]*],C[-1,-*M]' -s '$(bindkey -l)' -- bindkey +compctl -c -x 'C[-1,-*k]' -A - 'C[-1,-*K]' -F -- compctl +compctl -x 'C[-1,-*e]' -c - 'C[-1,-[ARWI]##]' -f -- fc +compctl -x 'p[1]' - 'p[2,-1]' -l '' -- sched +compctl -x 'C[-1,[+-]o]' -o - 'c[-1,-A]' -A -- set +compctl -b -x 'w[1,-N] p[3]' -F -- zle +compctl -s '${^module_path}/*(N:t:r)' -x \ + 'W[1,-*(a*u|u*a)*],W[1,-*a*]p[3,-1]' -B - \ + 'W[1,-*u*]' -s '$(zmodload)' -- zmodload + +# Anything after nohup is a command by itself with its own completion +compctl -l '' nohup noglob exec nice eval - time rusage +compctl -l '' -x 'p[1]' -eB -- builtin +compctl -l '' -x 'p[1]' -em -- command +compctl -x 'p[1]' -c - 'p[2,-1]' -k signals -- trap +#------------------------------------------------------------------------------ +# kill takes signal names as the first argument after -, but job names after % +# or PIDs as a last resort +compctl -j -P '%' + -s '`ps -x | tail +2 | cut -c1-5`' + \ + -x 's[-] p[1]' -k "($signals[1,-3])" -- kill +#------------------------------------------------------------------------------ +compctl -s '$(groups)' + -k groups newgrp +compctl -f -x 'p[1], p[2] C[-1,-*]' -k groups -- chgrp +compctl -f -x 'p[1] n[-1,.], p[2] C[-1,-*] n[-1,.]' -k groups - \ + 'p[1], p[2] C[-1,-*]' -u -S '.' -q -- chown +compctl -/g '*.x' rpcgen +compctl -u -x 's[+] c[-1,-f],s[-f+]' -W ~/Mail -f - \ + 's[-f],c[-1,-f]' -f -- mail elm +compctl -x 'c[-1,-f]' -W ~/Mail -f -- pine +#------------------------------------------------------------------------------ +compctl -s "\$(awk '/^[a-zA-Z0-9][^ ]+:/ {print \$1}' FS=: [mM]akefile)" -x \ + 'c[-1,-f]' -f -- make gmake pmake +#------------------------------------------------------------------------------ +# tar +tarnames () { + # Completion function for use with tar: + # get the names of files in the tar archive to extract. + # + # The main claim to fame of this particular function is that it + # completes directories in the tar-file in a manner very roughly + # consistent with `compctl -f'. There are two bugs: first, the whole + # path prefix up to the present is listed with ^D, not just the new + # part to add; second, after a unique completion a space is always + # inserted, even if the completion ends with a slash. These are + # currently limitations of zsh. + # + # This only works for the (fairly common) tar argument style where + # the arguments are bunched into the first argument, and the second + # argument is the name of the tarfile. For example, + # tar xvzf zsh-3.1.2.tar.gz ... + # You can only use compressed/gzipped files if tar is GNU tar, + # although the correct name for the tar programme will be inferred. + + local line list=tf + read -cA line + # $line[2] is the first argument: check for possible compression args. + # (This is harmless when used with non-GNU tar, but then the file must + # be uncompressed to be able to use it with tar anyway.) + [[ $line[2] = *[Zz]* ]] && list=tfz + # $line[1] is the command name: something like tar or gnutar. + # $line[3] is the name of the tar archive. + + # cache contents for multiple completion: note tar_cache_name + # and tar_cache_list are not local. Assumes all files with the + # same name are the same file, even if in different directories: + # you can trick it with $PWD/file on the command line. + if [[ $line[3] != $tar_cache_name ]]; then + tar_cache_list=($($line[1] $list $line[3])) + tar_cache_name=$line[3] + fi + + # Now prune the list to include only appropriate directories. + local file new + reply=() + if [[ $1 = */* ]]; then + local sofar=${1%/*}/ + for file in $tar_cache_list; do + if [[ $file = $sofar* ]]; then + new=${file#$sofar} + if [[ $new = */* ]]; then + new=$sofar${new%%/*}/ + else + new=$file + fi + if [[ $1 != */ || $new != $1 ]]; then + reply=($reply $new) + fi + fi + done + else + for file in $tar_cache_list; do + if [[ $file = */* ]]; then + new=${file%%/*}/ + else + new=$file + fi + reply=($reply $new) + done + fi +} + +compctl -f \ + -x 'p[2] C[-1,*(z*f|f*z)*]' -/g '*.(taz|tar.(gz|z|Z)|tgz)' \ + - 'p[2] C[-1,*(Z*f|f*Z)*]' -/g '*.(tar.Z|taz)' \ + - 'p[2] C[-1,*f*]' -/g '*.tar' \ + - 'p[1] N[-1,ctxvzZ]' -k "(v z f)" \ + - 'p[1] s[]' -k "(c t x)" -S '' \ + - 'p[3,-1] W[1,*x*]' -K tarnames \ + -- tar gtar gnutar +#------------------------------------------------------------------------------ +# rmdir only real directories +compctl -/g '*(/)' rmdir dircmp +#------------------------------------------------------------------------------ +# cd/pushd only directories or symbolic links to directories +compctl -/ cd chdir dirs pushd + +# Another possibility for cd/pushd is to use it in conjunction with the +# cdmatch function (in the Functions subdirectory of zsh distribution). +compctl -K cdmatch -S '/' -q -x 'p[2]' -Q -K cdmatch2 - \ + 'S[/][~][./][../]' -g '*(-/)' + -g '*(-/D)' - \ + 'n[-1,/]' -K cdmatch -S '/' -q -- cd chdir pushd +#------------------------------------------------------------------------------ +# If the command is rsh, make the first argument complete to hosts and treat the +# rest of the line as a command on its own. +compctl -k hosts -x 'p[2,-1]' -l '' -- rsh + +# rlogin takes hosts and users after `-l' +compctl -k hosts -x 'c[-1,-l]' -u -- rlogin + +# rcp: match users, hosts and files initially. Match files after a :, or hosts +# after an @. If one argument contains a : then the other matches files only. +# Not quite perfect; compctl just isn't up to it yet. +compctl -u -k hosts -f -x 'n[1,:]' -f - 'n[1,@]' -k hosts -S ':' - \ + 'p[1] W[2,*:*]' -f - 'p[1] W[2,*?*]' -u -k hosts -S ':' - \ + 'p[2] W[1,*:*]' -f - 'p[2] W[1,*?*]' -u -k hosts -S ':' -- rcp + +compctl -k hosts host rup rusers ping +#------------------------------------------------------------------------------ +# strip, profile, and debug only executables. The compctls for the +# debuggers could be better, of course. +compctl -/g '*(*)' strip gprof adb dbx xdbx ups +compctl -/g '*.[ao]' -/g '*(*)' nm +#------------------------------------------------------------------------------ +# shells: compctl needs some more enhancement to do -c properly. +compctl -f -x 'C[-1,-*c]' -c - 'C[-1,[-+]*o]' -o -- bash ksh sh zsh +#------------------------------------------------------------------------------ +# su takes a username and args for the shell. +compctl -u -x 'w[1,-]p[3,-1]' -l sh - 'w[1,-]' -u - 'p[2,-1]' -l sh -- su +#------------------------------------------------------------------------------ +# Run ghostscript on postscript files, but if no postscript file matches what +# we already typed, complete directories as the postscript file may not be in +# the current directory. +compctl -/g '*.(e|E|)(ps|PS)' \ + gs ghostview nup psps pstops psmulti psnup psselect +#------------------------------------------------------------------------------ +# Similar things for tex, texinfo and dvi files. +compctl -/g '*.tex*' {,la,gla,ams{la,},{g,}sli}tex texi2dvi +compctl -/g '*.dvi' xdvi dvips +#------------------------------------------------------------------------------ +# For rcs users, co and rlog from the RCS directory. We don't want to see +# the RCS and ,v though. +compctl -g 'RCS/*(:s@RCS/@@:s/,v//)' co rlog rcs rcsdiff +#------------------------------------------------------------------------------ +# gzip uncompressed files, but gzip -d only gzipped or compressed files +compctl -x 'R[-*[dt],^*]' -/g '*.(gz|z|Z|t[agp]z|tarZ|tz)' + -f - \ + 's[]' -/g '^*(.(tz|gz|t[agp]z|tarZ|zip|ZIP|jpg|JPG|gif|GIF|[zZ])|[~#])' \ + + -f -- gzip +compctl -/g '*.(gz|z|Z|t[agp]z|tarZ|tz)' gunzip gzcat zcat +compctl -/g '*.Z' uncompress zmore +compctl -/g '*.F' melt fcat +#------------------------------------------------------------------------------ +# ftp takes hostnames +ftphosts=(prep.ai.mit.edu wuarchive.wustl.edu ftp.uu.net ftp.math.gatech.edu) +compctl -k ftphosts ftp + +# Some systems have directories containing indices of ftp servers. +# For example: we have the directory /home/ftp/index/INDEX containing +# files of the form `<name>-INDEX.Z', this leads to: +#compctl -g '/home/ftp/index/INDEX/*-INDEX.Z(:t:r:s/-INDEX//)' ftp tftp +#------------------------------------------------------------------------------ +# Change default completion (see the multicomp function in the Function +# subdirectory of the zsh distribution). +#compctl -D -f + -U -K multicomp +# If completion of usernames is slow for you, you may want to add something +# like +# -x 'C[0,*/*]' -f - 's[~]' -S/ -k users + -u +# where `users' contains the names of the users you want to complete often. +# If you want to use this and to be able to complete named directories after +# the `~' you should add `+ -n' at the end +#------------------------------------------------------------------------------ +# This is to complete all directories under /home, even those that are not +# yet mounted (if you use the automounter). + +# This is for NIS+ (e.g. Solaris 2.x) +#compctl -Tx 's[/home/] C[0,^/home/*/*]' -S '/' -s '$(niscat auto_home.org_dir | \ +# awk '\''/export\/[a-zA-Z]*$/ {print $NF}'\'' FS=/)' + +# And this is for YP (e.g. SunOS4.x) +#compctl -Tx 's[/home/] C[0,^/home/*/*]' -S '/' -s '$(ypcat auto.home | \ +# awk '\''/export\/[a-zA-Z]*$/ {print $NF}'\'' FS=/)' +#------------------------------------------------------------------------------ +# Find is very system dependent, this one is for GNU find. +# Note that 'r[-exec,;]' must come first +if [[ -r /proc/filesystems ]]; then + # Linux + filesystems='"${${(f)$(</proc/filesystems)}#* }"' +else + filesystems='ufs 4.2 4.3 nfs tmp mfs S51K S52K' +fi +compctl -x 'r[-exec,;][-ok,;]' -l '' - \ +'s[-]' -s 'daystart {max,min,}depth follow noleaf version xdev + {a,c,}newer {a,c,m}{min,time} empty false {fs,x,}type gid inum links + {i,}{l,}name {no,}{user,group} path perm regex size true uid used + exec {f,}print{f,0,} ok prune ls' - \ + 'p[1]' -g '. .. *(-/)' - \ + 'C[-1,-((a|c|)newer|fprint(|0|f))]' -f - \ + 'c[-1,-fstype]' -s $filesystems - \ + 'c[-1,-group]' -k groups - \ + 'c[-1,-user]' -u -- find +#------------------------------------------------------------------------------ +# Generic completion for C compiler. +compctl -/g "*.[cCoa]" -x 's[-I]' -/ - \ + 's[-l]' -s '${(s.:.)^LD_LIBRARY_PATH}/lib*.a(:t:r:s/lib//)' -- cc +#------------------------------------------------------------------------------ +# GCC completion, by Andrew Main +# completes to filenames (*.c, *.C, *.o, etc.); to miscellaneous options after +# a -; to various -f options after -f (and similarly -W, -g and -m); and to a +# couple of other things at different points. +# The -l completion is nicked from the cc compctl above. +# The -m completion should be tailored to each system; the one below is i386. +compctl -/g '*.([cCmisSoak]|cc|cxx|ii|k[ih])' -x \ + 's[-l]' -s '${(s.:.)^LD_LIBRARY_PATH}/lib*.a(:t:r:s/lib//)' - \ + 'c[-1,-x]' -k '(none c objective-c c-header c++ cpp-output + assembler assembler-with-cpp)' - \ + 'c[-1,-o]' -f - \ + 'C[-1,-i(nclude|macros)]' -/g '*.h' - \ + 'C[-1,-i(dirafter|prefix)]' -/ - \ + 's[-B][-I][-L]' -/ - \ + 's[-fno-],s[-f]' -k '(all-virtual cond-mismatch dollars-in-identifiers + enum-int-equiv external-templates asm builtin strict-prototype + signed-bitfields signd-char this-is-variable unsigned-bitfields + unsigned-char writable-strings syntax-only pretend-float caller-saves + cse-follow-jumps cse-skip-blocks delayed-branch elide-constructors + expensive-optimizations fast-math float-store force-addr force-mem + inline-functions keep-inline-functions memoize-lookups default-inline + defer-pop function-cse inline peephole omit-frame-pointer + rerun-cse-after-loop schedule-insns schedule-insns2 strength-reduce + thread-jumps unroll-all-loops unroll-loops)' - \ + 's[-g]' -k '(coff xcoff xcoff+ dwarf dwarf+ stabs stabs+ gdb)' - \ + 's[-mno-][-mno][-m]' -k '(486 soft-float fp-ret-in-387)' - \ + 's[-Wno-][-W]' -k '(all aggregate-return cast-align cast-qual + char-subscript comment conversion enum-clash error format id-clash-6 + implicit inline missing-prototypes missing-declarations nested-externs + import parentheses pointer-arith redundant-decls return-type shadow + strict-prototypes switch template-debugging traditional trigraphs + uninitialized unused write-strings)' - \ + 's[-]' -k '(pipe ansi traditional traditional-cpp trigraphs pedantic + pedantic-errors nostartfiles nostdlib static shared symbolic include + imacros idirafter iprefix iwithprefix nostdinc nostdinc++ undef)' \ + -X 'Use "-f", "-g", "-m" or "-W" for more options' -- gcc g++ +#------------------------------------------------------------------------------ +# There are (at least) two ways to complete manual pages. This one is +# extremely memory expensive if you have lots of man pages +man_var() { + man_pages=( ${^manpath}/man*/*(N:t:r) ) + compctl -k man_pages -x 'C[-1,-P]' -m - \ + 'R[-*l*,;]' -/g '*.(man|[0-9](|[a-z]))' -- man + reply=( $man_pages ) +} +compctl -K man_var -x 'C[-1,-P]' -m - \ + 'R[-*l*,;]' -/g '*.(man|[0-9](|[a-z]))' -- man + +# This one isn't that expensive but somewhat slower +man_glob () { + local a + read -cA a + if [[ $a[2] = -s ]] then # Or [[ $a[2] = [0-9]* ]] for BSD + reply=( ${^manpath}/man$a[3]/$1*$2(N:t:r) ) + else + reply=( ${^manpath}/man*/$1*$2(N:t:r) ) + fi +} +#compctl -K man_glob -x 'C[-1,-P]' -m - \ +# 'R[-*l*,;]' -/g '*.(man|[0-9nlpo](|[a-z]))' -- man +#------------------------------------------------------------------------------ +# xsetroot: gets possible colours, cursors and bitmaps from wherever. +# Uses two auxiliary functions. You might need to change the path names. +Xcolours() { + reply=( ${(L)$(awk '{ if (NF = 4) print $4 }' \ + < /usr/openwin/lib/X11/rgb.txt)} ) +} +Xcursor() { + reply=( $(sed -n 's/^#define[ ][ ]*XC_\([^ ]*\)[ ].*$/\1/p' \ + < /usr/include/X11/cursorfont.h) ) +} +compctl -k '(-help -def -display -cursor -cursor_name -bitmap -mod -fg -bg + -grey -rv -solid -name)' -x \ + 'c[-1,-display]' -s '$DISPLAY' -k hosts -S ':0' - \ + 'c[-1,-cursor]' -f - 'c[-2,-cursor]' -f - \ + 'c[-1,-bitmap]' -g '/usr/include/X11/bitmaps/*' - \ + 'c[-1,-cursor_name]' -K Xcursor - \ + 'C[-1,-(solid|fg|bg)]' -K Xcolours -- xsetroot +#------------------------------------------------------------------------------ +# dd +compctl -k '(if of conv ibs obs bs cbs files skip file seek count)' \ + -S '=' -x 's[if=], s[of=]' -f - 'C[0,conv=*,*] n[-1,,], s[conv=]' \ + -k '(ascii ebcdic ibm block unblock lcase ucase swap noerror sync)' \ + -q -S ',' - 'n[-1,=]' -X '<number>' -- dd +#------------------------------------------------------------------------------ +# Various MH completions by Peter Stephenson +# You may need to edit where it says *Edit Me*. + +# The following three functions are best autoloaded. +# mhcomp completes folders (including subfolders), +# mhfseq completes sequence names and message numbers, +# mhfile completes files in standard MH locations. + +function mhcomp { + # Completion function for MH folders. + # Works with both + (rel. to top) and @ (rel. to current). + local nword args pref char mhpath + read -nc nword + read -cA args + + pref=$args[$nword] + char=$pref[1] + pref=$pref[2,-1] + + # The $(...) here accounts for most of the time spent in this function. + if [[ $char = + ]]; then + # mhpath=$(mhpath +) + # *Edit Me*: use a hard wired value here: it's faster. + mhpath=~/Mail + elif [[ $char = @ ]]; then + mhpath=$(mhpath) + fi + + eval "reply=($mhpath/$pref*(N-/))" + + # I'm frankly amazed that this next step works, but it does. + reply=(${reply#$mhpath/}) +} + +mhfseq() { + # Extract MH message names and numbers for completion. Use of the + # correct folder, if it is not the current one, requires that it + # should be the previous command line argument. If the previous + # argument is `-draftmessage', a hard wired draft folder name is used. + + local folder foldpath words pos nums + read -cA words + read -cn pos + + # Look for a folder name. + # First try the previous word. + if [[ $words[$pos-1] = [@+]* ]]; then + folder=$words[$pos-1] + # Next look and see if we're looking for a draftmessage + elif [[ $words[$pos-1] = -draftmessage ]]; then + # *Edit Me*: shortcut -- hard-wire draftfolder here + # Should really look for a +draftfolder argument. + folder=+drafts + fi + # Else use the current folder ($folder empty) + + if [[ $folder = +* ]]; then + # *Edit Me*: use hard-wired path with + for speed. + foldpath=~/Mail/$folder[2,-1] + else + foldpath=$(mhpath $folder) + fi + + # Extract all existing message numbers from the folder. + nums=($foldpath/<->(N:t)) + # If that worked, look for marked sequences. + # *Edit Me*: if you never use non-standard sequences, comment out + # or delete the next three lines. + if (( $#nums )); then + nums=($nums $(mark $folder | awk -F: '{print $1}')) + fi + + # *Edit Me*: `unseen' is the value of Unseen-Sequence, if it exists; + set -A reply next cur prev first last all unseen $nums + +} + +mhfile () { + # Find an MH file; for use with -form arguments and the like. + # Use with compctl -K mhfile. + + local mhfpath file + # *Edit Me*: Array containing all the places MH will look for templates etc. + mhfpath=(~/Mail /usr/local/lib/MH) + + # Emulate completeinword behaviour as appropriate + local wordstr + if [[ -o completeinword ]]; then + wordstr='$1*$2' + else + wordstr='$1$2*' + fi + + if [[ $1$2 = */* ]]; then + # path given: don't search MH locations + eval "reply=($wordstr(.N))" + else + # no path: only search MH locations. + eval "reply=(\$mhfpath/$wordstr(.N:t))" + fi +} + +# Note: you must type the initial + or @ of a folder name to get +# completion, even in places where only folder names are allowed. +# Abbreviations for options are not recognised. Hit tab to complete +# the option name first. +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ + 's[-]' -k "(all fast nofast header noheader help list nolist \ + pack nopack pop push recurse norecurse total nototal)" -- folder +compctl -K mhfseq -x 's[+][@],c[-1,-draftfolder] s[+][@]' \ + -K mhcomp -S / -q - 'c[-1,-draftmessage]' -K mhfseq - \ + 'C[-1,-(editor|whatnowproc)]' -c - \ + 's[-]' -k "(draftfolder draftmessage nodraftfolder editor noedit \ + file form use nouse whatnowproc nowhatnowproc help)" - \ + 'c[-1,-form]' -K mhfile -- comp +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ + 's[-]' -k "(audit noaudit changecur nochangecur form format \ + file silent nosilent truncate notruncate width help)" - \ + 'C[-1,-(audit|form)]' -K mhfile - 'c[-1,-file]' -f + -- inc +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ + 's[-]' -k "(sequence add delete list public nopublic zero nozero help)" -- \ + mark +compctl -K mhfseq -x 's[+][@]' \ + -K mhcomp -S / -q - 'c[-1,-file]' -f - 'c[-1,-rmmprov]' -c - \ + 's[-]' -k "(draft link nolink preserve nopreserve src file \ + rmmproc normmproc help)" -- refile +compctl -K mhfseq -x 's[+][@]' \ + -K mhcomp -S / -q - 'c[-1,-draftmessage]' -K mhfseq -\ + 's[-]' -k "(annotate noannotate cc nocc draftfolder nodraftfolder \ + draftmessage editor noedit fcc filter form inplace noinplace query \ + noquery width whatnowproc nowhatnowproc help)" - 'c[-1,(cc|nocc)]' \ + -k "(all to cc me)" - 'C[-1,-(filter|form)]' -K mhfile - \ + 'C[-1,-(editor|whatnowproc)]' -c -- repl +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ + 's[-]' -k "(clear noclear form format header noheader reverse noreverse \ + file help width)" - 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile -- scan +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ + 's[-]' -k "(draft form moreproc nomoreproc header noheader \ + showproc noshowproc length width help)" - 'C[-1,-(show|more)proc]' -c - \ + 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - \ + 'c[-1,-length]' -s '$LINES' - 'c[-1,-width]' -s '$COLUMNS' -- show next prev +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \ + -k "(help)" -- rmm +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - \ + 's[-]' -k "(after before cc date datefield from help list nolist \ + public nopublic search sequence subject to zero nozero not or and \ + lbrace rbrace)" -- pick +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \ + -k "(alias check draft draftfolder draftmessage help nocheck \ + nodraftfolder)" -- whom +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' \ + -k "(file part type list headers noheaders realsize norealsize nolist \ + show serialonly noserialonly form pause nopause noshow store auto noauto \ + nostore cache nocache rcache wcache check nocheck ebcdicsafe noebcdicsafe \ + rfc934mode norfc934mode verbose noverbose help)" - \ + 'c[-1,-file]' -f - 'c[-1,-form]' -K mhfile - \ + 'C[-1,-[rw]cache]' -k '(public private never ask)' -- mhn +compctl -K mhfseq -x 's[+][@]' -K mhcomp -S / -q - 's[-]' -k '(help)' -- mhpath +#------------------------------------------------------------------------------ +# CVS +# +cvscmds=(add admin rcs checkout commit diff rdiff export history import log rlog + release remove status tag rtag update annotate) +cvsignore="*~ *# .#* *.o *.a CVS . .." + +compctl -k cvscmds \ + -x "c[-1,-D]" -k '(today yesterday 1\ week\ ago)' \ + - "c[-1,-m]" -k '(bugfix cosmetic\ fix ... added\ functionality foo)' \ + - "c[-1,-F]" -f \ + - "c[-1,-r]" -K cvsrevisions \ + - "c[-1,-I]" -f \ + - "R[add,;]" -K cvsaddp \ + - "R[(admin|rcs),;]" -/K cvstargets \ + - "R[(checkout|co),;]" -K cvsrepositories \ + - "R[(commit|ci),;]" -/K cvstargets \ + - "R[(r|)diff,;]" -/K cvstargets \ + - "R[export,;]" -f \ + - "R[history,;]" -/K cvstargets \ + - "R[history,;] c[-1,-u]" -u \ + - "R[import,;]" -K cvsrepositories \ + - "R[(r|)log,;]" -/K cvstargets \ + - 'R[(r|)log,;] s[-w] n[-1,,],s[-w]' -u -S , -q \ + - "R[rel(|ease),;]" -f \ + - "R[(remove|rm),;] R[-f,;]" -/K cvstargets \ + - "R[(remove|rm),;]" -K cvsremovep \ + - "R[status,;]" -/K cvstargets \ + - "R[(r|)tag,;]" -/K cvstargets \ + - "R[up(|date),;]" -/K cvstargets \ + - "R[annotate,;]" -/K cvstargets \ + -- cvs + +compctl -/K cvstargets cvstest + +cvsprefix() { + local nword args f + read -nc nword; read -Ac args + pref=$args[$nword] + if [[ -d $pref:h && ! -d $pref ]]; then + pref=$pref:h + elif [[ $pref != */* ]]; then + pref= + fi + [[ -n "$pref" && "$pref" != */ ]] && pref=$pref/ +} + +cvsentries() { + setopt localoptions nullglob unset + if [[ -f ${pref}CVS/Entries ]]; then + reply=( "${pref}${^${${${(f@)$(<${pref}CVS/Entries)}:#D*}#/}%%/*}" ) + fi +} + +cvstargets() { + local pref + cvsprefix + cvsentries +} + +cvsrevisions() { + reply=( "${${${(M)${(f)$(cvs -q status -vl .)}:# *}##[ ]##}%%[ ]*}" ) +} + +cvsrepositories() { + local root=$CVSROOT + [[ -f CVS/Root ]] && root=$(<CVS/Root) + reply=( + $root/^CVSROOT(:t) + "${${(M)${(f)$(<$root/CVSROOT/modules)}:#[^#]*}%%[ ]*}" + ) +} + +cvsremovep() { + local pref + cvsprefix + cvsentries + setopt localoptions unset + local omit + omit=( ${pref}*(D) ) + eval 'reply=( ${reply:#('${(j:|:)omit}')} )' +} + +cvsaddp() { + local pref + cvsprefix + cvsentries + setopt localoptions unset + local all omit + all=( ${pref}*(D) ) + omit=( $reply ${pref}${^${=cvsignore}} ) + [[ -r ~/.cvsignore ]] && omit=( $omit ${pref}${^$(<~/.cvsignore)} ) + [[ -r ${pref}.cvsignore ]] && omit=( $omit ${pref}${^$(<${pref}.cvsignore)} ) + eval 'reply=( ${all:#('${(j:|:)omit}')} )' +} + +#------------------------------------------------------------------------------ +# RedHat Linux rpm utility +# +compctl -s '$(rpm -qa)' \ + -x 's[--]' -s 'oldpackage percent replacefiles replacepkgs noscripts + root excludedocs includedocs test upgrade test clean + short-circuit sign recompile rebuild resign querytags + queryformat version help quiet rcfile force hash' - \ + 's[ftp:]' -P '//' -s '$(</u/zsh/ftphosts)' -S '/' - \ + 'c[-1,--root]' -/ - \ + 'c[-1,--rcfile]' -f - \ + 'p[1] s[-b]' -k '(p l c i b a)' - \ + 'c[-1,--queryformat] N[-1,{]' \ + -s '"${${(f)$(rpm --querytags)}#RPMTAG_}"' -S '}' - \ + 'W[1,-q*] C[-1,-([^-]*|)f*]' -f - \ + 'W[1,-i*], W[1,-q*] C[-1,-([^-]*|)p*]' \ + -/g '*.rpm' + -f -- rpm +#------------------------------------------------------------------------------ +compctl -u -x 'c[-1,-w]' -f -- ac +compctl -/g '*.m(.)' mira +#------------------------------------------------------------------------------ +# talk completion: complete local users, or users at hosts listed via rwho +compctl -K talkmatch talk ytalk ytalk3 +function talkmatch { + local u + reply=($(users)) + for u in "${${(f)$(rwho 2>/dev/null)}%%:*}"; do + reply=($reply ${u%% *}@${u##* }) + done +} +#------------------------------------------------------------------------------ +# Linux mount +comp_fsmount () { + local tmp; if [[ $UID = 0 ]]; then tmp=""; else tmp="user"; fi + sed -n -e "s|^[^# ][^ ]*[ ][ ]*\(/[^ ]*\)[ ].*$tmp.*|\1|p" /etc/fstab +} +comp_nfsmount () { + local cmd args host + read -Ac cmd; read -cn where + host=${${cmd[$where]}%%:*} + reply=("${(@f)$(showmount -e $host | sed -n -e "s|^/\([^ ]*\) .*|$host:/\1|p")}") +} +compctl -s '$(mount | \ + sed -e "s/^[^ ]* on \\([^ ]*\\) type.*/\\1/"'"$( + if [[ ! $UID = 0 ]]; then + echo ' | egrep "^${(j:|:)$(comp_fsmount)}\$"' + fi)"')' umount +compctl -s '$(comp_fsmount)' + \ + -x 'S[/]' -f -- + \ + -x 'C[0,*:*]' -K comp_nfsmount -- + \ + -s '$(< /etc/hosts)' \ + mount +#------------------------------------------------------------------------------ +# Lynx (web browser) +compctl -k '(http:// file: ftp:// gopher:// news://)' -S '' \ + -x 's[ftp://]' -k ftphosts -S/ \ + - 'n[1,://]' -k hosts -S/ \ + - 's[file:/]' -/g '*.html' -W/ \ + - 's[file:]' -s '~+' -S '/' \ + - 's[-]' -k '(anonymous auth base book buried_news cache case + cfg child cookies crawl display dump editor emacskeys + enable_scrollback error_file fileversions force_html + from ftp get_data head help historical homepage + image_links index link localhost locexec mime_header + minimal newschunksize newsmaxchunk nobrowse noexec + nofilereferer nofilereferer nolist nolog nopause + noprint noredir noreferer nosocks nostatus number_links + popup post_data print pseudo_inlines raw realm reload + restrictions resubmit_posts rlogin selective show_cursor + source startfile_ok telnet term trace traversal underscore + validate version vikeys)' \ + -- lynx +#------------------------------------------------------------------------------ +# ssh (secure shell) +compctl -k hosts \ + -x "c[-1,-l]" -u \ + - "c[-1,-i]" -f \ + - "c[-1,-e]" -k "(~ none)" \ + - "c[-1,-c]" -k "(idea des 3des tss arcfour none)" \ + - "c[-1,-p]" -k ports \ + - "c[-1,-L] c[-1,-R] c[-1,-o]" -k "()" \ + -- ssh +#------------------------------------------------------------------------------ +# network stuff +compctl -k hosts \ + -x "s[-class=]" -k "(any in chaos hesiod)" \ + - "s[-query=]" -k "(a cname hinfo md mx mb mg minfo ns ptr soa txt uinfo wks any)" \ + - "s[-]" -Q -S '' -k "(query= all\ class= d2\ nod2\ debug\ nodebug\ defname\ nodefname\ domain= ignoretc\ noignoretc\ )" \ + -- nslookup + +compctl -k hosts \ + -x "C[-1,[^-]*] p[2,-1]" -k ports \ + -- telnet + +compctl -x 'N[-1,@]' -k hosts - 's[]' -u -qS '@' -- finger +#------------------------------------------------------------------------------ +# gdb +compctl -/g "*(*)" \ + -x "s[-]" -k "(help nx q batch cd f b tty exec se core symbols c x d)" \ + - "C[-1,(-cd|-directory)]" -/ \ + - "C[-1,(-core|-c)]" -/g 'core*' \ + - "C[-1,(-se|-exec)]" -f \ + - "C[-1,(-symbols|-command|-x)]" -f \ + - "p[2,-1] C[-1,[^-]*]" -/g "core*" \ + -- gdb diff --git a/Misc/globtests b/Misc/globtests new file mode 100755 index 000000000..728aee5ae --- /dev/null +++ b/Misc/globtests @@ -0,0 +1,107 @@ +#!/usr/local/bin/zsh -f + +setopt extendedglob badpattern +unsetopt kshglob + +failed=0 +while read res str pat; do + [[ $res = '#' ]] && continue + [[ $str = ${~pat} ]] + ts=$? + [[ $1 = -q ]] || print "$ts: [[ $str = $pat ]]" + if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then + print "Test failed: [[ $str = $pat ]]" + (( failed++ )) + fi +done <<EOT +t fofo (fo#)# +t ffo (fo#)# +t foooofo (fo#)# +t foooofof (fo#)# +t fooofoofofooo (fo#)# +f foooofof (fo##)# +f xfoooofof (fo#)# +f foooofofx (fo#)# +t ofxoofxo ((ofo#x)#o)# +f ofooofoofofooo (fo#)# +t foooxfooxfoxfooox (fo#x)# +f foooxfooxofoxfooox (fo#x)# +t foooxfooxfxfooox (fo#x)# +t ofxoofxo ((ofo#x)#o)# +t ofoooxoofxo ((ofo#x)#o)# +t ofoooxoofxoofoooxoofxo ((ofo#x)#o)# +t ofoooxoofxoofoooxoofxoo ((ofo#x)#o)# +f ofoooxoofxoofoooxoofxofo ((ofo#x)#o)# +t ofoooxoofxoofoooxoofxooofxofxo ((ofo#x)#o)# +t aac ((a))#a(c) +t ac ((a))#a(c) +f c ((a))#a(c) +t aaac ((a))#a(c) +f baaac ((a))#a(c) +t abcd ?(a|b)c#d +t abcd (ab|ab#)c#d +t acd (ab|ab#)c#d +t abbcd (ab|ab#)c#d +t effgz (bc##d|ef#g?|(h|)i(j|k)) +t efgz (bc##d|ef#g?|(h|)i(j|k)) +t egz (bc##d|ef#g?|(h|)i(j|k)) +t egzefffgzbcdij (bc##d|ef#g?|(h|)i(j|k))# +f egz (bc##d|ef##g?|(h|)i(j|k)) +t ofoofo (ofo##)# +t oxfoxoxfox (oxf(ox)##)# +f oxfoxfox (oxf(ox)##)# +t ofoofo (ofo##|f)# +# The following is supposed to match only as fo+ofo+ofo +t foofoofo (foo|f|fo)(f|ofo##)# +t oofooofo (of|oofo##)# +t fffooofoooooffoofffooofff (f#o#)# +# If the following is really slow, that's a bug. +f fffooofoooooffoofffooofffx (f#o#)# +# The following tests backtracking in alternation matches +t fofoofoofofoo (fo|foo)# +# Exclusion: test both types +t foo ((^x)) +t foo ((^x)*) +f foo ((^foo)) +t foo ((^foo)*) +t foobar ((^foo)) +t foobar ((^foo)*) +f foot z*~*x +t zoot z*~*x +f foox z*~*x +f zoox z*~*x +t moo.cow (*~*.*).(*~*.*) +f mad.moo.cow (*~*.*).(*~*.*) +t moo.cow (^*.*).(^*.*) +f sane.moo.cow (^*.*).(^*.*) +f mucca.pazza mu(^c#)?.pa(^z#)? +t fff ((^f)) +t fff ((^f)#) +t fff ((^f)##) +t ooo ((^f)) +t ooo ((^f)#) +t ooo ((^f)##) +t foo ((^f)) +t foo ((^f)#) +t foo ((^f)##) +f f ((^f)) +f f ((^f)#) +f f ((^f)##) +t foot (^z*|*x) +f zoot (^z*|*x) +t foox (^z*|*x) +t zoox (^z*|*x) +t foo (^foo)# +f foob (^foo)b* +t foobb (^foo)b* +f zsh ^z* +t a%1X [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]] +f a%1 [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]] +t [: [[:]# +t :] []:]# +t :] [:]]# +t [ [[] +t ] []] +t [] [^]]] +EOT +print "$failed tests failed." diff --git a/Misc/globtests.ksh b/Misc/globtests.ksh new file mode 100755 index 000000000..b03cc488e --- /dev/null +++ b/Misc/globtests.ksh @@ -0,0 +1,91 @@ +#!/usr/local/bin/zsh -f + +setopt kshglob + +failed=0 +while read res str pat; do + [[ $res = '#' ]] && continue + [[ $str = ${~pat} ]] + ts=$? + [[ $1 = -q ]] || print "$ts: [[ $str = $pat ]]" + if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then + print "Test failed: [[ $str = $pat ]]" + (( failed++ )) + fi +done <<EOT +t fofo *(f*(o)) +t ffo *(f*(o)) +t foooofo *(f*(o)) +t foooofof *(f*(o)) +t fooofoofofooo *(f*(o)) +f foooofof *(f+(o)) +f xfoooofof *(f*(o)) +f foooofofx *(f*(o)) +t ofxoofxo *(*(of*(o)x)o) +f ofooofoofofooo *(f*(o)) +t foooxfooxfoxfooox *(f*(o)x) +f foooxfooxofoxfooox *(f*(o)x) +t foooxfooxfxfooox *(f*(o)x) +t ofxoofxo *(*(of*(o)x)o) +t ofoooxoofxo *(*(of*(o)x)o) +t ofoooxoofxoofoooxoofxo *(*(of*(o)x)o) +t ofoooxoofxoofoooxoofxoo *(*(of*(o)x)o) +f ofoooxoofxoofoooxoofxofo *(*(of*(o)x)o) +t ofoooxoofxoofoooxoofxooofxofxo *(*(of*(o)x)o) +t aac *(@(a))a@(c) +t ac *(@(a))a@(c) +f c *(@(a))a@(c) +t aaac *(@(a))a@(c) +f baaac *(@(a))a@(c) +t abcd ?@(a|b)*@(c)d +t abcd @(ab|a*@(b))*(c)d +t acd @(ab|a*(b))*(c)d +t abbcd @(ab|a*(b))*(c)d +t effgz @(b+(c)d|e*(f)g?|?(h)i@(j|k)) +t efgz @(b+(c)d|e*(f)g?|?(h)i@(j|k)) +t egz @(b+(c)d|e*(f)g?|?(h)i@(j|k)) +t egzefffgzbcdij *(b+(c)d|e*(f)g?|?(h)i@(j|k)) +f egz @(b+(c)d|e+(f)g?|?(h)i@(j|k)) +t ofoofo *(of+(o)) +t oxfoxoxfox *(oxf+(ox)) +f oxfoxfox *(oxf+(ox)) +t ofoofo *(of+(o)|f) +# The following is supposed to match only as fo+ofo+ofo +t foofoofo @(foo|f|fo)*(f|of+(o)) +t oofooofo *(of|oof+(o)) +t fffooofoooooffoofffooofff *(*(f)*(o)) +# If the following is really slow, that's a bug. +f fffooofoooooffoofffooofffx *(*(f)*(o)) +# The following tests backtracking in alternation matches +t fofoofoofofoo *(fo|foo) +# Exclusion +t foo !(x) +t foo !(x)* +f foo !(foo) +t foo !(foo)* +t foobar !(foo) +t foobar !(foo)* +t moo.cow !(*.*).!(*.*) +f mad.moo.cow !(*.*).!(*.*) +f mucca.pazza mu!(*(c))?.pa!(*(z))? +t fff !(f) +t fff *(!(f)) +t fff +(!(f)) +t ooo !(f) +t ooo *(!(f)) +t ooo +(!(f)) +t foo !(f) +t foo *(!(f)) +t foo +(!(f)) +f f !(f) +f f *(!(f)) +f f +(!(f)) +t foot @(!(z*)|*x) +f zoot @(!(z*)|*x) +t foox @(!(z*)|*x) +t zoox @(!(z*)|*x) +t foo *(!(foo)) +f foob !(foo)b* +t foobb !(foo)b* +EOT +print "$failed tests failed." diff --git a/Misc/lete2ctl b/Misc/lete2ctl new file mode 100755 index 000000000..ca00b8aee --- /dev/null +++ b/Misc/lete2ctl @@ -0,0 +1,301 @@ +#!/usr/local/bin/perl -w +# +# ``Wee have also Shelles, thee Lyke of whych you knowe not, wherein +# thee User may with thee merest Presse of thee Tabbe-Keye expande +# or compleat al Maner of Wordes and such-like Diversities.'' +# - Francis Bacon, `New Atlantis' (or not). +# +# Convert tcsh "complete" statements to zsh "compctl" statements. +# Runs as a filter. Should ignore anything which isn't a "complete". +# It expects each "complete" statement to be the first thing on a line. +# All the examples in the tcsh manual give sensible results. +# +# Option: +# -x (exact): only applies in the case of command disambiguation (is +# that really a word?) If you have lines like +# complete '-co*' 'p/0/(compress)' +# (which makes co<TAB> always complete to `compress') then the +# resulting "compctl" statements will produce one of two behaviours: +# (1) By default (like tcsh), com<TAB> etc. will also complete to +# "compress" and nothing else. +# (2) With -x, com<TAB> does ordinary command completion: this is +# more flexible. +# I don't understand what the hyphen in complete does and I've ignored it. +# +# Notes: +# (1) The -s option is the way to do backquote expansion. In zsh, +# "compctl -s '`users`' talk" works (duplicates are removed). +# (2) Complicated backquote completions should definitely be rewritten as +# shell functions (compctl's "-K func" option). Although most of +# these will be translated correctly, differences in shell syntax +# are not handled. +# (3) Replacement of $:n with the n'th word on the current line with +# backquote expansion now works; it is not necessarily the most +# efficient way of doing it in any given case, however. +# (4) I have made use of zsh's more sophisticated globbing to change +# things like ^foo.{a,b,c,d} to ^foo.(a|b|c|d), which works better. +# It's just possible in some cases you may want to change it back. +# (5) Make sure all command names with wildcards are processed together -- +# they need to be lumped into one "compctl -C" or "compctl -D" +# statement for zsh. + +# Handle options +if (@ARGV) { + ($ARGV[0] eq '-x') && shift && ($opt_x = 1); + ($ARGV[0] =~ /^-+$/) && shift; +} + +# Function names used (via magic autoincrement) when cmdline words are needed +$funcnam = 'compfn001'; + +# Read next word on command line +sub getword { + local($word, $word2, $ret); + ($_) = /^\s*(.*)$/; + while ($_ =~ /^\S/) { + if (/^[\']/) { + ($word, $_) = /^\'([^\']*).(.*)$/; + } elsif (/^[\"]/) { + ($word, $_) = /^\"([^\"]*).(.*)$/; + while ($word =~ /\\$/) { + chop($word); + ($word2, $_) = /^([^\"]*).(.*)$/; + $word .= '"' . $word2; + } + } elsif (/\S/) { + ($word, $_) = /^([^\s\\\'\"\#;]*)(.*)$/; + # Backslash: literal next character + /^\\(.)/ && (($word .= substr($_,1,1)), + ($_ = substr($_,2))); + # Rest of line quoted or end of command + /^[\#;]/ && ($_ = ''); + } else { + return undef; + } + length($word) && ($ret = defined($ret) ? $ret . $word : $word); + } + $ret; +} + +# Interpret the x and arg in 'x/arg/type/' +sub getpat { + local($pat,$arg) = @_; + local($ret,$i); + if ($pat eq 'p') { + $ret = "p[$arg]"; + } elsif ($pat eq 'n' || $pat eq 'N') { + $let = ($arg =~ /[*?|]/) ? 'C' : 'c'; + $num = ($pat eq 'N') ? 2 : 1; + $ret = "${let}[-${num},$arg]"; + } elsif ($pat eq 'c' || $pat eq 'C') { + # A few tricks to get zsh to ignore up to the end of + # any matched pattern. + if (($pat eq 'c' && $arg =~ /^\*([^*?]*)$/)) { + $ret = "n[-1,$1]"; + } elsif ($arg =~ /[*?]([^*?]*)$/) { + length($1) && ($ret = " n[-1,$1]"); + $ret = "C[0,$arg] $ret"; + } else { + $let = ($pat eq 'c') ? 's' : 'S'; + $ret = "${let}[$arg]"; + } + } + $ret =~ s/'/'\\''/g; + $ret; +} + +# Interpret the type in 'x/arg/type/' +sub gettype { + local ($_) = @_; + local($qual,$c,$glob,$ret,$b,$m,$e,@m); + $c = substr($_,0,1); + ($c =~ /\w/) && (substr($_,1,1) eq ':') && ($glob = substr($_,2)); +# Nothing (n) can be handled by returning nothing. (C.f. King Lear, I.i.) + if ($c =~ /[abcjuv]/) { + $ret = "-$c"; + } elsif ($c eq 'S') { + $ret = '-k signals'; + } elsif ($c eq 'd') { + if (defined($glob)) { + $qual = '-/'; + } else { + $ret = '-/'; + } + } elsif ($c eq 'e') { + $ret = '-E'; + } elsif ($c eq 'f' && !$glob) { + $ret = '-f'; + } elsif ($c eq 'l') { + $ret = q!-k "(`limit | awk '{print $1}'`)"!; + } elsif ($c eq 'p') { + $ret = "-W $glob -f", undef($glob) if defined($glob); + } elsif ($c eq 's') { + $ret = '-p'; + } elsif ($c eq 't') { + $qual = '.'; + } elsif ($c eq 'x') { + $glob =~ s/'/'\\''/g; + $ret = "-X '$glob'"; + undef($glob); + } elsif ($c eq '$') { # '){ + $ret = "-k " . substr($_,1); + } elsif ($c eq '(') { + s/'/'\\''/g; + $ret = "-k '$_'"; + } elsif ($c eq '`') { + # this took some working out... + if (s/\$:(\d+)/$foo=$1+1,"\${word[$foo]}"/ge) { + $ret = "-K $funcnam"; + $genfunc .= <<"HERE"; +function $funcnam { + local word + read -cA word + reply=($_) +} +HERE + $funcnam++; + } else { + s/'/'\\''/g; + $ret = "-s '$_'"; + } + } + + # foo{bar,ba,blak,sheap} -> foo(bar|ba|blak|sheap). + # This saves a lot of mess, since in zsh brace expansion occurs + # before globbing. I'm sorry, but I don't trust $` and $'. + while (defined($glob) && (($b,$m,$e) = ($glob =~ /^(.*)\{(.*)\}(.*)$/)) + && $m =~ /,/) { + @m = split(/,/, $m); + for ($i = 0; $i < @m; $i++) { + while ($m[$i] =~ /\\$/) { + substr($m[$i],-1,1) = ""; + splice(@m,$i,2,"$m[$i]\\,$m[$i+1]"); + } + } + $glob = $b . "(" . join('|',@m) . ")" . $e; + } + + if ($qual) { + $glob || ($glob = '*'); + $glob .= "($qual)"; + } + $glob && (($glob =~ s/'/'\\''/g),($glob = "-g '$glob'")); + + defined($ret) && defined($glob) && ($ret .= " $glob"); + defined($ret) ? $ret : $glob; +} + +# Quoted array separator for extended completions +$" = " - "; + +while (<>) { + if (/^\s*complete\s/) { + undef(@stuff); + $default = ''; + $_ = $'; + while (/\\$/) { + # Remove backslashed newlines: in principle these should become + # real newlines inside quotes, but what the hell. + ($_) = /^(.*)\\$/; + $_ .= <>; + } + $command = &getword; + if ($command =~ /^-/ || $command =~ /[*?]/) { + # E.g. complete -co* ... + $defmatch = $command; + ($defmatch =~ /^-/) && ($defmatch = substr($defmatch,1)); + } else { + undef($defmatch); + } + while (defined($word = &getword)) { + # Loop over remaining arguments to "complete". + $sep = substr($word,1,1); + $sep =~ s/(\W)/\\$1/g; + @split = split(/$sep/,$word); + for ($i = 0; $i < 3; $i++) { + while ($split[$i] =~ /\\$/) { + substr($split[$i],-1,1) = ""; + splice(@split,$i,2,"$split[$i]\\$sep$split[$i+1]"); + } + } + ($pat,$arg,$type,$suffix) = @split; + defined($suffix) && ($suffix =~ /^\s*$/) && undef($suffix); + if (($word =~ /^n$sep\*$sep/) && + (!defined($defmatch))) { + # The "complete" catch-all: treat this as compctl\'s + # default (requiring no pattern matching). + $default .= &gettype($type) . ' '; + defined($suffix) && ($defsuf .= $suffix); + } else { + $pat = &getpat($pat,$arg); + $type = &gettype($type); + if (defined($defmatch)) { + # The command is a pattern: use either -C or -D option. + if ($pat eq 'p[0]') { + # Command word (-C): 'p[0]' is redundant. + if ($defmatch eq '*') { + $defcommand = $type; + } else { + ($defmatch =~ /\*$/) && chop($defmatch); + if ($opt_x) { + $c = ($defmatch =~ /[*?]/) ? 'C' : 'c'; + $pat = $c . "[0,${defmatch}]"; + } else { + $pat = ($defmatch =~ /[*?]/) ? + "C[0,${defmatch}]" : "S[${defmatch}]"; + } + push(@commandword,defined($suffix) ? + "'$pat' $type -S '$suffix'" : "'$pat' $type"); + } + } elsif ($pat eq "C[-1,*]") { + # Not command word completion, but match + # command word (only) + if ($defmatch eq "*") { + # any word of any command + $defaultdefault .= " $type"; + } else { + $pat = "W[0,$defmatch]"; + push(@defaultword,defined($suffix) ? + "'$pat' $type -S '$suffix'" : "'$pat' $type"); + } + } else { + # Not command word completion, but still command + # word with pattern + ($defmatch eq '*') || ($pat = "W[0,$defmatch] $pat"); + push(@defaultword,defined($suffix) ? + "'$pat' $type -S '$suffix'" : "'$pat' $type"); + } + } else { + # Ordinary command + push(@stuff,defined($suffix) ? + "'$pat' $type -S '$suffix'" : "'$pat' $type"); + } + } + } + if (!defined($defmatch)) { + # Ordinary commands with no pattern + print("compctl $default"); + defined($defsuf) && print("-S '$defsuf' ") && undef($defsuf); + defined(@stuff) && print("-x @stuff -- "); + print("$command\n"); + } + if (defined($genfunc)) { + print $genfunc; + undef($genfunc); + } + } +} + +(defined(@commandword) || defined($defcommand)) && + print("compctl -C ", + defined($defcommand) ? $defcommand : '-c', + defined(@commandword) ? " -x @commandword\n" : "\n"); + +if (defined($defaultdefault) || defined(@defaultword)) { + defined($defaultdefault) || ($defaultdefault = "-f"); + print "compctl -D $defaultdefault"; + defined(@defaultword) && print(" -x @defaultword"); + print "\n"; +} + +__END__ |