1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-25 17:20:25 +02:00

zsh-3.1.5-pws-9

This commit is contained in:
Tanaka Akira 1999-04-15 18:16:27 +00:00
parent ba4f5e80ec
commit b4a5b9db8b
99 changed files with 3672 additions and 478 deletions

View file

@ -27,5 +27,5 @@
# This must also serve as a shell script, so do not add spaces around the # This must also serve as a shell script, so do not add spaces around the
# `=' signs. # `=' signs.
VERSION=3.1.5-pws-8 VERSION=3.1.5-pws-9
VERSION_DATE='February 13, 1999' VERSION_DATE='February 18, 1999'

View file

@ -38,7 +38,7 @@ TEXI2HTML = texi2html -expandinfo -split_chapter
.SUFFIXES: .yo .1 .SUFFIXES: .yo .1
# man pages to install # man pages to install
MAN = zsh.1 zshbuiltins.1 zshcompctl.1 \ MAN = zsh.1 zshbuiltins.1 zshcompctl.1 zshcompwid.1 \
zshexpn.1 zshmisc.1 zshmodules.1 \ zshexpn.1 zshmisc.1 zshmodules.1 \
zshoptions.1 zshparam.1 zshzle.1 zshall.1 zshoptions.1 zshparam.1 zshzle.1 zshall.1
@ -48,7 +48,7 @@ YODLSRC = zmacros.yo zman.yo ztexi.yo Zsh/arith.yo Zsh/builtins.yo \
Zsh/compat.yo Zsh/compctl.yo Zsh/cond.yo Zsh/exec.yo Zsh/expn.yo \ Zsh/compat.yo Zsh/compctl.yo Zsh/cond.yo Zsh/exec.yo Zsh/expn.yo \
Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/guide.yo \ Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/guide.yo \
Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \ Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \
Zsh/modules.yo Zsh/mod_cap.yo \ Zsh/modules.yo Zsh/mod_cap.yo Zsh/compwid.yo \
Zsh/mod_clone.yo Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \ Zsh/mod_clone.yo Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_deltochar.yo \
Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_stat.yo \ Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_stat.yo \
Zsh/mod_zle.yo Zsh/options.yo \ Zsh/mod_zle.yo Zsh/options.yo \

View file

@ -1,9 +1,9 @@
DISTFILES_SRC=' DISTFILES_SRC='
.distfiles .distfiles
arith.yo builtins.yo compat.yo compctl.yo cond.yo exec.yo expn.yo arith.yo builtins.yo compat.yo compctl.yo compwid.yo cond.yo exec.yo
filelist.yo files.yo func.yo grammar.yo guide.yo index.yo intro.yo expn.yo filelist.yo files.yo func.yo grammar.yo guide.yo index.yo intro.yo
invoke.yo jobs.yo metafaq.yo mod_cap.yo mod_clone.yo mod_comp1.yo invoke.yo jobs.yo metafaq.yo mod_cap.yo mod_clone.yo mod_comp1.yo
mod_compctl.yo mod_deltochar.yo mod_example.yo mod_files.yo mod_sched.yo mod_compctl.yo mod_deltochar.yo mod_example.yo mod_files.yo mod_sched.yo
mod_stat.yo mod_zle.yo modules.yo options.yo params.yo prompt.yo mod_stat.yo mod_zftp.yo mod_zle.yo modules.yo options.yo params.yo
redirect.yo restricted.yo seealso.yo zle.yo prompt.yo redirect.yo restricted.yo seealso.yo zle.yo
' '

View file

@ -1,4 +1,4 @@
texinode(Programmable Completion)(Zsh Modules)(Zsh Line Editor)(Top) texinode(Programmable Completion)(Completion Widgets)(Zsh Line Editor)(Top)
chapter(Programmable Completion) chapter(Programmable Completion)
cindex(completion, programmable) cindex(completion, programmable)
cindex(completion, controlling) cindex(completion, controlling)
@ -89,7 +89,7 @@ to the user database is too slow and/or it contains too many users (so
that completion after `tt(~)' is too slow to be usable), you can use that completion after `tt(~)' is too slow to be usable), you can use
indent( indent(
tt(compctl -T -x 'C[0,*/*]' -f - 's[~]' -k friends -S/ -tn) tt(compctl -T -x 's[~] C[0,[^/]#]' -k friends -S/ -tn)
) )
to complete the strings in the array tt(friends) after a `tt(~)'. to complete the strings in the array tt(friends) after a `tt(~)'.

428
Doc/Zsh/compwid.yo Normal file
View file

@ -0,0 +1,428 @@
texinode(Completion Widgets)(Zsh Modules)(Programmable Completion)(Top)
chapter(Completion Widgets)
cindex(completion, widgets)
cindex(completion, programmable)
cindex(completion, controlling)
sect(Description)
Completion widgets are defined using the tt(-C) option to the tt(zle)
builtin command provided by the tt(zle) module (see
ifzman(zmanref(zshzle))\
ifnzman(noderef(The zle Module))\
). For example, the invocation:
indent(nofill(
tt(zle -C complete expand-or-complete completer)))
defines a widget named tt(complete). If this widget is bound to a key
using the tt(bindkey) builtin command defined in the tt(zle) module
(see
ifzman(zmanref(zshzle))\
ifnzman(noderef(Zsh Line Editor))\
) typing that key will make the completion code call the shell
function tt(completer). This function is responsible for generating
the possible matches using the builtins described below. Once the
function returns, the completion code takes over control again and
treats the matches the way the builtin widget tt(expand-or-complete)
would do it. For this second argument, the name of any of the builtin
widgets that handle completions can be given, i.e. it may be any of
tt(complete-word), tt(expand-or-complete),
tt(expand-or-complete-prefix), tt(menu-complete),
tt(menu-expand-or-complete), tt(reverse-menu-complete),
tt(list-choices), or tt(delete-char-or-list).
startmenu()
menu(Special Parameters)
menu(Builtin Commands)
menu(Condition Codes)
menu(Examples)
endmenu()
texinode(Special Parameters)(Builtin Commands)()(Completion Widgets)
sect(Special Parameters)
Inside completion widgets some parameters have special meaning. They
will be used inside the widget function and other shell functions
called from it. Outside of these function they are not special to the
shell in any way.
The parameters are used to give information about the internal state
from the completion code to the completion widget and can be set to
give information to the completion code from the completion
widget. Some of the builtin commands and the condition codes use or
change the current values of these parameters. While the completion
widget is active, these parameters are reseton each function exit to
the values they had when the function was entered.
startitem()
item(tt(argv))(
The positional parameters are set to the arguments on the command line
when the widget function is invoked from the completion code.
)
item(tt(CURRENT))(
This is the number of the current word, i.e. the word the cursor is
currently on in the tt(argv) array.
)
item(tt(CONTEXT))(
This will be set by the completion code to the overall context
completion is attempted in. Possible values are:
startitem()
item(tt(command))(
when completing in a command position, e.g. in the first word on the
command line
)
item(tt(argument))(
when completing an argument for a command
)
item(tt(redirect))(
when completing after a redirection operator; in this case the
positional parameters contain not only the arguments but also the
command name itself as the first element
)
item(tt(condition))(
when completing inside a `tt([[)...tt(]])' conditional expressing; in
this case the positional parameters are set to the words inside the
conditional expressions
)
item(tt(math))(
when completing in a mathematical environment such as a
`tt(LPAR()LPAR())...tt(RPAR()RPAR())' construct
)
item(tt(value))(
when completing the value of a parameter assignment; in case of an
array value the positional parameters are set to the words in
parentheses
)
item(tt(subscript))(
when completing inside a parameter expansion subscript
)
enditem()
)
item(tt(COMMAND))(
In most cases this is set to name of the command for which completion
is tried. When completing after a redirection operator it contains the
string forming that operator. Also, when completing in the value of a
parameter assignment or in a parameter subscript it is set to the name
of the parameter.
)
item(tt(PREFIX))(
This should be set to that part of the current word that should be
taken as the string every possible match has to begin with. Initially
this will be set to the part of the current word from the beginning of
the word up to the position of the cursor. When
)
item(tt(IPREFIX))(
When a part of the current word should not be considered part of the
matches, this part should be taken from the tt(PREFIX) parameter and
appended to this parameter. This will initially be set to the empty
string when called from the completion code.
)
item(tt(SUFFIX))(
This should be set to that part of the current word that should be
taken as the string every possible match has to end with. The
completion code sets this to the part of the current word from the
cursor position to the end.
)
item(tt(NMATCHES))(
This is always set to the number of matches generated and accepted by
the completion code so far.
)
item(tt(MATCHER))(
When completion is used with a global match specification (i.e. a
tt(compctl) with only a tt(-M) option), this parameter is set to the
number of the specification string which is currently used.
)
enditem()
texinode(Builtin Commands)(Condition Codes)(Special Parameters)(Completion Widgets)
sect(Builtin Commands)
startitem()
findex(complist)
item(tt(complist) var(flags ...))(
Generate matches according to the given var(flags) which can be any of
the option flags supported by the tt(compctl) builtin command (see
ifzman(zmanref(zshcompctl))\
ifnzman(noderef(Programmable Completion))\
) except for the tt(-t) and tt(-l) flags. Also, when using the tt(-K)
flag, the function given as argument to it can not access the command
line with the tt(read) builtin command.
The matches will be generated in the same way as if the completion code
generated them directly from a tt(compctl)-definition with the same
flags. The completion code will consider only those matches as
possible completions that match the prefix and suffix from the special
parameters desribed above. These strings will be compared with the
generated matches using the normal matching rules and any matching
specifications given with the tt(-M) flag to tt(complist) and the
global matching specifications given to the tt(compctl) builtin
command.
)
xitem(tt(compadd) [ tt(-qQfnUam) ] [ tt(-F) var(array) ])
xitem([ tt(-P) var(prefix) ] [ tt(-S) var(suffix) ])
xitem([ tt(-p) var(hidden-prefix) ] [ tt(-s) var(hidden-suffix) ])
xitem([ tt(-i) var(ignored-prefix) ] [ tt(-W) var(file-prefix) ])
xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ])
xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ])
item([ tt(-M) var(match-spec) ] [ tt(--) ] [ var(words) ... ])(
This builtin command can be used to add matches and directly control
all the information the completion code stores with each possible
match.
The supported flags are:
startitem()
item(tt(-P) var(prefix))(
The same as for tt(compctl) and tt(complist), it gives a string that
should be inserted before the given words when they are completed. The
string given is not considered to be part of the match.
)
item(tt(-S) var(suffix))(
Like tt(-P) but gives a string that has to be inserted after the match.
)
item(tt(-p) var(hidden-prefix))(
This gives a string that should be
...
)
item(tt(-s) var(hidden-suffix))(
...
)
item(tt(-i) var(ignored-prefix))(
...
)
item(tt(-J) var(name))(
As for tt(compctl) and tt(complist) this gives the name of the group
of matches the words should be stored in.
)
item(tt(-V) var(name))(
Like tt(-J) but naming a unsorted group.
)
item(tt(-q))(
This flag has the same meaning as for tt(compctl) and tt(complist),
too. It makes the suffix given with tt(-S) be automatically removed if
the next character typed is a blank or does not insert anything or if
the suffix consists of only one character and the next character typed
is the same character.
)
item(tt(-r) var(remove-chars))(
This makes the suffix given with tt(-S) be automatically removed if
the next character typed inserts one of the characters given in the
var(remove-chars). This string is parsed as a characters class with
the usual backslash-sequences understood, e.g. using `tt(-r "a-z\t")'
removes the suffix if the next character typed inserts one of the
lower case letters or a TAB, and `tt(-r "^0-9")' removes the suffix if
the next character typed inserts anything but a digit. One extra
backslash sequence is understood in this string: `tt(\-)' stands for
all characters that insert nothing. Thus `tt(-S "=" -q)' is the same
as `tt(-S "=" -r "= \t\n\-")'.
)
item(tt(-R) var(remove-func))(
For the cases where one wants to remove suffix and the tt(-r) option
does not give enough control, this option can be used. It stores the
name of the shell function var(remove-func) in the matches. If one of
the matches is finally accepted and the tt(-S)-suffix inserted, this
function will be called after the next character typed. It gets the
length of the suffix as its argument and can use the special
parameters available in zle widgets (see
ifzman(zmanref(zshzle))\
ifnzman(noderef(Zsh Line Editor))\
) to analyse and modify the command line.
)
item(tt(-f))(
If this flag is given, the matches build are marked as being the names
of files. They need not be actual filenames, though. But if they are
and the option tt(LIST_TYPES) is set, the characters describing the
types of the files in the completion lists will be shown. This also
makes a slash automatically be added when the name of a directory is
completed.
)
item(tt(-W) var(file-prefix))(
This option has the same meaning as for the tt(compctl) and
tt(complist) builtin commands. Here, however, only one string may be
given, not an array. This string is used as a pathname that will be
prepended to the given words and the prefix given with the tt(-p)
option to perform the file-tests when showing completion
listings. Hence it is only useful if combined with the tt(-f) flag,
since the tests will only be performed if that flag is given.
)
item(tt(-a))(
When used by tt(compctl) or tt(complist) the completion code normally
builds two sets of matches: the normal one where words with one of the
suffixes in the array parameter tt(fignore) are not considered
possible matches, and the alternate set where the words excluded
from the first set are stored. Normally only the matches in the first
set are used. But if this set is empty, the words from the alternate
set are used.
The tt(compadd) builtin does not use tt(fignore) parameter and
normally stores all words in the first set. With the tt(-a)-flag
given, however, they are all stored in the alternate set unless this
flag is overridden by the tt(-F) option.
)
item(tt(-F) var(array))(
This can be used to give an array containing suffixes like the
tt(fignore) parameter. Words with one of these suffixes are stored in
the alternate set of matches and words without one of these suffixes
are stored in the normal set.
The var(array) may be the name of an array parameter or a list of
literal suffixes enclosed in parentheses as in `tt(-F "(.o .h)")'. If
the name of an array is given, the elements of the array are taken as
the suffixes.
)
item(tt(-Q))(
As for tt(compctl) and tt(complist) this flag instructs the completion
code not to quote any metacharacters in the words when inserting them
in the command line.
)
item(tt(-m))(
Normally the matches added by tt(compadd) will not be compared with
what is already on the line. If this flag is given, this comparison is
performed as usual and the match specifications given with the tt(-M)
option to tt(compadd) and the global match specifications defined with
tt(compctl) will be used. This means that probably not all the word
given will be stored as matches since some of them may not match the
string on the line.
)
item(tt(-M) var(match-spec))(
This option allows one to give local match specifications with the
same meaning and format as for the tt(compctl) and tt(complist)
builtin commands. Note that they will only be used if the tt(-m) is
given, too.
)
item(tt(-n))(
Words added with tt(compadd) with this flag will be used as possible
matches as usual but they not appear in the completion listing.
)
item(tt(-U))(
If this flag is given to one of the calls to tt(compadd) and the
option tt(AUTO_MENU) is set, the completion code will immediatly
switch to menucompletion.
)
item(tt(-), tt(--))(
This flag ends the list of flags and options. All arguments after it
will be taken as the words to use as matches even if they begin with
hyphens.
)
enditem()
)
item(tt(compcall) [ tt(-TD) ])(
This allows one to use completion definitions given with the
tt(compctl) builtin from within completion widgets. It makes
completion code complete the current word according to the
tt(compctl)s defined. Normally only tt(compctl)s given for specific
commands are used. To make the code use the completion flags given to
the tt(-T) option of tt(compctl), one can give the tt(-T) flag to
tt(compctl). Likewise, the tt(-D) flag to tt(compcall) makes the
default completion flags given to tt(compctl) with the tt(-D) option
be used.
)
enditem()
texinode(Condition Codes)(Examples)(Builtin Commands)(Completion Widgets)
sect(Condition Codes)
Inside completion widgets not only the builtin commands described
above can be used, but also some additional condition codes. These
work on the special parameters and can be used to easily build
completion functions that generate different matches depending on the
strings on the line.
The following condition codes are made available inside completion
widgets:
startitem()
item(tt(-prefix) var(string))(
true if the content of tt(PREFIX) starts with var(string)
)
item(tt(-iprefix) var(string))(
like tt(-prefix), but the var(string) is removed from tt(PREFIX) and
added to tt(IPREFIX)
)
item(tt(-position) var(beg) [ var(end) ])(
true if tt(CURRENT) is equal to var(beg) or, if var(end) is given,
equal to or greater than var(beg) and equal to or less than var(end);
both of var(beg) and var(end) may be arithmetic expressions, if they
are less than zero the number of words in tt(argv) are added to them
before comparing them to tt(CURRENT); thus, tt(-1) is the last word,
tt(-2) is the word before that and so on
)
item(tt(-word) var(index) var(string))(
true if the word number var(index) in tt(argv) is equal to
var(string); again, var(index) may be negative, counting backwards
)
item(tt(-mword) var(index) var(pattern))(
like tt(-word) but using pattern matching
)
item(tt(-current) var(offset) var(string))(
like tt(-word) but var(offset) is relative to the value of
tt(CURRENT)
)
item(tt(-mcurrent) var(offset) var(pattern))(
like tt(-current) but using pattern matching
)
item(tt(-string) [ var(number) ] var(string))(
true if the current word contains var(string); anything up to the last
occurrence of this string will be ingnored by removing it from
tt(PREFIX) and adding it to tt(IPREFIX); if var(number) is given,
anything up to the var(number)'th occurrence of the var(string) will
be ignored; again, var(nmuber) may be any arithmetic expression and
negative values count backward
)
item(tt(-class) [ var(number) ] var(class))(
like tt(-string) but the var(class) is used as a character class so
that anything up to and including the last or the var(number)'th
occurrence of any character from the string var(class) is ignored
)
item(tt(-words) var(min) [ var(max) ])(
true if the number of words is equal to var(min); if var(max) is
given, it is true if the number of words is equal to or greater than
var(min) and equal to or less than var(max)
)
item(tt(-after) var(string))(
true if the cursor is after a word that is equal to var(string)
)
item(tt(-mafter) var(pattern))(
like tt(-after) but using pattern matching
)
item(tt(-between) var(string1) var(string2))(
true if the cursor is after a word that is equal to var(string1), if
there is also a word that is equal to va(string2), this is true only
if the cursor is before it
)
item(tt(-mbetween) var(pattern1) var(pattern2))(
like tt(-between) but using pattern matching
)
item(tt(-nmatches) var(number))(
true if the the value of tt(NMATCHES) is equal to var(number)
)
item(tt(-matcher) var(number))(
true if the value of tt(MATCHER) is equal to var(number)
)
enditem()
texinode(Examples)()(Condition Codes)(Completion Widgets)
sect(Examples)
The first step is to define the widget:
indent(nofill(
tt(zle -C complete complete-word complete-history)))
Then the widget can be bound to a key using the tt(bindkey) builtin
command:
indent(nofill(
tt(bindkey '^X\t' complete)))
After that the shell function tt(complete-history) will be invoked
after typing control-X and TAB. The function should then generte the
matches, e.g.:
indent(nofill(
tt(complete-history LPAR()RPAR() { complist -H 0 '' })))
In this the function will complete words from the history matching the
current word.

View file

@ -29,6 +29,7 @@ menu(Options)
menu(Shell Builtin Commands) menu(Shell Builtin Commands)
menu(Zsh Line Editor) menu(Zsh Line Editor)
menu(Programmable Completion) menu(Programmable Completion)
menu(Completion Widgets)
menu(Zsh Modules) menu(Zsh Modules)
--- Indices --- --- Indices ---
@ -103,6 +104,13 @@ menu(Alternative Completion)
menu(Extended Completion) menu(Extended Completion)
menu(Example) menu(Example)
Completion Widgets
menu(Special Parameters)
menu(Builtin Commands)
menu(Condition Codes)
menu(Examples)
Zsh Modules Zsh Modules
menu(The cap Module) menu(The cap Module)

View file

@ -21,6 +21,7 @@ list(em(zshoptions) Zsh options)
list(em(zshbuiltins) Zsh built-in functions) list(em(zshbuiltins) Zsh built-in functions)
list(em(zshzle) Zsh command line editing) list(em(zshzle) Zsh command line editing)
list(em(zshcompctl) Zsh completion control) list(em(zshcompctl) Zsh completion control)
list(em(zshcompwid) Zsh completion widgets)
list(em(zshmodules) Zsh loadable modules) list(em(zshmodules) Zsh loadable modules)
ifzshone(\ ifzshone(\
list(em(zshall) Meta-man page containing all of the above) list(em(zshall) Meta-man page containing all of the above)

View file

@ -11,7 +11,7 @@ sect(Author)
cindex(author) cindex(author)
Zsh was originally written by Paul Falstad tt(<pf@zsh.org>). Zsh was originally written by Paul Falstad tt(<pf@zsh.org>).
Zsh is now maintained by the members of the zsh-workers mailing Zsh is now maintained by the members of the zsh-workers mailing
list tt(<zsh-workers@math.gatech.edu>). The development is currently list tt(<zsh-workers@sunsite.auc.dk>). The development is currently
coordinated by Andrew Main (Zefram) tt(<zefram@zsh.org>). The coordinator coordinated by Andrew Main (Zefram) tt(<zefram@zsh.org>). The coordinator
can be contacted at tt(<coordinator@zsh.org>), but matters relating to can be contacted at tt(<coordinator@zsh.org>), but matters relating to
the code should generally go to the mailing list. the code should generally go to the mailing list.

View file

@ -1,7 +1,12 @@
texinode(The compctl Module)(The deltochar Module)(The comp1 Module)(Zsh Modules) texinode(The compctl Module)(The deltochar Module)(The comp1 Module)(Zsh Modules)
sect(The compctl Module) sect(The compctl Module)
The tt(compctl) module makes available one builtin command, tt(compctl), The tt(compctl) module makes available several builtin commands. tt(compctl),
which is the standard way to control completions for ZLE. See is the standard way to control completions for ZLE. See
ifzman(zmanref(zshcompctl))\ ifzman(zmanref(zshcompctl))\
ifnzman(noderef(Programmable Completion))\ ifnzman(noderef(Programmable Completion))\
. .
The other builtin commands can be used in user-defined completion widgets,
see
ifzman(zmanref(zshcompwid))\
ifnzman(noderef(Completion Widgets))\
.

View file

@ -439,4 +439,8 @@ until the next call to tt(zftp). Other status changes in subshells
will not be reflected by changes to the variables (but should will not be reflected by changes to the variables (but should
be otherwise harmless). be otherwise harmless).
On some operatings systems, the control connection is not valid after a
fork(), so that operations in subshells or on the left hand side of a
pipeline are not possible.
enditem() enditem()

View file

@ -165,7 +165,7 @@ xitem(tt(zle) tt(-l) [ tt(-L) ])
xitem(tt(zle) tt(-D) var(widget) ...) xitem(tt(zle) tt(-D) var(widget) ...)
xitem(tt(zle) tt(-A) var(old-widget) var(new-widget)) xitem(tt(zle) tt(-A) var(old-widget) var(new-widget))
xitem(tt(zle) tt(-N) var(widget) [ var(function) ]) xitem(tt(zle) tt(-N) var(widget) [ var(function) ])
xitem(tt(zle) tt(-C) [ tt(-mMgG) ] var(widget) [ var(compctl-options) ]) xitem(tt(zle) tt(-C) var(widget) var(completion-widget) var(function))
item(tt(zle) var(widget))( item(tt(zle) var(widget))(
The tt(zle) builtin performs a number of different actions concerning The tt(zle) builtin performs a number of different actions concerning
ZLE. Which operation it performs depends on its options: ZLE. Which operation it performs depends on its options:
@ -193,22 +193,15 @@ widget is invoked from within the editor, the specified shell var(function)
is called. If no function name is specified, it defaults to is called. If no function name is specified, it defaults to
the same name as the widget. the same name as the widget.
) )
item(tt(-C) [ tt(-mMgG) ] var(widget) [ var(compctl-options) ])( item(tt(-C) var(widget) var(completion-widget) var(function))(
Create a user-defined widget which will perform completion according Create a user-defined completion widget names var(widget). The
to var(compctl-options). These are passed directly to the completion widget will behave like the built-in completion-widget
tt(compctl) command, see whose name is given as var(completion-widget). To generate the
ifzman(zmanref(zshcompctl))\ completions, the shell function var(function) will be called.
ifnzman(noderef(Programmable Completion))\ For further information, see
; no command names or special options (tt(-LDCT)) may be used. If the ifzman(zmanref(zshcompwid))\
var(compctl-options) are missing the widget will have normal ifnzman(noderef(Completion Widgets))\
completion behaviour as modified by the tt(zle) options. .
There are four additional tt(zle) options, which must precede the
widget name: tt(-m) and tt(-M) force the widget to use or not to use
menu completion, respectively, while tt(-g) and tt(-G) likewise force
the widget to use or not to use glob completion. The defaults are to
use the current settings of tt(MENU_COMPLETE) and tt(GLOB_COMPLETE)
as with normal completion.
) )
item(var(widget))( item(var(widget))(
Invoke the specified widget. This can only be done when ZLE is Invoke the specified widget. This can only be done when ZLE is

View file

@ -1,4 +1,4 @@
texinode(Zsh Modules)()(Programmable Completion)(Top) texinode(Zsh Modules)()(Completion Widgets)(Top)
chapter(Zsh Modules) chapter(Zsh Modules)
cindex(modules) cindex(modules)
sect(Description) sect(Description)
@ -19,7 +19,8 @@ item(tt(comp1))(
Base of the completion system. Used by the tt(compctl) and tt(zle) modules. Base of the completion system. Used by the tt(compctl) and tt(zle) modules.
) )
item(tt(compctl))( item(tt(compctl))(
The tt(compctl) builtin for controlling completion. The tt(compctl) builtin for controlling completion and the builtins for
completion widgets.
) )
item(tt(deltochar))( item(tt(deltochar))(
A ZLE function duplicating EMACS' tt(zap-to-char). A ZLE function duplicating EMACS' tt(zap-to-char).

View file

@ -544,12 +544,14 @@ List jobs in the long format by default.
) )
pindex(MAGIC_EQUAL_SUBST) pindex(MAGIC_EQUAL_SUBST)
item(tt(MAGIC_EQUAL_SUBST))( item(tt(MAGIC_EQUAL_SUBST))(
All unquoted arguments of the form `var(identifier)tt(=)var(expression)' All unquoted arguments of the form `var(anything)tt(=)var(expression)'
appearing after the command name have filename expansion (that is, appearing after the command name have filename expansion (that is,
where var(expression) has a leading `tt(~)' or `tt(=)') performed on where var(expression) has a leading `tt(~)' or `tt(=)') performed on
var(expression) as if it were a parameter assignment. The argument is var(expression) as if it were a parameter assignment. The argument is
not otherwise treated specially; it is passed to the command as a single not otherwise treated specially; it is passed to the command as a single
argument, and not used as an actual parameter assignment. argument, and not used as an actual parameter assignment. For example, in
tt(echo foo=~/bar:~/rod), both occurrences of tt(~) would be replaced.
Note that this happens anyway with tt(typeset) and similar statements.
) )
pindex(MAIL_WARNING) pindex(MAIL_WARNING)
cindex(mail, warning of reading) cindex(mail, warning of reading)

View file

@ -10,6 +10,7 @@ ifzshone(\
, ,
zmanref(zshbuiltins), zmanref(zshbuiltins),
zmanref(zshcompctl), zmanref(zshcompctl),
zmanref(zshcompwid),
zmanref(zshexpn), zmanref(zshexpn),
zmanref(zshmisc), zmanref(zshmisc),
zmanref(zshmodules), zmanref(zshmodules),

View file

@ -64,6 +64,7 @@ ifnzman(includefile(Zsh/options.yo))
ifnzman(includefile(Zsh/builtins.yo)) ifnzman(includefile(Zsh/builtins.yo))
ifnzman(includefile(Zsh/zle.yo)) ifnzman(includefile(Zsh/zle.yo))
ifnzman(includefile(Zsh/compctl.yo)) ifnzman(includefile(Zsh/compctl.yo))
ifnzman(includefile(Zsh/compwid.yo))
ifnzman(includefile(Zsh/modules.yo)) ifnzman(includefile(Zsh/modules.yo))
ifzshall(\ ifzshall(\
def(source)(1)(NOTRANS(.so )man1/ARG1NOTRANS(.)1)\ def(source)(1)(NOTRANS(.so )man1/ARG1NOTRANS(.)1)\
@ -75,6 +76,7 @@ source(zshoptions)
source(zshbuiltins) source(zshbuiltins)
source(zshzle) source(zshzle)
source(zshcompctl) source(zshcompctl)
source(zshcompwid)
source(zshmodules) source(zshmodules)
manpage(ZSHALL)(1)(date())(zsh version()) manpage(ZSHALL)(1)(date())(zsh version())
)\ )\

3
Doc/zshcompwid.yo Normal file
View file

@ -0,0 +1,3 @@
manpage(ZSHCOMPWID)(1)(date())(zsh version())
manpagename(zshcompwid)(zsh completion widgets)
includefile(Zsh/compwid.yo)

View file

@ -76,9 +76,12 @@ Reliant: SINIX
linking; configure now detects this and will disable dynamic linking; configure now detects this and will disable dynamic
linking even if you requested it. linking even if you requested it.
SGI: IRIX 5.1.1.1, 5.2, 5.3, 6.2, 6.3 SGI: IRIX 5.1.1.1, 5.2, 5.3, 6.2, 6.3, 6.5
Should build `out-of-the-box'. Should build `out-of-the-box'.
On 6.5.2, zsh malloc routines are reported not to work; also
full optimization (cc -O3 -OPT:Olimit=0) causes problems.
Sun: SunOS 4.1.* Sun: SunOS 4.1.*
Under 4.1.3 if yellow pages is used, username completion may cause Under 4.1.3 if yellow pages is used, username completion may cause
segmentation violation. This is a bug in the shared library not segmentation violation. This is a bug in the shared library not

View file

@ -0,0 +1,3 @@
#defcomp unalias
complist -a

View file

@ -0,0 +1,3 @@
#defcomp shift
complist -A

View file

@ -0,0 +1,3 @@
#defcomp autoload
complist -s '${^fpath}/*(N:t)'

View file

@ -0,0 +1,3 @@
#defcomp bg
complist -z -P '%'

View file

@ -0,0 +1,7 @@
#defcomp bindkey
if [[ -mword 1 -*[DAN]* || -mcurrent -1 -*M ]]; then
complist -s '$(bindkey -l)'
else
complist -b
fi

View file

@ -0,0 +1,7 @@
#defcomp builtin
if [[ -position 2 -1 ]]; then
compsub
else
complist -eB
fi

3
Functions/Completion/_cd Normal file
View file

@ -0,0 +1,3 @@
#defcomp cd
_files -W cdpath -g '*(-/)'

View file

@ -0,0 +1,7 @@
#defcomp command
if [[ -position 2 -1 ]]; then
_normal "$@"
else
complist -em
fi

View file

@ -0,0 +1,3 @@
#defcomp -command-
complist -c

View file

@ -0,0 +1,3 @@
#defcomp compress
_files -g '*~*.Z'

View file

@ -0,0 +1,10 @@
#defcomp -condition-
if [[ -current -1 -o ]]; then
complist -o -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}'
elif [[ -current -1 -nt || -current -1 -ot || -current -1 -ef ]]; then
_files
else
_files
complist -v
fi

View file

@ -0,0 +1,12 @@
#defcomp configure
if [[ $PREFIX = *=* ]]; then
# Complete filenames after e.g. --prefix=
IPREFIX=${PREFIX%%=*}=
PREFIX=${PREFIX#*=}
complist -f
else
# Generate a list of options from configure --help
complist -s '$($COMMAND --help |
sed -n -e '\''s/^ *\(--[-a-z0-9]*\)[ =,].*$/\1/p'\'')'
fi

13
Functions/Completion/_dd Normal file
View file

@ -0,0 +1,13 @@
#defcomp dd
if [[ -iprefix conv= ]]; then
# If there's a comma present, ignore up to the last one. The
# test alone will have that effect.
[[ -string , ]]
complist -S, -q \
-k '(ascii ebcdic ibm block unblock lcase ucase swab noerror sync)'
elif [[ -iprefix 'if=' || -iprefix 'of=' ]]; then
_files
else
complist -S '=' -k '(if of ibs obs bs cbs skip files seek count conv)'
fi

View file

@ -0,0 +1,13 @@
#defcomp -default-
# We first try the `compctl's. This is without first (-T) and default (-D)
# completion. If you want them add `-T' and/or `-D' to this command.
# If there is a `compctl' for the command we are working on, we return
# immediatly. If you want to use new style completion anyway, remove the
# `|| return'. Also, you may want to use new style completion if the
# `compctl' didn't produce any matches. In that case remove the `|| return'
# and at the line `[[ -nmatches 0 ]] || return' after `compcall'.
compcall || return
_files

View file

@ -0,0 +1,3 @@
#defcomp rmdir df du dircmp
_files -/ '*(-/)'

View file

@ -0,0 +1,6 @@
#defcomp disable
[[ -mcurrent -1 -*a* ]] && complist -ea
[[ -mcurrent -1 -*f* ]] && complist -eF
[[ -mcurrent -1 -*r* ]] && complist -ew
[[ ! -mcurrent -1 -* ]] && complist -eB

View file

@ -0,0 +1,3 @@
#defcomp xdvi dvips dvibook dviconcat dvicopy dvidvi dviselect dvitodvi dvitype
_files -g '*.(dvi|DVI)'

View file

@ -0,0 +1,3 @@
#defcomp echotc
complist -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)'

View file

@ -0,0 +1,6 @@
#defcomp enable
[[ -mcurrent -1 -*a* ]] && complist -da
[[ -mcurrent -1 -*f* ]] && complist -dF
[[ -mcurrent -1 -*r* ]] && complist -dw
[[ ! -mcurrent -1 -* ]] && complist -dB

7
Functions/Completion/_fc Normal file
View file

@ -0,0 +1,7 @@
#defcomp fc
if [[ -mcurrent -1 -*e ]]; then
complist -c
elif [[ -mcurrent -1 -[ARWI]## ]]; then
_files
fi

View file

@ -0,0 +1,10 @@
#autoload
# Utility function for completing files of a given type or any file.
# In many cases you will want to call this one instead of _path_files().
local nm=$NMATCHES
_path_files "$@"
[[ $# -ne 0 && -nmatches nm ]] && _path_files

View file

@ -0,0 +1,21 @@
#defcomp find
if [[ -mbetween -(ok|exec) \\\; ]]; then
_normal "$@"
elif [[ -iprefix - ]]; then
complist -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'
elif [[ -position 1 ]]; then
complist -g '. ..'
_files -g '(-/)'
elif [[ -mcurrent -1 -((a|c|)newer|fprint(|0|f)) ]]; then
_files
elif [[ -current -1 -fstype ]]; then
complist -k '(ufs 4.2 4.3 nfs tmp mfs S51K S52K)'
elif [[ -current -1 -group ]]; then
complist -k groups
elif [[ -current -1 -user ]]; then
complist -u
fi

View file

@ -0,0 +1,3 @@
#defcomp unfunction
complist -F

View file

@ -0,0 +1,3 @@
#defcomp gunzip zcat
_files -g '*.[gG][z]'

View file

@ -0,0 +1,3 @@
#defcomp gzip
_files -g '*~*.[gG][zZ]'

View file

@ -0,0 +1,13 @@
#defcomp hash
if [[ -mword 1 -*d* ]]; then
if [[ -string 1 '=' ]]; then
_path_files -g '*(-/)'
else
complist -n -q -S '='
fi
elif [[ -string 1 '=' ]]; then
_files -g '*(*)' '*(-/)'
else
complist -m -q -S '='
fi

View file

@ -0,0 +1,3 @@
#defcomp ftp ncftp ping rwho rup xping traceroute nslookup
complist -k hosts

View file

@ -0,0 +1,3 @@
#defcomp fg jobs
complist -j -P '%'

View file

@ -0,0 +1,8 @@
#defcomp kill
if [[ -iprefix '-' ]]; then
complist -k "($signals[1,-3])"
else
complist -P '%' -j
complist -y _kill_helper -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'
fi

View file

@ -0,0 +1,3 @@
#autoload
reply=( "$(ps 2>/dev/null)" )

View file

@ -0,0 +1,3 @@
#defcomp limit unlimit
complist -k "(${(j: :)${(f)$(limit)}%% *})"

View file

@ -0,0 +1,48 @@
#autoload
# The main loop of the completion code. This is what is called when
# completion is attempted from the command line.
# The completion code gives us the special variables and the arguments
# from the command line are given as positional parameters.
local comp name
setopt localoptions nullglob rcexpandparam globdots
unsetopt markdirs globsubst shwordsplit nounset
# An entry for `-first-' is the replacement for `compctl -T'
# Completion functions may set `COMPSKIP' to any value to make the
# main loops stop calling other completion functions.
comp="$comps[-first-]"
if [[ ! -z "$comp" ]]; then
"$comp" "$@"
if (( $+COMPSKIP )); then
unset COMPSKIP
return
fi
fi
# For arguments we use the `_normal function.
if [[ $CONTEXT == argument || $CONTEXT == command ]]; then
_normal "$@"
else
# Let's see if we have a special completion definition for the other
# possible contexts.
comp=''
case $CONTEXT in
redirect) comp="$comps[-redirect-]";;
math) comp="$comps[-math-]";;
subscript) comp="$comps[-subscript-]";;
value) comp="$comps[-value-]";;
condition) comp="$comps[-condition-]";;
esac
# If not, we use default completion, if any.
[[ -z "$comp" ]] && comp="$comps[-default-]"
[[ -z "$comp" ]] || "$comp" "$@"
fi

View file

@ -0,0 +1,3 @@
#defcomp make gmake pmake
complist -s "\$(awk '/^[a-zA-Z0-9][^/ ]+:/ {print \$1}' FS=: [mM]akefile)"

11
Functions/Completion/_man Normal file
View file

@ -0,0 +1,11 @@
#defcomp man
setopt localoptions rcexpandparam
local rep
if [[ $2 = (<->*|ln) ]]; then
rep=( $manpath/(man|cat)$2/$PREFIX*$SUFFIX.<->*(N:t:r) )
else
rep=( $manpath/(man|cat)*/$PREFIX*$SUFFIX.<->*(N:t:r) )
fi
(( $#rep )) && compadd -m $rep

70
Functions/Completion/_mh Normal file
View file

@ -0,0 +1,70 @@
#defcomp folder comp inc mark refile repl scan show next prev rmm pick whom mhn mhpath mhpatch
# Completion for all possible MH commands.
# Alter the following two to your own mh directory and the directory
# where standard mh library files live. (It works anyway, but this
# will save a little time.)
local mymhdir=~/Mail
local mhlib=/usr/lib/mh
# To be on the safe side, check this exists and if not, get it anyway.
[[ -d $mymhdir ]] || mymhdir=$(mhpath +)
if [[ -iprefix - ]]; then
# get list of options, which MH commands can generate themselves
# awk is just too icky to use for this, sorry. send me one if
# you come up with it.
compadd -m $($COMMAND -help | perl -ne 'if (/^\s*-\(?(\S+)/) {
$n = $1;
$n =~ s/\)//g;
print $n =~ s/^\[([a-z]+)\]// ? "$n\n$1$n\n" : "$n\n";
}')
return
elif [[ -iprefix '+' || -iprefix '@' || -current -1 -draftfolder ]]; then
# Complete folder names.
local mhpath
if [[ $IPREFIX != '@' ]]; then
[[ $IPREFIX = '+' ]] || IPREFIX=+
mhpath=$mymhdir
else
mhpath=$(mhpath)
fi
# painless, or what?
complist -W mhpath -/
elif [[ -mcurrent -1 -(editor|(whatnow|rmm|show|more)proc) ]]; then
complist -c
elif [[ -current -1 -file ]]; then
complist -f
elif [[ -mcurrent -1 -(form|audit|filter) ]]; then
# Need some MH template file, which may be in our own MH directory
# or with the standard library.
local mhfpath
# This is the only place we need mhlib, so leave the test till here.
[[ -d $mhlib ]] || { mhlib=$(mhparam mhlproc); mhlib=$mhlib:h; }
mhfpath=($mymhdir $mhlib)
complist -W mhfpath -g '*(.)'
elif [[ -mcurrent -1 -(no|)cc ]]; then
compadd -m all to cc me
elif [[ -mcurrent -1 -[rw]cache ]]; then
compadd -m public private never ask
else
# Generate sequences.
local foldnam folddir f
for f in $argv; do
[[ $f = [@+]* ]] && foldnam=$f
done
if [[ $foldnam = '+'* ]]; then
folddir=$mymhdir/${foldnam#+}
elif [[ $foldnam = '@'* ]]; then
folddir=$(mhpath)/${foldnam#@}
else
folddir=$(mhpath)
# leaving foldnam empty works here
fi
complist -s '$(mark $foldnam | awk -F: '\''{ print $1 }'\'')'
compadd -m reply next cur prev first last all unseen
complist -W folddir -g '<->'
fi

View file

@ -0,0 +1,3 @@
#defkeycomp expand-or-complete \C-xm
complist -g '*(om[1])'

View file

@ -0,0 +1,56 @@
#autoload
local comp cmd1 cmd2 pat val name
# Completing in command position? If not we set up `cmd1' and `cmd2' as
# two strings we have search in the completion definition arrays (e.g.
# a path and the last path name component).
if [[ $CONTEXT == command ]]; then
comp="$comps[-command-]"
[[ -z "$comp" ]] || "$comp" "$@"
return
elif [[ "$COMMAND[1]" == '=' ]]; then
eval cmd1\=$COMMAND
cmd2="$COMMAND[2,-1]"
elif [[ "$COMMAND" == */* ]]; then
cmd1="$COMMAND"
cmd2="${COMMAND:t}"
else
cmd1="$COMMAND"
eval cmd2=$(whence -p $COMMAND)
fi
# See if there are any matching pattern completions.
if (( $#patcomps )); then
for i in "$patcomps[@]"; do
pat="${i% *}"
val="${i#* }"
if [[ "$cmd1" == $~pat || "$cmd2" == $~pat ]]; then
"$val" "$@"
if (( $+COMPSKIP )); then
unset COMPSKIP
return
fi
fi
done
fi
# Now look up the two names in the normal completion array.
name="$cmd1"
comp="$comps[$cmd1]"
if [[ -z "$comp" ]]; then
name="$cmd2"
comp="$comps[$cmd2]"
fi
# And generate the matches, probably using default completion.
if [[ -z "$comp" ]]; then
name=-default-
comp="$comps[-default-]"
fi
[[ -z "$comp" ]] || "$comp" "$@"

View file

@ -0,0 +1,272 @@
#autoload
# Utility function for in-path completion.
# First argument should be an complist-option (e.g. -f, -/, -g). The other
# arguments should be glob patterns, one per argument.
#
# E.g.: _path_files -g '*.tex' '*.texi'
#
# This is intended as a replacement for `complist -f', `complist -/', and
# `complist -g ...' (but don't use it with other options).
#
# You may also give the `-W <spec>' option as with `compctl' and `complist',
# but only as the first argument.
#
# This function also accepts an optional `-F <string>' option as its first
# argument or just after the `-W <spec>'. This can be used to define file
# name extension (a la `fignore'). Files with such an extension will not
# be considered possible completions.
#
# This function behaves as if you have a matcher definition like:
# compctl -M 'r:|[-.,_/]=* r:|=* m:{a-z}={A-Z} m:-=_ m:.=,' \
# 'm:{a-z}={A-Z} l:|=* r:|=*'
# so you may want to modify this.
local nm prepaths str linepath realpath donepath patstr prepath testpath rest
local tmp1 collect tmp2 suffixes i ignore
setopt localoptions nullglob rcexpandparam globdots extendedglob
unsetopt markdirs globsubst shwordsplit nounset
# Get the optional `-W' option and its argument.
if [[ "$1" = -W ]]; then
tmp1="$2"
if [[ "$tmp1[1]" = '(' ]]; then
prepaths=( $tmp1[2,-2]/ )
else
prepaths=( ${(P)${tmp1}} )
[[ $#prepaths -eq 0 ]] && prepaths=( $tmp1/ )
fi
[[ $#prepaths -eq 0 ]] && prepaths=( '' )
shift 2
else
prepaths=( '' )
fi
# Get the optional `-F' option and its argument.
if [[ "$1" = -F ]]; then
ignore=(-F "$2")
shift 2
else
ignore=''
fi
# str holds the whole string from the command line with a `*' between
# the prefix and the suffix.
str="${PREFIX:q}*${SUFFIX:q}"
# We will first try normal completion called with `complist', but only if we
# weren't given a `-F' option.
if [[ -z "$ignore" ]]; then
# First build an array containing the `-W' option, if there is any and we
# want to use it. We don't want to use it if the string from the command line
# is a absolute path or relative to the current directory.
if [[ -z "$tmp1[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]]; then
tmp1=()
else
tmp1=(-W "( $prepaths )")
fi
# Now call complist.
nm=$NMATCHES
if [[ $# -eq 0 ]]; then
complist "$tmp1[@]" -f
elif [[ "$1" = -g ]]; then
complist "$tmp1[@]" -g "$argv[2,-1]"
shift
else
complist "$tmp1[@]" $1
shift
fi
# If this generated any matches, we don't wnat to do in-path completion.
[[ -nmatches nm ]] || return
# No `-F' option, so we want to use `fignore'.
ignore=(-F fignore)
fi
# If we weren't given any file patterns as arguments, we trick ourselves
# into believing that we were given the pattern `*'. This is just to simplify
# the following code.
[[ -z "$1" ]] && 1='*'
# Now let's have a closer look at the string to complete.
if [[ "$str[1]" = \~ ]]; then
# It begins with `~', so remember anything before the first slash to be able
# to report it to the completion code. Also get an expanded version of it
# (in `realpath'), so that we can generate the matches. Then remove that
# prefix from the string to complete, set `donepath' to build the correct
# paths and make sure that the loop below is run only once with an empty
# prefix path by setting `prepaths'.
linepath="${str%%/*}/"
eval realpath\=path
str="${str#*/}"
donepath=''
prepaths=( '' )
else
# If the string does not start with a `~' we don't remove a prefix from the
# string.
liniepath=''
realpath=''
if [[ "$str[1]" = / ]]; then
# If it is a absolut path name, we remove the first slash and put it in
# `donepath' meaning that we treat it as the path that was already handled.
# Also, we don't use the paths from `-W'.
str="$str[2,-1]"
donepath='/'
prepaths=( '' )
else
# The common case, we just use the string as it is, unless it begins with
# `./' or `../' in which case we don't use the paths from `-W'.
[[ "$str" = (.|..)/* ]] && prepaths=( '' )
donepath=''
fi
fi
# First we skip over all pathname components in `str' which really exist in
# the file-system, so that `/usr/lib/l<TAB>' doesn't offer you `lib' and
# `lib5'. Pathname components skipped this way are taken from `str' and added
# to `donepath'.
while [[ "$str" = */* ]] do
[[ -e "$realpath$donepath${str%%/*}" ]] || break
donepath="$donepath${str%%/*}/"
str="${str#*/}"
done
# Now build the glob pattern. As noted above, this function behaves as if
# a global matcher with two matching specifications are given.
if [[ -matcher 1 ]]; then
patstr="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*."
else
patstr="${str%/*}/*${str##*/}*"
patstr="$patstr:gs./.*/.:gs.**.*."
fi
# Finally, generate the matches. First we loop over all the paths from `-W'.
# Note that in this loop `str' is used as a modifyable version of `patstr'
# and `testpath' is a modifyable version of `donepath'.
for prepath in "$prepaths[@]"; do
str="$patstr"
testpath="$donepath"
# The second loop tests the components of the path in `str' to get the
# possible matches.
while [[ "$str" = */* ]] do
# `rest' is the pathname after the first slash that is left. In `tmp1'
# we get the globbing matches for the pathname component currently
# handled.
rest="${str#*/}"
tmp1="${prepath}${realpath}${testpath}(#l)${str%%/*}(-/)"
tmp1=( $~tmp1 )
if [[ $#tmp1 -eq 0 ]]; then
# If this didn't produce any matches, we don't need to test this path
# any further, so continue with the next `-W' path, if any.
continue 2
elif [[ $#tmp1 -gt 1 ]]; then
# If it produced more than one match, we want to remove those which
# don't have possible following pathname components matching the
# rest of the string we are completing. (The case with only one
# match is handled below.)
# In `collect' we will collect those of the produced pathnames that
# have a matching possible path-suffix. In `suffixes' we build an
# array containing strings build from the rest of the string to
# complete and the glob patterns we were given as arguments.
collect=()
suffixes=( $rest$@ )
suffixes=( "${(@)suffixes:gs.**.*.}" )
# In the loop the prefixes from the `tmp1' array produced above and
# the suffixes we just built are used to produce possible matches
# via globbing.
for i in $tmp1; do
tmp2=( $~i/(#l)$~suffixes )
[[ $#tmp2 -ne 0 ]] && collect=( $collect $i )
done
# If this test showed that none of the matches from the glob in `tmp1'
# has a possible sub-path matching what's on the line, we give up and
# continue with the next `-W' path.
if [[ $#collect -eq 0 ]]; then
continue 2
elif [[ $#collect -ne 1 ]]; then
# If we have more than one possible match, this means that the
# pathname component currently handled is ambiguous, so we give
# it to the completion code.
# First we build the full path prefix in `tmp1'.
tmp1="$prepath$realpath$testpath"
# Now produce all matching pathnames in `collect'.
collect=( $~collect/(#l)$~suffixes )
# And then remove the common path prefix from all these matches.
collect=( ${collect#$tmp1} )
# Finally, we add all these matches with the common (unexpanded)
# pathprefix (the `-p' option), the path-prefix (the `-W' option)
# to allow the completion code to test file type, and the path-
# suffix (the `-s' option). We also tell the completion code that
# these are file names and that `fignore' should be used as usual
# (the `-f' and `-F' options).
for i in $collect; do
compadd -p "$linepath$testpath" -W "$tmp1" -s "/${i#*/}" -f "$ignore[@]" - "${i%%/*}"
done
# We have just finished handling all the matches from above, so we
# can continue with the next `-W' path.
continue 2
fi
# We reach this point if only one of the path prefixes in `tmp1'
# has a existing path-suffix matching the string from the line.
# In this case we accept this match and continue with the next
# path-name component.
tmp1=( "$collect[1]" )
fi
# This is also reached if the first globbing produced only one match
# in this case we just continue with the next pathname component, too.
tmp1="$tmp1[1]"
testpath="$testpath${tmp1##*/}/"
str="$rest"
done
# We are here if all pathname components except the last one (which is still
# not tested) are unambiguous. So we add matches with the full path prefix,
# no path suffix, the `-W' we are currently handling, all the matches we
# can produce in this directory, if any.
tmp1="$prepath$realpath$testpath"
suffixes=( $str$@ )
suffixes=( "${(@)suffixes:gs.**.*.}" )
tmp2=( $~tmp1(#l)$~suffixes )
compadd -p "$linepath$testpath" -W "$prepath$realpath$testpath" -f "$ignore[@]" - ${tmp2#$tmp1}
done

View file

@ -0,0 +1,3 @@
function acroread
_files -g '*.(pdf|PDF)'

View file

@ -0,0 +1,5 @@
#defcomp - nohup nice eval time rusage noglob nocorrect exec
[[ -position 1 -1 ]]
_normal "$@"

3
Functions/Completion/_ps Normal file
View file

@ -0,0 +1,3 @@
#defcomp gs ghostview gview psnup psselect pswrap pstops pstruct lpr
_files -g '*([pP][sS]|eps)'

View file

@ -0,0 +1,9 @@
#defcomp co ci rcs
[[ $COMMAND = ci || $COMMAND = rcs ]] && _files
if [[ $NMATCHES -eq 0 && -d RCS && $COMMAND != ci ]]; then
local rep
rep=(RCS/$PREFIX*$SUFFIX,v(:t:s/\,v//))
(( $#rep )) && compadd -m $rep
fi

View file

@ -0,0 +1,9 @@
#defcomp rlogin rsh ssh
if [[ -position 1 ]]; then
complist -k hosts
elif [[ -position 2 ]]; then
complist -k '(-l)'
else
complist -u
fi

View file

@ -0,0 +1,3 @@
#defcomp sched
[[ -position 2 -1 ]] && compsub

View file

@ -0,0 +1,7 @@
#defcomp set
if [[ -mcurrent -1 [-+]o ]]; then
complist -o
elif [[ -current -1 -A ]]; then
complist -A
fi

View file

@ -0,0 +1,7 @@
#defcomp setopt
local nm=$NMATCHES
complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
-s '$({ unsetopt kshoptionprint; unsetopt } 2>/dev/null)'
[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o

View file

@ -0,0 +1,7 @@
#defcomp source
if [[ -position 2 -1 ]]; then
compsub
else
_files
fi

View file

@ -0,0 +1,2 @@
#defcomp strip
_files -g '*(*)'

View file

@ -0,0 +1,16 @@
#defcomp stty
if [[ -mcurrent -1 \
(*erase|discard|status|dsusp|intr|kill|lnext|quit|reprint|start|s*p) ]]
then
compadd -m -Q '^-' '^h' '^?' '^c' '^u'
else
[[ -string '-' || -string '+' ]]
compadd -m rows columns intr quit erase kill eof eol \
eol2 start stop susp dsusp reprint discard werase lnext \
parenb parodd cs8 cstopb hupcl cread clocal parext \
ignbrk brkint ignpar parmrk inpck istrip inlcr igncr icrnl iuclc \
ixon ixany ixoff imaxbel isig icanon xcase echo echoe echok \
echonl noflsh tostop echoctl echoprt echoke flusho pending iexten \
opost olcuc onlcr ocrnl onocr onlret ofill ofdel
fi

View file

@ -0,0 +1,4 @@
#defcomp -subscript-
_compalso -math- "$@"
[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"

11
Functions/Completion/_tar Normal file
View file

@ -0,0 +1,11 @@
#defcomp tar
local nm=$NMATCHES tf="$2"
if [[ ( -mword 1 *t*f* || -mword 1 *x*f* ) && -position 3 100000 ]]; then
complist -k "( $(tar tf $tf) )"
elif [[ -mword 1 *c*f* && -position 3 100000 ]]; then
_files
elif [[ -mcurrent -1 *f* && -position 2 ]]; then
_files -g '*.(tar|TAR)'
fi

View file

@ -0,0 +1,3 @@
#defcomp tex latex slitex
_files -g '*.(tex|TEX|texinfo|texi)'

View file

@ -0,0 +1,7 @@
#defcomp trap
if [[ -position 1 ]]; then
complist -c
else
complist -k signals
fi

View file

@ -0,0 +1,3 @@
#defcomp uncompress zmore
_files -g '*.Z'

View file

@ -0,0 +1,6 @@
#defcomp unhash
[[ -mword 1 -*d* ]] && complist -n
[[ -mword 1 -*a* ]] && complist -a
[[ -mword 1 -*f* ]] && complist -F
[[ ! -mword 1 -* ]] && complist -m

View file

@ -0,0 +1,7 @@
#defcomp unsetopt
local nm=$NMATCHES
complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
-s '$({ unsetopt kshoptionprint; setopt } 2>/dev/null)'
[[ -nmatches nm ]] && complist -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o

View file

@ -0,0 +1,3 @@
#defcomp -math- getopts read unset vared
complist -v

View file

@ -0,0 +1,3 @@
#defcomp declare export integer local readonly typeset
complist -v -q -S '='

View file

@ -0,0 +1,4 @@
#defcomp wait
complist -P '%' -j
complist -y _kill_helper -s '`ps 2>/dev/null | tail +2 | cut -c1-5`'

View file

@ -0,0 +1,3 @@
#defcomp which whence where type
complist -caF

View file

@ -0,0 +1,5 @@
#defpatcomp */X11/*
# A simple pattern completion, just as an example.
complist -J options -k '(-display -name -xrm)'

View file

@ -0,0 +1,3 @@
#defcomp xfig
_files -g '*.fig'

View file

@ -0,0 +1,50 @@
#defpatcomp zf*
# Don't try any more completion after this.
COMPSKIP=1
# Completion for zftp builtin and zf* functions. The functions
# zfcd_match and zfget_match (used for old-style completion)
# need to be installed for remote file and directory completion to work.
local subcom
if [[ $COMMAND = zftp ]]; then
if [[ $CURRENT -eq 1 ]]; then
compadd -m open params user login type ascii binary mode put \
putat get getat append appendat ls dir local remote mkdir rmdir
return
fi
subcom=$1
else
subcom=$COMMAND
fi
case $subcom in
*(cd|ls|dir))
# complete remote directories; we could be smarter about hiding prefixes
zfcd_match $PREFIX $SUFFIX
(( $#reply )) && compadd -m -S/ -q $reply
;;
*(get(|at)|gcp|delete|remote))
# complete remote files
zfget_match $PREFIX $SUFFIX
(( $#reply )) && compadd -F fignore -m $reply
;;
*(put(|at)|pcp))
# complete local files
_files
;;
*(open|anon|params))
# complete hosts: should do cleverer stuff with user names
complist -k hosts
;;
*)
# dunno... try ordinary completion after all.
unset COMPSKIP
;;
esac

View file

@ -0,0 +1,7 @@
#defcomp zle
if [[ -word 1 -N && -position 3 ]]; then
complist -F
else
complist -b
fi

View file

@ -0,0 +1,9 @@
#defcomp zmodload
if [[ -mword 1 -*(a*u|u*a)* || -mword 1 -*a* && -position 3 -1 ]]; then
complist -B
elif [[ -mword 1 -*u* ]]; then
complist -s '$(zmodload)'
else
complist -s '${^module_path}/*(N:t:r)'
fi

89
Functions/Completion/dump Normal file
View file

@ -0,0 +1,89 @@
# This is a file to be sourced to dump the definitions for new-style
# completion defined by 'init' in the same directory. For best results,
# it should be run immediately after init, before any of the completions
# have been autoloaded. The output should be directed into the "init.dump"
# in the same directory as init. If you rename init, just stick .dump onto
# the end of whatever you have called it and put it in the same directory.
#
# You will need to update the dump every time you add a new completion.
# To do this, simply remove the .dump file, start a new shell, and
# create the .dump file as before.
#
# It relies on KSH_ARRAYS not being set.
# Print the number of files used for completion. This is used in init
# to see if auto-dump should re-dump the dump-file.
_d_file=${COMPDUMP-${0:h}/init.dump}
_d_files=( ${^~fpath}/_*~*~ )
print "#files: $#_d_files" > $_d_file
unset _d_files
# First dump the arrays comps and patcomps. The quoting hieroglyphyics
# ensure that a single quote inside a variable is itself correctly quoted.
print "comps=(" >> $_d_file
for _d_f in ${(k)comps}; do
print -r - "'${_d_f//\'/'\\''}'" "'${comps[$_d_f]//\'/'\\''}'"
done >> $_d_file
print ")" >> $_d_file
if (( $#patcomps )); then
print "\npatcomps=(" >> $_d_file
for _d_f in "$patcomps[@]"; do
print -r - "'${_d_f//\'/'\\''}'"
done >> $_d_file
print ")" >> $_d_file
fi
print >> $_d_file
# Now dump the key bindings. We dump all bindings for zle widgets
# whose names start with a underscore.
# We need both the zle -C's and the bindkey's to recreate.
_d_bks=()
zle -lL |
while read -rA _d_line; do
if [[ ${_d_line[5]} = _* ]]; then
print -r - ${_d_line}
_d_bks=($_d_bks ${_d_line[3]})
fi
done >> $_d_file
bindkey |
while read -rA _d_line; do
if [[ ${_d_line[2]} = (${(j.|.)~_d_bks}) ]]; then
print -r "bindkey '${_d_line[1][2,-2]}' ${_d_line[2]}"
fi
done >> $_d_file
print >> $_d_file
# Autoloads: whence -w produces "_d_foo: function", so look for
# all functions beginning with `_'.
_d_als=($(whence -wm '_*' |
while read -rA _d_line; do
[[ ${_d_line[2]} = function ]] && print -r - ${_d_line[1]%:}
done))
# print them out: about six to a line looks neat
while (( $#_d_als )); do
print -n autoload
for (( _i = 0; _i < 6; _i++ )); do
if (( $#_d_als )); then
print -n " $_d_als[1]"
shift _d_als
fi
done
print
done >> $_d_file
print >> $_d_file
unset _d_line _d_zle _d_bks _d_als _d_f _f_file

View file

@ -3,34 +3,22 @@
# directory that will automatically be made autoloaded (see the end of this # directory that will automatically be made autoloaded (see the end of this
# file). # file).
# The names of the files that will be considered for autoloading have to # The names of the files that will be considered for autoloading have to
# start with two underscores (like `__setopt). # start with a underscores (like `_setopt).
# The first line of these files will be read and has to say what should be # The first line of these files will be read and has to say what should be
# done with its contents: # done with its contents:
# #
# `#function <names ...>' # `#defcomp <names ...>'
# if the first line looks like this, the file is # if the first line looks like this, the file is
# autoloaded as a function and that function will # autoloaded as a function and that function will
# be called to generate the matches when completing # be called to generate the matches when completing
# for one of the commands whose <name> is given # for one of the commands whose <name> is given
# #
# `#array <names ...>' # `#defpatcomp <pattern>'
# with a first line like this, the filename is taken as
# the name of an array; when trying to generate matches
# for the command <name>, the file will be sourced and
# should define this array, the builtin `complist' will
# then be called with the elements of this array as its
# arguments; this is intended for simple definitions
# for which you don't need a shell function
#
# `#pattern-function <pattern>'
# this defines a function that should be called to generate # this defines a function that should be called to generate
# matches for commands whose name matches <pattern>; note # matches for commands whose name matches <pattern>; note
# that only one pattern may be given # that only one pattern may be given
# #
# `#pattern-array <pattern>' # `#defkeycomp <style> [ <key-sequence> ... ]
# like `#pattern-function' but defining an array
#
# `#key-function <style> [ <key-sequence> ... ]
# this is used to bind special completions to all the given # this is used to bind special completions to all the given
# <key-sequence>(s). The <style> is the name of one of the built-in # <key-sequence>(s). The <style> is the name of one of the built-in
# completion widgets (complete-word, delete-char-or-list, # completion widgets (complete-word, delete-char-or-list,
@ -41,45 +29,47 @@
# rather than by the context. The widget has the same name as # rather than by the context. The widget has the same name as
# the autoload file and can be bound using bindkey in the normal way. # the autoload file and can be bound using bindkey in the normal way.
# #
# `#key-array <style> [ <key-sequence> ... ] # `#autoload'
# like `#key-function', but defining an array instead
#
# `#helper'
# this is for helper functions that are not used to # this is for helper functions that are not used to
# generate matches, but should automatically be loaded # generate matches, but should automatically be loaded
# when they are called # when they are called
# #
# Note that no white space is allowed between the `#' and the rest of # Note that no white space is allowed between the `#' and the rest of
# the string. # the string.
#
# See the file `dump' for how to speed up initialiation.
# If we got the `-d'-flag, we will automatically dump the new state (at
# the end).
# An associative array for completions definitions. The keys of the entries if [[ "$1" = -d ]]; then
# are the names of the command, the values are names of functions or variables _i_autodump=1
# that are to be used to generate the matches. else
# Pattern completions will be stored in an normal array named `patcomps'. _i_autodump=0
# Completion definitions bound directly to keys are stored in an assoc array fi
# named `keycomps'.
# The associative array containing the definitions for the commands.
# Definitions for patterns will be stored in the normal array `patcomps'.
typeset -A comps typeset -A comps
typeset -A keycomps
# This may be used to define completion handlers. The first argument is the # This may be used to define completion handlers. The first argument is the
# name of the function or variable containing the definition, the other # name of the function containing the definition, the other arguments are the
# arguments are the command names for which this definition should be used. # command names for which this definition should be used.
# With only one argument the function/variable-name __$1 is used. # With only one argument the function/variable-name _$1 is used.
# If given the `-a' option, the function is defined as being autoloaded. # If given the `-a' option, the function is defined as being autoloaded.
defcomp() { defcomp() {
local name autol='' local name
if [[ "$1" = -a ]]; then if [[ "$1" = -a ]]; then
shift shift
autol=yes autol=yes
fi fi
if [[ $# -eq 1 ]]; then if [[ $# -eq 1 ]]; then
comps[$1]="__$1" comps[$1]="_$1"
[[ -z "$autol" ]] || autoload "__$1" [[ -z "$autol" ]] || autoload "_$1"
else else
name="$1" name="$1"
shift shift
@ -90,10 +80,9 @@ defcomp() {
fi fi
} }
# Almost like `defcomp', but this always gets two arguments: the name of a # Almost like `defcomp', but this always gets two arguments: the name of a
# variable or function describing what should be completed and the pattern # function describing what should be completed and the pattern that will be
# that will be compared to the command names for which completion is attempted. # compared to the command names for which completion is attempted.
defpatcomp() { defpatcomp() {
if [[ "$1" = -a ]]; then if [[ "$1" = -a ]]; then
@ -101,13 +90,12 @@ defpatcomp() {
autoload "$1" autoload "$1"
fi fi
if (( $+patcomps )) then if (( $+patcomps )) then
patcomps=("$patcomps[@]" "$2 $1" ) patcomps=("$patcomps[@]" "$2 $1")
else else
patcomps=( "$2 $1" ) patcomps=("$2 $1")
fi fi
} }
# This is used to define completion handlers directly bound to keys. The # This is used to define completion handlers directly bound to keys. The
# first argument is as for `defcomp', giving the handler. The second # first argument is as for `defcomp', giving the handler. The second
# argument is the name of one of the built-in completion widgets. Any # argument is the name of one of the built-in completion widgets. Any
@ -122,15 +110,10 @@ defkeycomp() {
if [[ "$1" = -a ]]; then if [[ "$1" = -a ]]; then
shift shift
autoload "$1" autoload "$1"
name="$1"
elif [[ "${1[1]}" = ' ' ]]; then
name="${1:t}"
else
name="$1"
fi fi
keycomps[$name]="$1" name="$1"
shift shift
zle -C "$name" "$1" __main_key_complete zle -C "$name" "$1" "$name"
shift shift
while (( $# )); do while (( $# )); do
bindkey "$1" "$name" bindkey "$1" "$name"
@ -138,116 +121,101 @@ defkeycomp() {
done done
} }
# These can be used to easily save and restore the state of the special
# variables used by the completion code.
alias compsave='local _oprefix _oiprefix _oargv _ocurrent; \
_oprefix="$PREFIX"; \
_oiprefix="$IPREFIX"; \
_oargv=( "$@" ); \
_ocurrent="$CURRENT"'
alias compreset='PREFIX="$_oprefix"; \
IPREFIX="$_oiprefix"; \
argv=( "$_oargv[@]" ); \
CURRENT="$_ocur"'
# This is an easy way to get completion for sub-commands.
alias compsub='__normal "$@" || return 1'
# This searches $1 in the array for normal completions and calls the result. # This searches $1 in the array for normal completions and calls the result.
compalso() { _compalso() {
local tmp local tmp
tmp="$comps[$1]" tmp="$comps[$1]"
[[ -z "$tmp" ]] || callcomplete comps "$1" "$@" [[ -z "$tmp" ]] || "$tmp" "$@"
} }
# These can be used to easily save and restore the state of the special
# variables used by the completion code.
# This generates matches. The first argument is the name of one of the alias _compsave='local _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; \
# arrays containing completion definitions. The second argument is the index eval "_oprefix${_level}=\"\$PREFIX\"; \
# into this array. The other arguments are the positional parameters to give _oiprefix${_level}=\"\$IPREFIX\"; \
# to the completion function (containing the arguments from the command line). _oargv${_level}=( \"\$@\" ); \
_ocurrent${_level}=\"\$CURRENT\"; \
_ocommand${_level}=\"\$COMMAND\"; \
_ocontext${_level}=\"\$CONTEXT\""'
alias _compreset='eval "PREFIX=\"\$_oprefix${_level}\"; \
IPREFIX=\"\$_oiprefix${_level}\"; \
argv=( \"\$_oargv${_level}[@]\" ); \
CURRENT=\"\$_ocur${_level}\"; \
COMMAND=\"\$_ocommand${_level}\"; \
CONTEXT=\"\$_ocontext${_level}\""'
callcomplete() { # These can be used to build tests that modify the special parameters
local file def # without having to reset them by hand.
# Get the definition from the array. alias _if='(( $+_level )) || local _level=0; (( _level++ )); _compsave; if'
alias _elif='_compreset; elif'
alias _else='_compreset; else'
alias _fi='_compreset; fi; unset _oprefix$_level _oiprefix$_level _oargv$_level _ocurrent$_level _ocommand$_level _ocontext$_level; (( _level-- ))'
eval "def=\$${1}[${2}]"
# If the definition starts with a space then this means that we should # Now we automatically make the definition files autoloaded.
# source a file to get the definition for an array.
if [[ "$def[1]" = ' ' ]]; then # First we get the name of a dump file if this will be used.
# The definition starts with a space, so source the file and change
# the definition.
file="$def[2,-1]" : ${COMPDUMP:=$0.dump}
builtin . "$file"
def="${file:t}" _i_files=( ${^~fpath}/_*~*~ )
eval "${1}[${2}]=$def" _i_initname=$0
_i_done=''
# If we have a dump file, load it.
if [[ -f "$COMPDUMP" ]]; then
read -rA _i_line < "$COMPDUMP"
if [[ _i_autodump -eq 1 || $_i_line[2] -eq $#_i_files ]]; then
builtin . "$COMPDUMP"
_i_done=yes
fi fi
unset _i_line
fi
if [[ -z "$_i_done" ]]; then
# Get rid of the array-name and -index. for _i_dir in $fpath; do
[[ $_i_dir = . ]] && continue
shift 2 for _i_file in $_i_dir/_*~*~(N); do
if [[ ${(P)+def} -eq 1 ]]; then read -rA _i_line < $_i_file
# It is a parameter name, call complist directly. _i_tag=$_i_line[1]
shift _i_line
complist "${(@P)def}" if [[ $_i_tag = '#defcomp' ]]; then
else defcomp -a ${_i_file:t} "${_i_line[@]}"
# Otherwise it's a function name, call this function. elif [[ $_i_tag = '#defpatcomp' ]]; then
defpatcomp -a "${_i_file:t}" "${_i_line[@]}"
"$def" "$@" elif [[ $_i_tag = '#defkeycomp' ]]; then
fi defkeycomp -a "${_i_file:t}" "${_i_line[@]}"
} elif [[ $_i_tag = '#autoload' ]]; then
autoload ${_i_file:t}
fi
# Now we make the files automatically autoloaded. done
local dir file line func
for dir in $fpath; do
[[ $dir = . ]] && continue
for file in $dir/__*~*~(N); do
read -rA line < $file
func=$line[1]
shift line
if [[ $func = '#function' ]]; then
defcomp -a ${file:t} "${line[@]}"
elif [[ $func = '#array' ]]; then
defcomp " $file" "${line[@]}"
elif [[ $func = '#pattern-function' ]]; then
defpatcomp -a ${file:t} "${line[@]}"
elif [[ $func = '#pattern-array' ]]; then
defcomp " $file" "${line[@]}"
elif [[ $func = '#key-function' ]]; then
defkeycomp -a "${file:t}" "${line[@]}"
elif [[ $func = '#key-array' ]]; then
defkeycomp " $file" "${line[@]}"
elif [[ $func = '#helper' ]]; then
autoload ${file:t}
fi
done done
done
bindkey |
while read -rA _i_line; do
if [[ "$_i_line[2]" = complete-word ||
"$_i_line[2]" = delete-char-or-list ||
"$_i_line[2]" = expand-or-complete ||
"$_i_line[2]" = expand-or-complete-prefix ||
"$_i_line[2]" = list-choices ||
"$_i_line[2]" = menu-complete ||
"$_i_line[2]" = menu-expand-or-complete ||
"$_i_line[2]" = reverse-menu-complete ]]; then
zle -C _complete_$_i_line[2] $_i_line[2] _main_complete
bindkey "${_i_line[1][2,-2]}" _complete_$_i_line[2]
fi
done
# Finally we make all this be called by changing the key bindings. unset _i_dir _i_line _i_file _i_tag
bindkey | while read -A line; do # if autodumping was requested, do it now.
if [[ "$line[2]" = complete-word ||
"$line[2]" = delete-char-or-list || (( _i_autodump )) && builtin . ${_i_initname:h}/dump
"$line[2]" = expand-or-complete || fi
"$line[2]" = expand-or-complete-prefix ||
"$line[2]" = list-choices || unset _i_files _i_initname _i_done _i_autodump
"$line[2]" = menu-complete ||
"$line[2]" = menu-expand-or-complete ||
"$line[2]" = reverse-menu-complete ]]; then
zle -C __complete_$line[2] $line[2] __main_complete
bindkey "${line[1][2,-2]}" __complete_$line[2]
fi
done

View file

@ -164,18 +164,21 @@ alias zfuget='noglob zfuget'
setopt completealiases setopt completealiases
# #
# zftp completions # zftp completions: only use these if new-style completion is not
# active.
# #
compctl -f -x 'p[1]' \ if [[ ${#patcomps} -eq 0 || ${patcomps[(i)zf*]} -gt ${#patcomps} ]]; then
-k '(open params user login type ascii binary mode put putat compctl -f -x 'p[1]' \
get getat append appendat ls dir local remote mkdir rmdir delete -k '(open params user login type ascii binary mode put putat
close quit)' - \ get getat append appendat ls dir local remote mkdir rmdir delete
'w[1,cd][1,ls][1,dir][1,rmdir]' -K zfcd_match -S/ -q - \ close quit)' - \
'W[1,get*]' -K zfget_match - 'w[1,delete][1,remote]' -K zfget_match - \ 'w[1,cd][1,ls][1,dir][1,rmdir]' -K zfcd_match -S/ -q - \
'w[1,open][1,params]' -k hosts -- zftp 'W[1,get*]' -K zfget_match - 'w[1,delete][1,remote]' -K zfget_match - \
compctl -K zfcd_match -S/ -q zfcd zfdir zfls 'w[1,open][1,params]' -k hosts -- zftp
compctl -K zfget_match zfget zfgcp zfuget zfcget compctl -K zfcd_match -S/ -q zfcd zfdir zfls
compctl -k hosts zfopen zfparams compctl -K zfget_match zfget zfgcp zfuget zfcget
compctl -k hosts zfanon zfopen zfparams
fi
function zfanon { function zfanon {
local opt optlist once local opt optlist once
@ -245,6 +248,40 @@ function zfanon {
fi fi
} }
function zfautocheck {
# This function is used to implement auto-open behaviour.
#
# With first argument including n, don't change to the old directory; else do.
#
# Set do_close to 1 if the connection was not previously open, 0 otherwise
# With first arguemnt including d, don't set do_close to 1. Broadly
# speaking, we use this mechanism to shut the connection after use
# if the connection had been explicitly closed (i.e. didn't time out,
# which zftp test investigates) and we are not using a directory
# command, which implies we are looking for something so should stay open
# for it.
# Remember the old session: zflastsession will be overwritten by
# a successful open.
local lastsession=$zflastsession
if [[ -z $ZFTP_HOST ]]; then
zfopen || return 1
[[ $1 = *d* ]] || do_close=1
elif zftp test 2>/dev/null; then
return 0
else
zfopen || return 1
fi
if [[ $1 = *n* ]]; then
return 0
else
zfcd ${lastsession#*:}
fi
}
function zfcd { function zfcd {
# zfcd: change directory on the remote server. # zfcd: change directory on the remote server.
# #
@ -266,9 +303,11 @@ function zfcd {
# second, we can no do 'zfcd $PWD' and the like, and that will # second, we can no do 'zfcd $PWD' and the like, and that will
# work just as long as the directory structures under the home match. # work just as long as the directory structures under the home match.
# Autoopen: if not already open, hope there are parameters set up to if [[ $1 = /* ]]; then
# do so. If not, we get the right error message, so no harm done. zfautocheck -dn
[[ -z $ZFTP_HOST ]] && { zfopen || return 1; } else
zfautocheck -d
fi
if [[ $1 = $HOME || $1 = $HOME/* ]]; then if [[ $1 = $HOME || $1 = $HOME/* ]]; then
1="~${1#$HOME}" 1="~${1#$HOME}"
@ -291,6 +330,7 @@ function zfcd {
local lastdir=$ZFTP_PWD local lastdir=$ZFTP_PWD
zftp cd "$@" && zflastdir=$lastdir zftp cd "$@" && zflastdir=$lastdir
print $zflastsession
} }
function zfcd_match { function zfcd_match {
@ -303,6 +343,8 @@ function zfcd_match {
local ZFTP_VERBOSE=45 local ZFTP_VERBOSE=45
# should we redirect 2>/dev/null or let the user see it? # should we redirect 2>/dev/null or let the user see it?
local tmpf=${TMPPREFIX}zfcm$$
if [[ $ZFTP_SYSTEM = UNIX* ]]; then if [[ $ZFTP_SYSTEM = UNIX* ]]; then
# hoo, aren't we lucky: this makes things so much easier # hoo, aren't we lucky: this makes things so much easier
setopt localoptions rcexpandparam setopt localoptions rcexpandparam
@ -315,8 +357,9 @@ function zfcd_match {
# If we're using -F, we get away with using a directory # If we're using -F, we get away with using a directory
# to list, but not a glob. Don't ask me why. # to list, but not a glob. Don't ask me why.
# I hate having to rely on awk here. # I hate having to rely on awk here.
reply=($(zftp ls -F $dir | zftp ls -F $dir >$tmpf
awk '/\/$/ { print substr($1, 0, length($1)-1) }')) reply=($(awk '/\/$/ { print substr($1, 0, length($1)-1) }' $tmpf))
rm -f $tmpf
if [[ $dir = / ]]; then if [[ $dir = / ]]; then
reply=(${dir}$reply) reply=(${dir}$reply)
elif [[ -n $dir ]]; then elif [[ -n $dir ]]; then
@ -423,6 +466,84 @@ function zfclose {
zftp close zftp close
} }
function zfcput {
# Continuation put of files from remote server.
# For each file, if it's shorter over there, put the remainder from
# over here. This uses append, which is standard, so unlike zfcget it's
# expected to work on any reasonable server... err, as long as it
# supports SIZE and MDTM. (It could be enhanced so you can enter the
# size so far by hand.) You should probably be in binary transfer
# mode, thought it's not enforced.
#
# To read from midway through a local file, `tail +<n>c' is used.
# It would be nice to find a way of doing this which works on all OS's.
setopt localoptions
unsetopt ksharrays shwordsplit
local loc rem stat=0 locst remst offs tailtype
local tmpfile=${TMPPREFIX}zfcget$$ rstat
# find how tail works. this is intensely annoying, since it's completely
# standard in C. od's no use, since we can only skip whole blocks.
if [[ $(echo abcd | tail +2c) = bcd ]]; then
tailtype=c
elif [[ $(echo abcd | tail --bytes=+2) = bcd ]]; then
tailtype=b
else
print "I can't get your \`tail' to start from from arbitrary characters.\n" \
"If you know how to do this, let me know." 2>&1
return 1
fi
for loc in $*; do
# zfcd directory hack to put the front back to ~
rem=$loc
if [[ $rem = $HOME || $rem = $HOME/* ]]; then
rem="~${rem#$HOME}"
fi
if [[ ! -r $loc ]]; then
print "Can't read file $loc"
stat=1
else
# Compare the sizes.
locst=($(zftp local $loc))
zftp remote $rem >$tmpfile
rstat=$?
remst=($(<$tmpfile))
rm -f $tmpfile
if [[ $rstat = 2 ]]; then
print "Server does not support remote status commands.\n" \
"You will have to find out the size by hand and use zftp append." 2>&1
stat=1
continue
elif [[ $rstat = 1 ]]; then
# Not found, so just do a standard put.
zftp put $rem <$loc
elif [[ $remst[1] -gt $locst[1] ]]; then
print "Remote file is larger!" 2>&1
continue;
elif [[ $locst[1] == $remst[1] ]]; then
print "Files are already the same size." 2>&1
continue
else
# tail +<N>c takes the count of the character
# to start from, not the offset from zero. if we did
# this with years, then 2000 would be 1999. no y2k bug!
# brilliant.
(( offs = $remst[1] + 1 ))
if [[ $tailtype = c ]]; then
tail +${offs}c $loc | zftp append $rem || stat=1
else
tail --bytes=+$offs $loc | zftp append $rem || stat=1
fi
fi
fi
done
return $stat
}
function zfdir { function zfdir {
# Long directory of remote server. # Long directory of remote server.
# The remote directory is cached. In fact, two caches are kept: # The remote directory is cached. In fact, two caches are kept:
@ -440,9 +561,11 @@ function zfdir {
# zfdir -f will force the existing cache to be ignored, e.g. if you know # zfdir -f will force the existing cache to be ignored, e.g. if you know
# or suspect the directory has changed. # or suspect the directory has changed.
# zfdir -d will remove both caches without listing anything. # zfdir -d will remove both caches without listing anything.
# If you need to pass -r, -f or -d to the dir itself, use zfdir -- -d etc. # If you need to pass -r, -f or -d to the dir itself, use zfdir -- -d etc.;
# unrecognised options are passed through to dir, but zfdir options must
# appear first and unmixed with the others.
setopt localoptions unset setopt localoptions unset extendedglob
unsetopt shwordsplit ksharrays unsetopt shwordsplit ksharrays
local file opt optlist redir i newargs force local file opt optlist redir i newargs force
@ -451,6 +574,9 @@ function zfdir {
if [[ $1 = - || $1 = -- ]]; then if [[ $1 = - || $1 = -- ]]; then
shift; shift;
break; break;
elif [[ $1 != -[rfd]## ]]; then
# pass options through to ls
break;
fi fi
optlist=${1#-} optlist=${1#-}
for (( i = 1; i <= $#optlist; i++)); do for (( i = 1; i <= $#optlist; i++)); do
@ -465,13 +591,13 @@ function zfdir {
zftp_fcache=() zftp_fcache=()
return 0 return 0
;; ;;
*) print option $opt not recognised >&2
;;
esac esac
done done
shift shift
done done
zfautocheck -d
# directory hack, see zfcd # directory hack, see zfcd
for (( i = 1; i <= $#argv; i++ )); do for (( i = 1; i <= $#argv; i++ )); do
if [[ $argv[$i] = $HOME || $argv[$i] = $HOME/* ]]; then if [[ $argv[$i] = $HOME || $argv[$i] = $HOME/* ]]; then
@ -507,27 +633,38 @@ function zfdir {
if [[ -n $file && -f $file ]]; then if [[ -n $file && -f $file ]]; then
eval ${PAGER:-more} \$file eval ${PAGER:-more} \$file
else else
zftp dir $* | tee $file | eval ${PAGER-:more} if (zftp test); then
# Works OK in subshells
zftp dir $* | tee $file | eval ${PAGER-:more}
else
# Doesn't work in subshells (IRIX 6.2 --- why?)
zftp dir $* >$file
eval ${PAGER-:more} >$file
fi
fi fi
} }
function zfgcp { function zfgcp {
# ZFTP get as copy: i.e. first arguments are remote, last is local. # ZFTP get as copy: i.e. first arguments are remote, last is local.
# Supposed to work exactly like a normal copy otherwise, i.e. # Supposed to work exactly like a normal copy otherwise, i.e.
# zfcp rfile lfile # zfgcp rfile lfile
# or # or
# zfcp rfile1 rfile2 rfile3 ... ldir # zfgcp rfile1 rfile2 rfile3 ... ldir
# Options: # Options:
# -G don't to remote globbing, else do # -G don't to remote globbing, else do
# -t update the local file times to the same time as the remote. # -t update the local file times to the same time as the remote.
# Currently this only works if you have the `perl' command, # Currently this only works if you have the `perl' command,
# and that perl is version 5 with the standard library. # and that perl is version 5 with the standard library.
# See the function zfrtime for more gory details. # See the function zfrtime for more gory details.
#
# If there is no current connection, try to use the existing set of open
# parameters to establish one and close it immediately afterwards.
setopt localoptions setopt localoptions
unsetopt shwordsplit unsetopt shwordsplit
local opt optlist nglob remlist rem loc stat=0 time local opt optlist nglob remlist rem loc time
integer stat do_close
while [[ $1 == -* ]]; do while [[ $1 == -* ]]; do
if [[ $1 == - || $1 == -- ]]; then if [[ $1 == - || $1 == -- ]]; then
@ -549,6 +686,8 @@ function zfgcp {
shift shift
done done
zfautocheck
# hmm, we should really check this after expanding the glob, # hmm, we should really check this after expanding the glob,
# but we shouldn't expand the last argument remotely anyway. # but we shouldn't expand the last argument remotely anyway.
if [[ $# -gt 2 && ! -d $argv[-1] ]]; then if [[ $# -gt 2 && ! -d $argv[-1] ]]; then
@ -584,6 +723,9 @@ function zfgcp {
else else
zftp get $1 >$2 || stat=$? zftp get $1 >$2 || stat=$?
fi fi
(( $do_close )) && zfclose
return $stat return $stat
} }
@ -594,8 +736,14 @@ function zfget {
# Currently this only works if you have the `perl' command, # Currently this only works if you have the `perl' command,
# and that perl is version 5 with the standard library. # and that perl is version 5 with the standard library.
# See the function zfrtime for more gory details. # See the function zfrtime for more gory details.
#
# If the connection is not currently open, try to open it with the current
# parameters (set by a previous zfopen or zfparams), then close it after
# use. The file is put in the current directory (i.e. using the basename
# of the remote file only); for more control, use zfgcp.
local loc rem stat=0 optlist opt nglob remlist time local loc rem optlist opt nglob remlist time
integer stat do_close
while [[ $1 == -* ]]; do while [[ $1 == -* ]]; do
if [[ $1 == - || $1 == -- ]]; then if [[ $1 == - || $1 == -- ]]; then
@ -617,6 +765,8 @@ function zfget {
shift shift
done done
zfautocheck
for remlist in $*; do for remlist in $*; do
# zfcd directory hack to put the front back to ~ # zfcd directory hack to put the front back to ~
if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then
@ -637,6 +787,8 @@ function zfget {
fi fi
done done
(( $do_close )) && zfclose
return $stat return $stat
} }
@ -646,15 +798,20 @@ function zfget_match {
1="~${1#$HOME}" 1="~${1#$HOME}"
fi fi
local tmpf=${TMPPREFIX}zfgm$$
if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then if [[ $ZFTP_SYSTEM == UNIX* && $1 == */* ]]; then
# On the first argument to ls, we usually get away with a glob. # On the first argument to ls, we usually get away with a glob.
reply=($(zftp ls "$1*$2")) zftp ls "$1*$2" >$tmpf
reply=($(<$tmpf))
rm -f $tmpf
else else
if (( $#zftp_fcache == 0 )); then if (( $#zftp_fcache == 0 )); then
# Always cache the current directory and use it # Always cache the current directory and use it
# even if the system is UNIX. # even if the system is UNIX.
zftp_fcache=($(zftp ls)) zftp ls >$tmpf
zftp_fcache=($(<$tmpf))
rm -f $tmpf
fi fi
reply=($zftp_fcache); reply=($zftp_fcache);
fi fi
@ -671,6 +828,9 @@ function zfls {
if [[ $1 = $HOME || $1 = $HOME/* ]]; then if [[ $1 = $HOME || $1 = $HOME/* ]]; then
1="~${1#$HOME}" 1="~${1#$HOME}"
fi fi
zfautocheck -d
zftp ls $* zftp ls $*
} }
@ -725,15 +885,62 @@ function zfparams {
zftp params $* zftp params $*
} }
function zfpcp {
# ZFTP put as copy: i.e. first arguments are remote, last is local.
# Currently only supports
# zfcp lfile rfile
# if and only if there are two arguments
# or
# zfcp lfile1 lfile2 lfile3 ... rdir
# if and only if there are more than two (because otherwise it doesn't
# know if the last argument is a directory on the remote machine).
# argument.
setopt localoptions
unsetopt shwordsplit
local rem loc
integer stat do_close
zfautocheck
if (( $# > 2 )); then
local dir=$argv[-1]
argv[-1]=
# zfcd directory hack to put the front back to ~
if [[ $dir = $HOME || $dir = $HOME/* ]]; then
dir="~${dir#$HOME}"
fi
for loc in $*; do
rem=$dir/${loc:t}
zftp put $rem <$loc || stat=1
done
else
zftp put $2 <$1 || stat=$?
fi
(( $do_close )) && zfclose
return $stat
}
function zfput { function zfput {
# Simple put: dump every file under the same name, but stripping # Simple put: dump every file under the same name, but stripping
# off any directory parts. # off any directory parts.
local loc rem stat=0
local loc rem
integer stat do_close
zfautocheck
for loc in $*; do for loc in $*; do
rem=${loc:t} rem=${loc:t}
zftp put $rem <$loc zftp put $rem <$loc
[[ $? == 0 ]] || stat=$? [[ $? == 0 ]] || stat=$?
done done
(( $do_close )) && zfclose
return $stat return $stat
} }
@ -764,13 +971,16 @@ function zfrglob {
# globbing characters, and if extendedglob is set and we are # globbing characters, and if extendedglob is set and we are
# using zsh for the actual pattern matching also look for # using zsh for the actual pattern matching also look for
# extendedglob characters. # extendedglob characters.
if [[ $remlist != *[][*?]* && if [[ $pat != *[][*?]* &&
( -n $zfrglob || ! -o extendedglob || $remlist != *[(|)~#^]* ) ]]; then ( -n $zfrglob || ! -o extendedglob || $pat != *[(|)#^]* ) ]]; then
return 0 return 0
fi fi
local tmpf={$TMPPREFIX}zfrglob$$
if [[ $zfrglob != '' ]]; then if [[ $zfrglob != '' ]]; then
eval "$1=(\$(zftp ls \"$pat\" 2>/dev/null))" zftp ls "$pat" >$tmpf 2>/dev/null
eval "$1=(\$(<\$tmpf))"
rm -f $tmpf
else else
if [[ $ZFTP_SYSTEM = UNIX* && $pat = */* ]]; then if [[ $ZFTP_SYSTEM = UNIX* && $pat = */* ]]; then
# not the current directory and we know how to handle paths # not the current directory and we know how to handle paths
@ -781,12 +991,18 @@ function zfrglob {
dir=/ dir=/
fi fi
nondir=${pat##*/} nondir=${pat##*/}
files=($(zftp ls "$dir" 2>/dev/null)) zftp ls "$dir" 2>/dev/null >$tmpf
files=($(<$tmpf))
files=(${files:t})
rm -f $tmpf
else else
# we just have to do an ls and hope that's right # we just have to do an ls and hope that's right
nondir=$pat nondir=$pat
if (( $#zftp_fcache == 0 )); then if (( $#zftp_fcache == 0 )); then
zftp_fcache=($(zftp ls)) # Why does `zftp_fcache=($(zftp ls))' sometimes not work?
zftp ls >$tmpf
zftp_fcache=($(<$tmpf))
rm -f $tmpf
fi fi
files=($zftp_fcache) files=($zftp_fcache)
fi fi
@ -848,7 +1064,7 @@ function zfrtime {
function zfstat { function zfstat {
# Give a zftp status report using local variables. # Give a zftp status report using local variables.
# With option -v, connect the remote host and ask it what it # With option -v, connect to the remote host and ask it what it
# thinks the status is. # thinks the status is.
setopt localoptions unset setopt localoptions unset
@ -874,10 +1090,6 @@ function zfstat {
shift shift
done done
# hack: in case the status from a subshell process hasn't been
# fixed yet
zftp type >&/dev/null
if [[ -n $ZFTP_HOST ]]; then if [[ -n $ZFTP_HOST ]]; then
print "Host:\t\t$ZFTP_HOST" print "Host:\t\t$ZFTP_HOST"
print "IP:\t\t$ZFTP_IP" print "IP:\t\t$ZFTP_IP"
@ -907,12 +1119,14 @@ function zfstat {
fi fi
else else
print "Not connected." print "Not connected."
[[ -n $zflastsession ]] && print "Last session:\t$zflastsession"
stat=1 stat=1
fi fi
# things which may be set even if not connected: # things which may be set even if not connected:
[[ -n $ZFTP_REPLY ]] && print "Last reply:\t$ZFTP_REPLY" [[ -n $ZFTP_REPLY ]] && print "Last reply:\t$ZFTP_REPLY"
print "Verbosity:\t$ZFTP_VERBOSE" print "Verbosity:\t$ZFTP_VERBOSE"
print "Timeout:\t$ZFTP_TMOUT"
print -n "Preferences:\t" print -n "Preferences:\t"
for (( i = 1; i <= ${#ZFTP_PREFS}; i++ )); do for (( i = 1; i <= ${#ZFTP_PREFS}; i++ )); do
case $ZFTP_PREFS[$i] in case $ZFTP_PREFS[$i] in
@ -928,6 +1142,7 @@ function zfstat {
print print
if [[ -n $ZFTP_HOST && $verbose = 1 ]]; then if [[ -n $ZFTP_HOST && $verbose = 1 ]]; then
zfautocheck -d
print "Status of remote server:" print "Status of remote server:"
# make sure we print the reply # make sure we print the reply
local ZFTP_VERBOSE=045 local ZFTP_VERBOSE=045
@ -939,8 +1154,6 @@ function zfstat {
function zftp_chpwd { function zftp_chpwd {
# You may want to alter chpwd to call this when $ZFTP_USER is set. # You may want to alter chpwd to call this when $ZFTP_USER is set.
# If so, call it with a non-zero first argument so it doesn't
# print the new FTP directory.
# Cancel the filename cache for the current directory. # Cancel the filename cache for the current directory.
zftp_fcache=() zftp_fcache=()
@ -948,26 +1161,26 @@ function zftp_chpwd {
# As this function is called when we close the connection, this # As this function is called when we close the connection, this
# is the only place we need to do these two things. # is the only place we need to do these two things.
[[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir [[ -n $zfcurdir && -f $zfcurdir ]] && rm -f $zfcurdir
zfotherargs=
if [[ -z $ZFTP_USER ]]; then if [[ -z $ZFTP_USER ]]; then
# last call, after an FTP logout # last call, after an FTP logout
# delete the non-current cached directory # delete the non-current cached directory
[[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir [[ -n $zfotherdir && -f $zfotherdir ]] && rm -f $zfotherdir
zfotherargs=
# don't keep zflastdir between opens # don't keep zflastdir between opens (do keep zflastsession)
zflastdir= zflastdir=
# return the display to standard # return the display to standard
# uncomment the following line if you have a chpwd which shows directories # uncomment the following line if you have a chpwd which shows directories
# chpwd chpwd
else else
[[ -z $zflastdir ]] && zflastdir=$ZFTP_PWD [[ -n $ZFTP_PWD ]] && zflastdir=$ZFTP_PWD
zflastsession="$ZFTP_HOST:$ZFTP_PWD"
local args local args
if [[ -t 1 && -t 2 ]]; then if [[ -t 1 && -t 2 ]]; then
local str="$ZFTP_HOST:$ZFTP_PWD" local str=$zflastsession
[[ -z $1 ]] && print $str
[[ ${#str} -lt 70 ]] && str="%m: %~ $str" [[ ${#str} -lt 70 ]] && str="%m: %~ $str"
case $TERM in case $TERM in
sun-cmd) print -n -P "\033]l$str\033\\" sun-cmd) print -n -P "\033]l$str\033\\"
@ -999,10 +1212,14 @@ function zftp_progress {
} }
function zftype { function zftype {
local type local type zftmp=${TMPPREFIX}zftype$$
zfautocheck -d
if (( $# == 0 )); then if (( $# == 0 )); then
type=$(zftp type) zftp type >$zftmp
type=$(<$zftmp)
rm -f $zftmp
if [[ $type = I ]]; then if [[ $type = I ]]; then
print "Current type is image (binary)" print "Current type is image (binary)"
return 0 return 0
@ -1054,8 +1271,9 @@ function zfuget {
setopt localoptions setopt localoptions
unsetopt ksharrays shwordsplit unsetopt ksharrays shwordsplit
local loc rem stat=0 locstats remstats doit tmpfile=${TMPPREFIX}zfuget$$ local loc rem locstats remstats doit tmpfile=${TMPPREFIX}zfuget$$
local rstat remlist verbose optlist opt bad i silent nglob time local rstat remlist verbose optlist opt bad i silent nglob time
integer stat do_close
zfuget_print_time() { zfuget_print_time() {
local tim=$1 local tim=$1
@ -1097,6 +1315,8 @@ function zfuget {
[[ -n $bad ]] && return 1 [[ -n $bad ]] && return 1
zfautocheck
for remlist in $*; do for remlist in $*; do
# zfcd directory hack to put the front back to ~ # zfcd directory hack to put the front back to ~
if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then if [[ $remlist == $HOME || $remlist == $HOME/* ]]; then
@ -1166,6 +1386,9 @@ function zfuget {
done done
fi fi
done done
(( do_close )) && zfclose
return $stat return $stat
} }
@ -1183,8 +1406,9 @@ function zfuput {
setopt localoptions setopt localoptions
unsetopt ksharrays shwordsplit unsetopt ksharrays shwordsplit
local loc rem stat=0 locstats remstats doit tmpfile=${TMPPREFIX}zfuput$$ local loc rem locstats remstats doit tmpfile=${TMPPREFIX}zfuput$$
local rstat verbose optlist opt bad i silent local rstat verbose optlist opt bad i silent
integer stat do_close
zfuput_print_time() { zfuput_print_time() {
local tim=$1 local tim=$1
@ -1222,6 +1446,8 @@ function zfuput {
[[ -n $bad ]] && return 1 [[ -n $bad ]] && return 1
zfautocheck
if [[ $ZFTP_VERBOSE = *5* ]]; then if [[ $ZFTP_VERBOSE = *5* ]]; then
# should we turn it off locally? # should we turn it off locally?
print "Messages with code 550 are harmless." >&2 print "Messages with code 550 are harmless." >&2
@ -1277,5 +1503,8 @@ function zfuput {
zftp put $rem <$loc || stat=$? zftp put $rem <$loc || stat=$?
fi fi
done done
(( do_close )) && zfclose
return $stat return $stat
} }

View file

@ -554,7 +554,7 @@ zfgetline(char *ln, int lnsize, int tmout)
if (setjmp(zfalrmbuf)) { if (setjmp(zfalrmbuf)) {
alarm(0); alarm(0);
zwarnnam("zftp", "timeout getting response", NULL, 0); zwarnnam("zftp", "timeout getting response", NULL, 0);
return 5; return 6;
} }
zfalarm(tmout); zfalarm(tmout);
@ -676,7 +676,7 @@ zfgetmsg()
int stopit, printing = 0, tmout; int stopit, printing = 0, tmout;
if (zcfd == -1) if (zcfd == -1)
return 5; return 6;
if (!(verbose = getsparam("ZFTP_VERBOSE"))) if (!(verbose = getsparam("ZFTP_VERBOSE")))
verbose = ""; verbose = "";
zsfree(lastmsg); zsfree(lastmsg);
@ -763,7 +763,7 @@ zfgetmsg()
zfclose(); zfclose();
/* unexpected, so tell user */ /* unexpected, so tell user */
zwarnnam("zftp", "remote server has closed connection", NULL, 0); zwarnnam("zftp", "remote server has closed connection", NULL, 0);
return 6; /* pretend it failed, because it did */ return 6;
} }
if (lastcode == 530) { if (lastcode == 530) {
/* user not logged in */ /* user not logged in */
@ -802,20 +802,21 @@ zfsendcmd(char *cmd)
int ret, tmout; int ret, tmout;
if (zcfd == -1) if (zcfd == -1)
return 5; return 6;
tmout = getiparam("ZFTP_TMOUT"); tmout = getiparam("ZFTP_TMOUT");
if (setjmp(zfalrmbuf)) { if (setjmp(zfalrmbuf)) {
alarm(0); alarm(0);
zwarnnam("zftp", "timeout sending message", NULL, 0); zwarnnam("zftp", "timeout sending message", NULL, 0);
return 5; return 6;
} }
zfalarm(tmout); zfalarm(tmout);
ret = write(zcfd, cmd, strlen(cmd)); ret = write(zcfd, cmd, strlen(cmd));
alarm(0); alarm(0);
if (ret <= 0) { if (ret <= 0) {
zwarnnam("zftp send", "failed sending control message", NULL, 0); zwarnnam("zftp send", "failure sending control message: %e",
return 5; /* FTP status code */ NULL, errno);
return 6;
} }
return zfgetmsg(); return zfgetmsg();
@ -1023,11 +1024,11 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize)
/* accept the connection */ /* accept the connection */
len = sizeof(zdsock); len = sizeof(zdsock);
newfd = zfmovefd(accept(zdfd, (struct sockaddr *)&zdsock, &len)); newfd = zfmovefd(accept(zdfd, (struct sockaddr *)&zdsock, &len));
if (newfd < 0)
zwarnnam(name, "unable to accept data: %e", NULL, errno);
zfclosedata(); zfclosedata();
if (newfd < 0) { if (newfd < 0)
zwarnnam(name, "unable to accept data.", NULL, 0);
return 1; return 1;
}
zdfd = newfd; /* this is now the actual data fd */ zdfd = newfd; /* this is now the actual data fd */
} else { } else {
/* /*
@ -1270,7 +1271,7 @@ zfread_block(int fd, char *bf, size_t sz, int tmout)
n = zfread(fd, (char *)&hdr, sizeof(hdr), tmout); n = zfread(fd, (char *)&hdr, sizeof(hdr), tmout);
} while (n < 0 && errno == EINTR); } while (n < 0 && errno == EINTR);
if (n != 3 && !zfdrrrring) { if (n != 3 && !zfdrrrring) {
zwarnnam("zftp", "failed to read FTP block header", NULL, 0); zwarnnam("zftp", "failure reading FTP block header", NULL, 0);
return n; return n;
} }
/* size is stored in network byte order */ /* size is stored in network byte order */
@ -1324,7 +1325,7 @@ zfwrite_block(int fd, char *bf, size_t sz, int tmout)
n = zfwrite(fd, (char *)&hdr, sizeof(hdr), tmout); n = zfwrite(fd, (char *)&hdr, sizeof(hdr), tmout);
} while (n < 0 && errno == EINTR); } while (n < 0 && errno == EINTR);
if (n != 3 && !zfdrrrring) { if (n != 3 && !zfdrrrring) {
zwarnnam("zftp", "failed to write FTP block header", NULL, 0); zwarnnam("zftp", "failure writing FTP block header", NULL, 0);
return n; return n;
} }
bfptr = bf; bfptr = bf;

View file

@ -261,15 +261,19 @@ struct cline {
int llen; /* length of line */ int llen; /* length of line */
char *word; /* prefered string to insert */ char *word; /* prefered string to insert */
int wlen; /* length of word */ int wlen; /* length of word */
Cmatcher matcher; /* which matcher was used */
int flags; /* see CLF_* below */ int flags; /* see CLF_* below */
Cline prefix; /* prefix we've build for new parts */
Cline suffix; /* suffix we've build for new parts */
}; };
#define CLF_END 1 #define CLF_END 1
#define CLF_MID 2 #define CLF_MID 2
#define CLF_MISS 4 #define CLF_MISS 4
#define CLF_DIFF 8 #define CLF_DIFF 8
#define CLF_SUF 16 #define CLF_SUF 16
#define CLF_NEW 32
#define CLF_VAR 64
#define CLF_JOIN 128
/* Flags for makecomplist*(). Things not to do. */ /* Flags for makecomplist*(). Things not to do. */

View file

@ -1685,6 +1685,10 @@ bin_compadd(char *name, char **argv, char *ops, int func)
return 1; return 1;
} }
for (; *argv && **argv == '-'; argv++) { for (; *argv && **argv == '-'; argv++) {
if (!(*argv)[1]) {
argv++;
break;
}
for (p = *argv + 1; *p; p++) { for (p = *argv + 1; *p; p++) {
sp = NULL; sp = NULL;
dm = 0; dm = 0;
@ -1945,9 +1949,9 @@ restrict_range(int b, int e)
pparams = p; pparams = p;
zsfree(compcontext); zsfree(compcontext);
if ((compcurrent -= b + 1)) if ((compcurrent -= b + 1))
compcontext = ztrdup("arg"); compcontext = ztrdup("argument");
else else
compcontext = ztrdup("cmd"); compcontext = ztrdup("command");
} }
/**/ /**/

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,13 @@
#include "zsh.mdh" #include "zsh.mdh"
#include "cond.pro" #include "cond.pro"
int tracingcond;
static char *condstr[COND_MOD] = {
"!", "&&", "||", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
"-ne", "-lt", "-gt", "-le", "-ge"
};
/**/ /**/
int int
evalcond(Cond c) evalcond(Cond c)
@ -38,11 +45,23 @@ evalcond(Cond c)
switch (c->type) { switch (c->type) {
case COND_NOT: case COND_NOT:
if (tracingcond)
fprintf(stderr, " %s", condstr[c->type]);
return !evalcond(c->left); return !evalcond(c->left);
case COND_AND: case COND_AND:
return evalcond(c->left) && evalcond(c->right); if (evalcond(c->left)) {
if (tracingcond)
fprintf(stderr, " %s", condstr[c->type]);
return evalcond(c->right);
} else
return 0;
case COND_OR: case COND_OR:
return evalcond(c->left) || evalcond(c->right); if (!evalcond(c->left)) {
if (tracingcond)
fprintf(stderr, " %s", condstr[c->type]);
return evalcond(c->right);
} else
return 1;
case COND_MOD: case COND_MOD:
case COND_MODI: case COND_MODI:
{ {
@ -58,6 +77,9 @@ evalcond(Cond c)
return 0; return 0;
} }
} }
if (tracingcond)
tracemodcond((char *)c->left, (char **)c->right,
c->type == COND_MODI);
return cd->handler((char **) c->right, cd->condid); return cd->handler((char **) c->right, cd->condid);
} }
else { else {
@ -71,6 +93,8 @@ evalcond(Cond c)
zerr("unrecognized condition: `%s'", (char *) c->left, 0); zerr("unrecognized condition: `%s'", (char *) c->left, 0);
return 0; return 0;
} }
if (tracingcond)
tracemodcond((char *)c->left, a, c->type == COND_MODI);
a[0] = (char *) c->left; a[0] = (char *) c->left;
return cd->handler(a, cd->condid); return cd->handler(a, cd->condid);
} else } else
@ -86,6 +110,20 @@ evalcond(Cond c)
if (c->type != COND_STREQ && c->type != COND_STRNEQ) if (c->type != COND_STREQ && c->type != COND_STRNEQ)
untokenize(c->right); untokenize(c->right);
} }
if (tracingcond) {
if (c->type < COND_MOD) {
char *rt = (char *)c->right;
if (c->type == COND_STREQ || c->type == COND_STRNEQ) {
rt = dupstring(rt);
untokenize(rt);
}
fprintf(stderr, " %s %s %s", (char *)c->left, condstr[c->type],
rt);
} else
fprintf(stderr, " -%c %s", c->type, (char *)c->left);
}
switch (c->type) { switch (c->type) {
case COND_STREQ: case COND_STREQ:
return matchpat(c->left, c->right); return matchpat(c->left, c->right);
@ -294,3 +332,21 @@ cond_match(char **args, int num, char *str)
return matchpat(str, s); return matchpat(str, s);
} }
/**/
static void
tracemodcond(char *name, char **args, int inf)
{
char **aptr;
MUSTUSEHEAP("tracemodcond");
args = duparray(args, (VFunc) dupstring);
for (aptr = args; *aptr; aptr++)
untokenize(*aptr);
if (inf) {
fprintf(stderr, " %s %s %s", args[0], name, args[1]);
} else {
fprintf(stderr, " %s", name);
while (*args)
fprintf(stderr, " %s", *args++);
}
}

View file

@ -1208,7 +1208,7 @@ addvars(LinkList l, int export)
addlinknode(vl, v->str); addlinknode(vl, v->str);
} else } else
vl = v->arr; vl = v->arr;
prefork(vl, v->type == PM_SCALAR ? 7 : 3); prefork(vl, v->type == PM_SCALAR ? (PF_SINGLE|PF_ASSIGN) : PF_ASSIGN);
if (errflag) if (errflag)
return; return;
if (isset(GLOBASSIGN) || v->type != PM_SCALAR) if (isset(GLOBASSIGN) || v->type != PM_SCALAR)
@ -1356,7 +1356,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
} }
/* Do prefork substitutions */ /* Do prefork substitutions */
prefork(args, assign ? 2 : isset(MAGICEQUALSUBST)); prefork(args, (assign || isset(MAGICEQUALSUBST)) ? PF_TYPESET : 0);
if (type == SIMPLE) { if (type == SIMPLE) {
int unglobbed = 0; int unglobbed = 0;
@ -2519,13 +2519,26 @@ spawnpipes(LinkList l)
} }
} }
extern int tracingcond;
/* evaluate a [[ ... ]] */ /* evaluate a [[ ... ]] */
/**/ /**/
static int static int
execcond(Cmd cmd) execcond(Cmd cmd)
{ {
return !evalcond(cmd->u.cond); int stat;
if (isset(XTRACE)) {
fprintf(stderr, "%s[[", prompt4 ? prompt4 : "");
tracingcond++;
}
stat = !evalcond(cmd->u.cond);
if (isset(XTRACE)) {
fprintf(stderr, " ]]\n");
fflush(stderr);
tracingcond--;
}
return stat;
} }
/* evaluate a ((...)) arithmetic command */ /* evaluate a ((...)) arithmetic command */
@ -2537,8 +2550,17 @@ execarith(Cmd cmd)
char *e; char *e;
long val = 0; long val = 0;
while ((e = (char *) ugetnode(cmd->args))) if (isset(XTRACE))
fprintf(stderr, "%s((", prompt4 ? prompt4 : "");
while ((e = (char *) ugetnode(cmd->args))) {
if (isset(XTRACE))
fprintf(stderr, " %s", e);
val = matheval(e); val = matheval(e);
}
if (isset(XTRACE)) {
fprintf(stderr, " ))\n", stderr);
fflush(stderr);
}
errflag = 0; errflag = 0;
return !val; return !val;
} }
@ -2613,6 +2635,18 @@ execshfunc(Cmd cmd, Shfunc shf)
deletejob(jobtab + thisjob); deletejob(jobtab + thisjob);
} }
if (isset(XTRACE)) {
LinkNode lptr;
fprintf(stderr, "%s", prompt4 ? prompt4 : prompt4);
for (lptr = firstnode(cmd->args); lptr; incnode(lptr)) {
if (lptr != firstnode(cmd->args))
fputc(' ', stderr);
fprintf(stderr, "%s", (char *)getdata(lptr));
}
fputc('\n', stderr);
fflush(stderr);
}
doshfunc(shf->nam, shf->funcdef, cmd->args, shf->flags, 0); doshfunc(shf->nam, shf->funcdef, cmd->args, shf->flags, 0);
if (!list_pipe) if (!list_pipe)

View file

@ -1810,7 +1810,7 @@ xpandredir(struct redir *fn, LinkList tab)
fake = newlinklist(); fake = newlinklist();
addlinknode(fake, fn->name); addlinknode(fake, fn->name);
/* ...which undergoes all the usual shell expansions */ /* ...which undergoes all the usual shell expansions */
prefork(fake, isset(MULTIOS) ? 0 : 4); prefork(fake, isset(MULTIOS) ? 0 : PF_SINGLE);
/* Globbing is only done for multios. */ /* Globbing is only done for multios. */
if (!errflag && isset(MULTIOS)) if (!errflag && isset(MULTIOS))
globlist(fake); globlist(fake);

View file

@ -568,8 +568,10 @@ createparam(char *name, int flags)
if (isset(ALLEXPORT) && !oldpm) if (isset(ALLEXPORT) && !oldpm)
flags |= PM_EXPORTED; flags |= PM_EXPORTED;
} else } else {
pm = (Param) alloc(sizeof *pm); pm = (Param) alloc(sizeof *pm);
pm->nam = nulstring;
}
pm->flags = flags; pm->flags = flags;
if(!(pm->flags & PM_SPECIAL)) if(!(pm->flags & PM_SPECIAL))
@ -1835,6 +1837,12 @@ arrhashsetfn(Param pm, char **val)
while (*aptr) { while (*aptr) {
/* The parameter name is ztrdup'd... */ /* The parameter name is ztrdup'd... */
v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET); v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
/*
* createparam() doesn't return anything if the parameter
* already existed.
*/
if (!v->pm)
v->pm = (Param) paramtab->getnode(paramtab, *aptr);
zsfree(*aptr++); zsfree(*aptr++);
/* ...but we can use the value without copying. */ /* ...but we can use the value without copying. */
setstrvalue(v, *aptr++); setstrvalue(v, *aptr++);

View file

@ -42,11 +42,7 @@ char nulstring[] = {Nularg, '\0'};
* - Brace expansion * - Brace expansion
* - Tilde and equals substitution * - Tilde and equals substitution
* *
* Bits 0 and 1 of flags are used in filesub. * PF_* flags are defined in zsh.h
* bit 0 is set when we are doing MAGIC_EQUALSUBST or normal
* assignment but not a typeset.
* bit 1 is set on a real assignment (both typeset and normal).
* bit 2 is a flag to paramsubst (single word sub)
*/ */
/**/ /**/
@ -70,20 +66,22 @@ prefork(LinkList list, int flags)
return; return;
} else { } else {
if (isset(SHFILEEXPANSION)) if (isset(SHFILEEXPANSION))
filesub((char **)getaddrdata(node), flags & 3); filesub((char **)getaddrdata(node),
if (!(node = stringsubst(list, node, flags & 4))) flags & (PF_TYPESET|PF_ASSIGN));
if (!(node = stringsubst(list, node, flags & PF_SINGLE)))
return; return;
} }
} }
for (node = firstnode(list); node; incnode(node)) { for (node = firstnode(list); node; incnode(node)) {
if (*(char *)getdata(node)) { if (*(char *)getdata(node)) {
remnulargs(getdata(node)); remnulargs(getdata(node));
if (unset(IGNOREBRACES) && !(flags & 4)) if (unset(IGNOREBRACES) && !(flags & PF_SINGLE))
while (hasbraces(getdata(node))) while (hasbraces(getdata(node)))
xpandbraces(list, &node); xpandbraces(list, &node);
if (unset(SHFILEEXPANSION)) if (unset(SHFILEEXPANSION))
filesub((char **)getaddrdata(node), flags & 3); filesub((char **)getaddrdata(node),
} else if (!(flags & 4)) flags & (PF_TYPESET|PF_ASSIGN));
} else if (!(flags & PF_SINGLE))
uremnode(list, node); uremnode(list, node);
if (errflag) if (errflag)
return; return;
@ -234,7 +232,7 @@ singsub(char **s)
foo = newlinklist(); foo = newlinklist();
addlinknode(foo, *s); addlinknode(foo, *s);
prefork(foo, 4); prefork(foo, PF_SINGLE);
if (errflag) if (errflag)
return; return;
*s = (char *) ugetnode(foo); *s = (char *) ugetnode(foo);
@ -287,8 +285,10 @@ multsub(char **s, char ***a, int *isarr, char *sep)
return !l; return !l;
} }
/* ~, = subs: assign = 2 => typeset; assign = 1 => something that looks /*
like an assignment but may not be; assign = 3 => normal assignment */ * ~, = subs: assign & PF_TYPESET => typeset or magic equals
* assign & PF_ASSIGN => normal assignment
*/
/**/ /**/
void void
@ -302,12 +302,8 @@ filesub(char **namptr, int assign)
if (!assign) if (!assign)
return; return;
if (assign < 3) { if (assign & PF_TYPESET) {
if ((*namptr)[1] && (sub = strchr(*namptr + 1, Equals))) { if ((*namptr)[1] && (sub = strchr(*namptr + 1, Equals))) {
if (assign == 1)
for (ptr = *namptr; ptr != sub; ptr++)
if (!iident(*ptr) && !INULL(*ptr))
return;
str = sub + 1; str = sub + 1;
if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) { if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) {
sub[1] = '\0'; sub[1] = '\0';

View file

@ -2261,7 +2261,7 @@ duplist(LinkList l, VFunc func)
} }
/**/ /**/
static char ** char **
duparray(char **arr, VFunc func) duparray(char **arr, VFunc func)
{ {
char **ret, **rr; char **ret, **rr;

View file

@ -950,6 +950,11 @@ struct param {
#define SUB_ALL 0x0100 /* match complete string */ #define SUB_ALL 0x0100 /* match complete string */
#define SUB_GLOBAL 0x0200 /* global substitution ${..//all/these} */ #define SUB_GLOBAL 0x0200 /* global substitution ${..//all/these} */
/* Flags as the second argument to prefork */
#define PF_TYPESET 0x01 /* argument handled like typeset foo=bar */
#define PF_ASSIGN 0x02 /* argument handled like the RHS of foo=bar */
#define PF_SINGLE 0x04 /* single word substitution */
/* node for named directory hash table (nameddirtab) */ /* node for named directory hash table (nameddirtab) */
struct nameddir { struct nameddir {

3
config.guess vendored
View file

@ -526,6 +526,9 @@ EOF
RM*:SINIX-*:*:*) RM*:SINIX-*:*:*)
echo mips-sni-sysv4 echo mips-sni-sysv4
exit 0 ;; exit 0 ;;
RM*:ReliantUNIX-*:*:*)
echo mips-sni-sysv4
exit 0 ;;
*:SINIX-*:*:*) *:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null` UNAME_MACHINE=`(uname -p) 2>/dev/null`

View file

@ -1036,7 +1036,7 @@ char *argv[];
# #
sni_cc_version=`$CC -V 2>&1 | head -1` sni_cc_version=`$CC -V 2>&1 | head -1`
case "$sni_cc_version" in case "$sni_cc_version" in
CDS* ) *CDS* )
EXTRA_LDFLAGS="${EXTRA_LDFLAGS=-Wl,-Blargedynsym}" EXTRA_LDFLAGS="${EXTRA_LDFLAGS=-Wl,-Blargedynsym}"
;; ;;
* ) * )

View file

@ -445,3 +445,61 @@ new-style completions: not posted
Me: 5281 now works, 5364 Me: 5281 now works, 5364
Me: make dependencies for main.o, Makemod, zshpaths.h, 5365 Me: make dependencies for main.o, Makemod, zshpaths.h, 5365
pws-9
Bart: CVS should ignore version.h, 5367
Oliver Kiddle: another change of mailing list host, 5372
Oliver: compctl -T documentation for ~dirs, 5374
Andrej: Reliant UNIX configuration, 5377
Sven: Manual for new completion (so far), 5384, 5397
Me: dump new completion status for fast initialisation, 5393
Me: bug fixlet for __path_files, 5398
Sven: overhaul of do_ambiguous with some bug-fixage, 5399, 5407
Sven: print needs - in Functions/Completion/dump, 5400; auto-dump and use
$COMPDUMP file, 5402
Sven: files -> __files, 5401
Me: magicequalsubst now affects all arguments ...=~...:~..., 5403
Me: set -x output for [[ ... ]], 5408
Me: IRIX 6.5 problems in Etc/MACHINES (see 5410 from Helmut Jarausch).
Sven: 5412: better matcher control.
Sven: 5415: anchors in matchers shouldn't match variable part of completion
Sven: 5417: multiple subscripts with undefined array
Sven: 5418: small addmatches fixes
Me: 5421: setting same element of assoc array in full array assignment crashed
Sven: 5422: braces in completions were not tokenized; array parameters were
used uncopied
Sven: 5423: compadd accepts either - or -- to end options
Sven: 5424: addmatches fix when not doing matching
Me: 5425: fix pattern matching for new completion
Sven: 5429: $CONTEXT strings
Sven: 5430: rewrite Functions/Completions with simplified syntax (no #array
type completions).
Me: 5436: set -x for function calls and ((...)).
Me: unposted (but see 5440): zftp changes: more return 6's, functions now
do auto-open and avoid subshells.