1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-06-17 09:08:04 +02:00

zsh-3.1.5-pws-7

This commit is contained in:
Tanaka Akira 1999-04-15 18:14:01 +00:00
parent 7a40d6c258
commit 850fb2e7f9
35 changed files with 1137 additions and 507 deletions

View file

@ -27,5 +27,5 @@
# This must also serve as a shell script, so do not add spaces around the
# `=' signs.
VERSION=3.1.5-pws-6
VERSION_DATE='January 28, 1998'
VERSION=3.1.5-pws-7
VERSION_DATE='February 5, 1999'

View file

@ -913,7 +913,9 @@ is unset, the other will automatically be unset too. There is no way
of untying the variables without unsetting them, or converting the
type of one them with another tt(typeset) command; tt(+T) does not work,
assigning an array to var(SCALAR) is an error, and assigning a scalar
to var(array) sets it to be a single-element array.
to var(array) sets it to be a single-element array. Note that
both tt(typeset -xT ...) and tt(export -T ...) work, but only the
scalar will be marked for export.
If no var(name) is present, the names and values of all parameters are
printed. In this case the attribute flags restrict the the display to
@ -1072,10 +1074,16 @@ Each named parameter is unset.
Local parameters remain local even if unset; they appear unset within scope,
but the previous value will still reappear when the scope ends.
If the tt(-m) flag is specified the
arguments are taken as patterns (should be quoted) and all parameters
with matching names are unset. tt(unset -f) is equivalent to
tt(unfunction).
Individual elements of associative array parameters may be unset by using
subscript syntax on var(name), which should be quoted (or the entire command
prefixed with tt(noglob)) to protect the subscript from filename generation.
If the tt(-m) flag is specified the arguments are taken as patterns (should
be quoted) and all parameters with matching names are unset. Note that this
cannot be used when unsetting associative array elements, as the subscript
will be treated as part of the pattern.
tt(unset -f) is equivalent to tt(unfunction).
)
findex(unsetopt)
cindex(options, unsetting)

View file

@ -32,6 +32,7 @@ menu(Extended Completion)
menu(Matching Control)
menu(Example)
endmenu()
texinode(Command Flags)(Option Flags)()(Programmable Completion)
sect(Command Flags)
Completion of the arguments of a command may be different for each
@ -49,18 +50,20 @@ pathname containing slashes and no completion definition is found, the
search is retried with the last pathname component. If the command starts
with a tt(=), completion is tried with the pathname of the command.
The strings may also be patterns (i.e. they may contain an unquoted
occurrence of characters used to form patterns in the shell). When
completion is attempted, the shell first tries all such pattern compctls.
If one matches the command name on the line or if the pathname of the
command on the line matches a pattern, it is used. The patterns are tested
in reverse order, i.e. the pattern compctl defined last overrides all
previously defined pattern compctls. Unless the option list of that compctl
contains an tt(-t) flag with a \tt(c) character, no more compctls are tried.
Any of the var(command) strings may be patterns of the form normally
used for filename generation. These should be be quoted to protect them
from immediate expansion; for example the command string tt('foo*')
arranges for completion of the words of any command beginning with
tt(foo). When completion is attempted, all pattern completions are
tried in the reverse order of their definition until one matches. By
default, completion then procedes as normal, i.e. the shell will try to
generate more matches for the specific command on the command line; this
can be overridden by including tt(-tn) in the flags for the pattern
completion.
Note that aliases
are expanded before the command name is determined unless the
tt(COMPLETE_ALIASES) option is set. Commands should not be combined
tt(COMPLETE_ALIASES) option is set. Commands may not be combined
with the tt(-C), tt(-D) or tt(-T) flags.
)
item(tt(-C))(
@ -76,8 +79,8 @@ been issued, filenames are completed.
)
item(tt(-T))(
supplies completion flags to be used before any other processing is
done, even those given to specific commands with other compctl
definitions. This is especially useful when combined with extended
done, even before processing for tt(compctl)s defined for specific
commands. This is especially useful when combined with extended
completion (the tt(-x) flag, see noderef(Extended Completion) below).
Using this flag you can define default behavior
which will apply to all commands without exception, or you can alter
@ -85,10 +88,12 @@ the standard behavior for all commands. For example, if your access
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
nofill(tt(compctl -Tx 'C[0,*/*]' -f - 's[~]' -k friends -S/ -tn))
indent(
tt(compctl -T -x 'C[0,*/*]' -f - 's[~]' -k friends -S/ -tn)
)
to complete the strings in the array tt(friends) after a `tt(~)'.
The first argument is necessary so that this form of ~-completion is
The tt(C[...]) argument is necessary so that this form of ~-completion is
not tried after the directory name is finished.
)
item(tt(-L))(
@ -111,7 +116,8 @@ the default. In other words, completion will subsequently use the
options specified by the tt(-D) flag.
The form with tt(-M) as the first and only option defines global
matching specifications described below in noderef(Matching Control).
matching specifications, as described below in noderef(Matching Control).
texinode(Option Flags)(Alternative Completion)(Command Flags)(Programmable Completion)
sect(Option Flags)
startlist()
@ -136,6 +142,7 @@ menu(Simple Flags)
menu(Flags with Arguments)
menu(Control Flags)
endmenu()
texinode(Simple Flags)(Flags with Arguments)()(Option Flags)
subsect(Simple Flags)
These produce completion lists made up by the shell itself:
@ -234,6 +241,7 @@ item(tt(-u))(
User names.
)
enditem()
texinode(Flags with Arguments)(Control Flags)(Simple Flags)(Option Flags)
subsect(Flags with Arguments)
These have user supplied arguments to determine how the list of
@ -248,8 +256,10 @@ of space- or comma-separated values in parentheses, in which any
delimiter may be escaped with a backslash; in this case the argument
should be quoted. For example,
indent(
nofill(tt(compctl -k "(cputime filesize datasize stacksize
coredumpsize resident descriptors)" limit))
coredumpsize resident descriptors)" limit))
)
)
item(tt(-g) var(globstring))(
The var(globstring) is expanded using filename globbing; it should be
@ -282,8 +292,10 @@ should not be made local to the function. From such a function the
command line can be accessed with the tt(-c) and tt(-l) flags to
the tt(read) builtin. For example,
indent(
nofill(tt(function whoson { reply=(`users`); }
compctl -K whoson talk))
)
completes only logged-on users after `tt(talk)'. Note that `tt(whoson)' must
return an array, so `tt(reply=`users`)' would be incorrect.
@ -295,12 +307,15 @@ zero or negative the whole history is searched and if var(pattern) is
the empty string all words are taken (as with `tt(*)'). A typical
use is
nofill(tt(compctl -D -f PLUS() -H 0 ''))
indent(
tt(compctl -D -f PLUS() -H 0 '')
)
which forces completion to look back in the history list for a word if
no filename matches.
)
enditem()
texinode(Control Flags)()(Flags with Arguments)(Option Flags)
subsect(Control Flags)
These do not directly specify types of name to be completed, but
@ -322,7 +337,9 @@ The var(prefix) is inserted just before the completed string; any
initial part already typed will be completed and the whole var(prefix)
ignored for completion purposes. For example,
nofill(tt(compctl -j -P "%" kill))
indent(
tt(compctl -j -P "%" kill)
)
inserts a `%' after the kill command and then completes job names.
)
@ -337,20 +354,23 @@ With directory var(file-prefix): for command, file, directory and
globbing completion (options tt(-c), tt(-f), tt(-/), tt(-g)), the file
prefix is implicitly added in front of the completion. For example,
nofill(tt(compctl -/ -W ~/Mail maildirs))
indent(
tt(compctl -/ -W ~/Mail maildirs)
)
completes any subdirectories to any depth beneath the directory
tt(~/Mail), although that prefix does not appear on the command line.
The var(suffix) may also be of the form accepted by the tt(-k) flag, i.e.
the name of an array or a literal list in parenthesis. In this cases all
words are used as prefixes.
The var(file-prefix) may also be of the form accepted by the tt(-k)
flag, i.e. the name of an array or a literal list in parenthesis. In
this case all the directories in the list will be searched for
possible completions.
)
item(tt(-q))(
If used with a suffix as specified by the tt(-S) option, this
causes the suffix to be 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 (the same rule as used
for the tt(AUTO_REMOVE_SLASH) option). The option is most useful for list
and the next character typed is the same character; this the same rule used
for the tt(AUTO_REMOVE_SLASH) option. The option is most useful for list
separators (comma, colon, etc.).
)
item(tt(-l) var(cmd))(
@ -365,7 +385,9 @@ option. If the var(cmd) string is empty the first word in the range
is instead taken as the command name, and command name completion
performed on the first word in the range. For example,
nofill(tt(compctl -x 'r[-exec,;]' -l '' -- find))
indent(
tt(compctl -x 'r[-exec,;]' -l '' -- find)
)
completes arguments between `tt(-exec)' and the following `tt(;)' (or the end
of the command line if there is no such string) as if they were
@ -417,33 +439,52 @@ expansion following the usual rules for strings in double quotes.
The expansion will be carried out after any functions are called for
the tt(-K) or tt(-y) options, allowing them to set variables.
)
item(tt(-J))(
This gives the name of the group the matches should be placed in. Groups
are listed and sorted separately. Also, menucompletion will offer the matches
in the groups in the order, in which the groups were defined. If no group
name is explicitly given, the matches are stored in a group named var(default).
The first time a group name is encountered, a group with that name is created.
After that all matches with the same group name are stored in that group.
)
item(tt(-V))(
Like tt(-J), but the matches in the group will not be sorted in the listing and
with menucompletion. These unsorted groups are in a different name space than
the sorted ones. I.e. it is possible to have a sorted and a unsorted group
with the same name and the matches in those groups will not be mixed.
)
item(tt(-t) var(continue))(
The var(continue)-string contains a character that specifies which set
of completion flags should be used next. Normally those of the next
matching compctl are used, i.e. pattern compctls and normal compctls
after tt(-T) and after a pattern compctl. If var(continue) is the
character tt(PLUS()) the flags for the next alternative completion
(see below) are used. The characters tt(-) and tt(x) can be used in
sub-lists for extended completion (see below). They will make the
completion code use the flag list after the next tt(-) (if the
corresponding pattern matches) and the default flag list (those before
the tt(-x)), respectively. if var(continue) is the character tt(n) no
other flag lists are used, i.e. the generation of matches stops
immediately.
The var(continue)-string contains a character that specifies which set
of completion flags should be used next. It is useful:
(i) With tt(-T), or when trying a list of pattern completions, when
tt(compctl) would usually continue with ordinary processing after
finding matches; this can be suppressed with `tt(-tn)'.
(ii) With a list of alternatives separated by tt(+), when tt(compctl)
would normally stop when one of the alternatives generates matches. It
can be forced to consider the next set of completions by adding `tt(-t+)'
to the flags of the alternative before the `tt(+)'.
(iii) In an extended completion list (see below), when tt(compctl) would
normally continue until a set of conditions succeeded, then use only
the immediately following flags. With `tt(-t-)', tt(compctl) will
continue trying extended completions after the next `tt(-)'; with
`tt(-tx)' it will attempt completion with the default flags, in other
words those before the `tt(-x)'.
)
item(tt(-J) var(name))(
This gives the name of the group the matches should be placed in. Groups
are listed and sorted separately; likewise, menucompletion will offer
the matches in the groups in the order in which the groups were
defined. If no group name is explicitly given, the matches are stored in
a group named var(default). The first time a group name is encountered,
a group with that name is created. After that all matches with the same
group name are stored in that group.
This can be useful with non-exclusive alternative completions. For
example, in
indent(
tt(compctl -f -J files -t+ + -v -J variables foo)
)
both files and variables are possible completions, as the tt(-t+) forces
both sets of alternatives before and after the tt(+) to be considered at
once. Because of the tt(-J) options, however, all files are listed
before all variables.
)
item(tt(-V) var(name))(
Like tt(-J), but matches within the group will not be sorted in listings
nor in menucompletion. These unsorted groups are in a different name
space than the sorted ones, so groups defined as tt(-J files) and tt(-V
files) are distinct.
)
item(tt(-M) var(match-spec))(
This defines additional matching control specifications that should be used
@ -451,6 +492,7 @@ only when testing words for the list of flags this flag appears in. The format
of the var(match-spec) string is described below in noderef(Matching Control).
)
enditem()
texinode(Alternative Completion)(Extended Completion)(Option Flags)(Programmable Completion)
sect(Alternative Completion)
startlist()
@ -465,16 +507,17 @@ there are no flags after the last `tt(PLUS())' and a match has not been found
up to that point, default completion is tried.
If the list of flags contains a tt(-t) with a tt(PLUS()) character, the next
list of flags is used even if the current list produced matches.
texinode(Extended Completion)(Matching Control)(Alternative Completion)(Programmable Completion)
sect(Extended Completion)
startlist()
list(tt(compctl) [ tt(-CDT) ] var(options) \
tt(-x) var(pattern) var(options) tt(-) ... tt(--) \
[ var(command) ... ])
list(tt(compctl) [ tt(-CDT) ] var(options) \
[ tt(-x) var(pattern) var(options) tt(-) ... tt(--) ] \
[ tt(PLUS()) var(options) [ tt(-x) ... tt(--) ] ... [tt(PLUS())] ] \
[ var(command) ... ])
list(nofill(tt(compctl) [ tt(-CDT) ] var(options) \
tt(-x) var(pattern) var(options) tt(-) ... tt(--)
[ var(command) ... ]))
list(nofill(tt(compctl) [ tt(-CDT) ] var(options) \
[ tt(-x) var(pattern) var(options) tt(-) ... tt(--) ]
[ tt(PLUS()) var(options) [ tt(-x) ... tt(--) ] ... [tt(PLUS())] ] \
[ var(command) ... ]))
endlist()
The form with `tt(-x)' specifies extended completion for the
@ -541,7 +584,9 @@ considered part of the completion, but the rest will. var(index) may
be negative to count from the end: in most cases, var(index) will be
1 or -1. For example,
nofill(tt(compctl -s '`users`' -x 'n[1,@]' -k hosts -- talk))
indent(
tt(compctl -s '`users`' -x 'n[1,@]' -k hosts -- talk)
)
will usually complete usernames, but if you insert an tt(@) after the
name, names from the array var(hosts) (assumed to contain hostnames,
@ -568,184 +613,192 @@ item(tt(R[)var(str1)tt(,)var(str2)tt(])...)(
Like tt(r) but using pattern matching instead.
)
enditem()
texinode(Matching Control)(Example)(Extended Completion)(Programmable Completion)
sect(Matching Control)
Matching specifications are used to describe that certain strings
on the command line match possibly different strings in the words produced
by the completion code.
It is possible by use of the tt(-M) var(spec) flag to specify how the
characters in the string to be completed (referred to here as the
command line) map onto the characters in the list of matches produced by
the completion code (referred to here as the trial completions).
Matching specification strings consist of one or more matching
descriptions separated by whitespace. Each description consists of
a letter followed by a colon and the patterns describing which character
sequences on the line match which character sequences in the words.
The var(spec) consists of one or more matching descriptions separated by
whitespace. Each description consists of a letter followed by a colon,
then the patterns describing which character sequences on the line match
which character sequences in the trial completion. Any sequence of characters not
handled in this fashion must match exactly, as usual.
The forms of var(spec) understood are as follows. In each case, the
form with an uppercase initial character retains the string already
typed on the command line as the final result of completion, while with
a lowercase initial character the string on the command line is changed
into the corresponding part of the trial completion.
The letters understood are: tt(l), tt(r), tt(m), tt(L), tt(R), and tt(M).
startitem()
item(tt(m) and tt(M))(
These describe patterns that match anywhere in the words. The colon should
be followed by two patterns separated by an equal sign. The pattern on the
left side describes the substrings that are to be matched on the command line,
the pattern on the right side describes the substrings matched in the word.
xitem(tt(m:)var(lpat)tt(=)var(tpat))
item(tt(M:)var(lpat)tt(=)var(tpat))(
Here, var(lpat) is a pattern that matches on the command line,
corresponding to var(tpat) which matches in the trial completion.
)
item(tt(l) and tt(L))(
xitem(tt(l:)var(anchor)tt(|)var(lpat)tt(=)var(tpat))
item(tt(L:)var(anchor)tt(|)var(lpat)tt(=)var(tpat))(
These letters are for patterns that are anchored by another pattern on
the left side. In this case the colon has to be followed by the pattern
for the anchor, a pipe symbol, the pattern for the command line, an equal
sign, and the pattern for the word. Patterns anchored on the left side match
only if the anchor-pattern matches directly before the line pattern and if
the string in the word before the word pattern matches the string before
the line pattern in the line string.
the left side. Matching for var(lpat) and var(tpat) is as for tt(m) and
tt(M), but the pattern var(lpat) matched on the command line must be
preceeded by the pattern var(anchor). The var(anchor) can be blank to
anchor the match to the start of the command line string; otherwise the
anchor can occur anywhere, but must match in both the command line and
trial completion strings.
)
item(tt(r) and tt(R))(
Like tt(l) and tt(L) with the difference that the line and word patterns
are anchored on the right side. Also, here the pattern for the anchor has
to come after the pattern for the line, again separated by a pipe symbol.
xitem(tt(r:)var(lpat)tt(|)var(anchor)tt(=)var(tpat))
item(tt(R:)var(lpat)tt(|)var(anchor)tt(=)var(tpat))(
As tt(l) and tt(L) with the difference that the command line and trial
completion patterns are anchored on the right side. Here an empty
var(anchor) forces the match to the end of the command line string.
)
enditem()
Each pattern is either an empty string or consists of a sequence of
character (possibly quoted), question marks, character classes, and
correspondence classes. Normal characters match only themselves, question
marks match any character, and character classes are formed as for
globbing and match the same characters as there.
Correspondence classes are formed like character classes with two
differences: they are delimited by a pair of braces and negated
classes are not allowed (i.e. the characters tt(!) and tt(^) have no
special meaning directly after the opening brace).
Each var(lpat), var(tpat) or var(anchor) is either an empty string or
consists of a sequence of literal characters (which may be quoted with a
backslash), question marks, character classes, and correspondence
classes; ordinary shell patterns are not used. Literal characters match
only themselves, question marks match any character, and character
classes are formed as for globbing and match any character in the given
set.
Correspondence classes are used to conveniently describe that several
characters on the line match several other characters in the word. For
example, if you want to define the any lowercase letter on the line
matches the corresponding uppercase letter in the word all you need to
write down is: `tt(m:{a-z}={A-Z})'. More than one correspondence class
may be given on either side of the equal sign, in this case the first
class on the left says which character matches for the first class on
the right, the second class on either side work together, and so on.
If one side has more such classes than the other side, the superfluous
classes behave like normal character classes. In anchor patterns
correspondence classes always behave like normal character classes.
Correspondence classes are defined like character classes, but with two
differences: they are delimited by a pair of braces, and negated classes
are not allowed, so the characters tt(!) and tt(^) have no special
meaning directly after the opening brace. They indicate that a range of
characters on the line match a range of characters in the trial
completion, but (unlike ordinary character classes) paired according to
the corresponding position in the sequence. For example, to make any
lowercase letter on the line match the corresponding uppercase letter in
the trial completion, you can use `tt(m:{a-z}={A-Z})'. More than one
pair of classes can occur, in which case the first class before the
tt(=) corresponds to the first after it, and so on. If one side has
more such classes than the other side, the superfluous classes behave
like normal character classes. In anchor patterns correspondence classes
also behave like normal character classes.
The word pattern may also be a single star (tt(*)). This means that
the line pattern matches any number of characters in the word. In this
case the pattern has to be anchored (on any side) and the line pattern
matches all characters in the word up to a character sequence that
matches the anchor.
For anchors the empty string as a pattern has a special meaning. Such
empty anchors match only the beginning (in the case of an left side
anchor) or end (for right side anchors) of the command line string or
word.
The distinction between the lowercase and the uppercase forms of the
specification characters is used to define which matched substring
should be put in the match and the generated command line. The
lowercase forms use the substring from the word, so this should be
used if the exact words produced by the completion code need to be
used. The uppercase forms use the substring from the command line and
should be used if the typed string need to be retained.
The pattern var(tpat) may also be a single star, `tt(*)'. This means
that the pattern on the command line can match any number of characters
in the trial completion. In this case the pattern must be anchored (on
either side); the var(anchor) then determines how much of the trial
completion is to be included.
Examples:
startitem()
The option tt(-o) produces option names in all-lowercase form, without
The option tt(-o) produces option names in all-lowercase form, without
underscores, and without the optional tt(no) at the beginning even
though the buitlins tt(setopt) and tt(unsetopt) understand opotion
names with uppercase letters, underscores, and the optional tt(no).
So we want to be able to say, that in this case an prefix tt(no) and
any underscore may be ignored when trying to match the produced words,
and that uppercase letters on the line match the corresponding
lowercase letters in the words. This can be done with:
though the builtins tt(setopt) and tt(unsetopt) understand option names
with uppercase letters, underscores, and the optional tt(no). The
following alters the matching rules so that the prefix tt(no) and any
underscore are ignored when trying to match the trial completions
generated and uppercase letters on the line match the corresponding
lowercase letters in the words:
indent(
tt(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' -o setopt unsetopt)
nofill(tt(compctl -M 'L:|[nN][oO]= M:_= M:{A-Z}={a-z}' \
-o setopt unsetopt))
)
The first part says that the pattern `tt([nN][oO])' at the beginning
(note the empty anchor before the pipe symbol) of the string on the
line matches the the empty string in the produced words, i.e. it need
not be there. The second part says that an underscore anywhere on the
line need not be present in the word, and the third part uses
correspondence classes as in the example above to say that any
(the empty anchor before the pipe symbol) of the string on the
line matches the empty string in the list of words generated by
completion, so it will be ignored if present. The second part does the
same for an underscore anywhere in the command line string, and the
third part uses correspondence classes so that any
uppercase letter on the line matches the corresponding lowercase
letter in the word. The use of the uppercase forms of the
specification characters (tt(L) and tt(M)) guarantees that the special
wrinting on the command line (and especially the option tt(no)) will
not be erased.
As a second example we will make completion case insensitive. For this
we use the form of tt(compctl) that defines matching specification that
are to be used everywhere, i.e. a tt(compctl) with tt(-M) as the only
option given.
The pattern needed was already explained above, this gives us:
specification characters (tt(L) and tt(M)) guarantees that what has
already been typed on the command line (in particular the prefix
tt(no)) will not be deleted.
The second example makes completion case insensitive. By using
tt(compctl) with the tt(-M) option alone this applies to every
completion. This is just the same as in the tt(setopt) example, except
here we wish to retain the characters in the list of completions:
indent(
tt(compctl -M 'm:{a-z}={A-Z}')
)
This makes lowercase letters match their uppercase counterparts. If we
want to make uppercase letters match the lowercase forms, we would
have to use:
This makes lowercase letters match their uppercase counterparts.
To make uppercase letters match the lowercase forms as well:
indent(
tt(compctl -M 'm:{a-z}={A-Z} m:{A-Z}={a-z}')
tt(compctl -M 'm:{a-zA-Z}={A-Za-z}')
)
A nice example for the use of tt(*) patterns is partial word
completion. Sometimes you would like to make strings like tt(c.s.u)
complete to strings like tt(comp.source.unix), i.e. you consider the
word to consist of multiple parts (separated by the dot in the
example) and each part should be completed separately. Defining such
forms of matching is simple, for example if we want to separately
complete word parts separated by dots, commas, underscores, and
hyphens, we can do this by saying:
complete to strings like tt(comp.source.unix), i.e. the word on the
command line consists of multiple parts, separated by a dot in this
example, where each part should be completed separately --- note,
however, that the case where each part of the word, i.e. tt(comp),
tt(source) and tt(unix) in this example, is to be completed separately
is a different problem to be solved by extended completion. The
example can be handled by:
indent(
nofill(tt(compctl -M 'r:|.=* r:|=*' \
-k '(comp.sources.unix comp.sources.misc ...)' ngroups))
)
The first specification says that tt(lpat) is the empty string, while
tt(anchor) is a dot; tt(tpat) is tt(*), so this can match anything in
the trial completion word. So in tt(c.s.u), the matcher sees tt(c),
followed by the empty string, followed by the anchor `tt(.)', and
likewise for the second dot, and replaces the empty strings before the
anchors, giving tt(c)[tt(omp)]tt(.s)[tt(ources)]tt(.u)[tt(nix)], where
the last part of the completion is just as normal.
The second specification is needed to make this work when the cursor is
in the middle of the string on the command line and the option
tt(COMPLETE_IN_WORD) is set. In this case the completion code would
normally try to match trial completions that end with the string as
typed so far, i.e. it will only insert new characters at the cursor
position rather then at the end. However in our example we would like
the code to recognise matches which contain extra characters after the
string on the line (the tt(nix) in the example). Hence we say that the
empty string at the end of the string on the line matches any characters
at the end of the trial completion.
More generally, the specification
indent(
tt(compctl -M 'r:|[.,_-]=* r:|=*')
)
allows one to complete words with abbreviations before any of the
characters in the square brackets in any completion. For example, to
complete tt(veryverylongfile.c) rather than tt(veryverylongheader.h)
with the above in effect, you can just type tt(very.c) before attempting
completion.
The first specification says that an empty string on the line before
one of our special characters matches any number of characters in the
word which has the effect we wanted. The second specification is
needed to make this work when the cursor is in the middle of the word
and the option tt(COMPLETE_IN_WORD) is set. In this case the
completion code would normally try to match word that end with the
string that is already on the command line, but in our example we
would like the code to match words even if they contain extra
characters after the string on the line. Hence we say that the empty
string at the end of the string on the line matches any characters at
the end of the word.
The form of tt(compctl) that defines the global matching
specifications is a bit more powerful than described until now. It
accepts not only one specification strin, but any number of them. When
completion is attempted, the code first uses the definitions from the
first string. If no words could be matched with these specifications,
it tries the whole thing again with the specifications from the second
string, and so on. This allows one to define simple and fast matches
to be used first, more powerful matchers as a second choice, and so on.
As an example we would like to make the code match words that contain
the string on the line as a substring (anywhere, not just at the
beginning). But since this could produce more matches than we want,
this should be tried only if the matchers described above don't
produce any matches. E.g.:
The form tt(compctl -M) that defines global matching actually accepts
any number of specification strings, unlike the case where the tt(-M)
option applies only to a particular command. In this case, when
completion is attempted for any command, the code will try the
specifications in order until one matches. This allows one to define
simple and fast matches to be used first, more powerful matchers as a
second choice, and so on.
For example, one can make the code match trial completions that contain
the string on the command line as a substring, not just at the
beginning. Since this might produce more matches than we want,
we arrange for it to be tried only if the matchers described above don't
produce any matches:
indent(
tt(compctl -M 'r:|[.,_-]=* r:|=*' 'l:|=* r:|=*')
)
Here, if the string on the command line is tt(foo.bar), tt(compctl)
first tries matching tt(foo)var(anything)tt(.bar)var(anything), as
with the previous example. If that fails, the two descriptions in the
second string after the tt(-M) say that the blanks at the beginning
and end of the string on the command line can match any set of
characters at the beginning or end of the trial completion, so it will
look for var(anything)tt(foo.bar)var(anything).
If using the first specification string does not produce matches, the
second one is tried. The two descriptions it this string say that the
empty string at the beginning and end of the string on the line
matches any characters at the beginning or end of the word.
enditem()
texinode(Example)()(Matching Control)(Programmable Completion)
sect(Example)
nofill(tt(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' -g '~/Mail/*(:t)' \
- 's[-f],c[-1,-f]' -f -- mail))
indent(
nofill(
tt(compctl -u -x 's[tt(PLUS())] c[-1,-f],s[-f+PLUS()]' \
-g '~/Mail/*(:t)' - 's[-f],c[-1,-f]' -f -- mail))
)
This is to be interpreted as follows:
If the current command is tt(mail), then

View file

@ -161,8 +161,10 @@ Print the new command but do not execute it. Only works with history
expansion.
)
item(tt(q))(
Quote the substituted words, escaping further substitutions. Only
works with history expansion.
Quote the substituted words, escaping further substitutions. Works
with history expansion and parameter expansion, though in the second
case it is only useful if the resulting text is to be re-evaluated
such as by tt(eval).
)
item(tt(x))(
Like tt(q), but break into words at each blank.
@ -477,9 +479,10 @@ item(tt(${~)var(spec)tt(}))(
pindex(GLOB_SUBST)
Turn on the tt(GLOB_SUBST) option for the evaluation of
var(spec); if the `tt(~)' is doubled, turn it off. When this option is
set, any pattern characters resulting
from parameter expansion are eligible for filename expansion and filename
generation.
set, the string resulting from the expansion will be interpreted as a
pattern anywhere that is possible, such as in filename expansion and
filename generation and pattern-matching contexts like the right
hand side of the `tt(=)' and `tt(!=)' operators in conditions.
)
enditem()
@ -523,6 +526,15 @@ Perform em(parameter expansion), em(command substitution) and
em(arithmetic expansion) on the result. Such expansions can be
nested but too deep recursion may have unpredictable effects.
)
item(tt(P))(
This makes the value of the parameter var(name) be taken as a
parameter name on which to work. If it is used with a tt(${)...tt(})
type parameter expression or a tt($LPAR())...tt(RPAR()) type command
substitution in place of the parameter name this flag makes the result
of the expansion be taken as a parameter name which is then
used. E.g. if you have `tt(foo=bar)' and `tt(bar=baz)', the strings
`tt(${(P)foo})' and `tt(${(P)${foo}})' will be expanded to `tt(baz)'.
)
item(tt(o))(
Sort the resulting words in ascending order.
)
@ -788,7 +800,8 @@ directory as its prefix. If so, then the prefix portion
is replaced with a `tt(~)' followed by the name of the directory.
The shortest way of referring to the directory is used,
with ties broken in favour of using a named directory,
except when the directory is tt(/) itself.
except when the directory is tt(/) itself. The variables tt($PWD) and
tt($OLDPWD) are never abbreviated in this fashion.
If a word begins with an unquoted `tt(=)'
and the tt(EQUALS) option is set,
@ -1088,7 +1101,7 @@ setgid files (02000)
item(tt(t))(
files with the sticky bit (01000)
)
item(tt(o)var(spec))(
item(tt(f)var(spec))(
files with access rights matching var(spec). This var(spec) may be a
octal number optionally preceded by a `tt(=)', a `tt(PLUS())', or a
`tt(-)'. If none of these characters is given, the behavior is the
@ -1101,7 +1114,7 @@ octal digit anywhere in the number ensures that the corresponding bits
inthe file-modes are not checked, this is only useful in combination
with `tt(=)'.
If the qualifier `tt(o)' is followed by any other character anything
If the qualifier `tt(f)' is followed by any other character anything
up to the next matching character (`tt([)', `tt({)', and `tt(<)' match
`tt(])', `tt(})', and `tt(>)' respectively, any other character
matches itself) is taken as a list of comma-separated
@ -1122,11 +1135,11 @@ are to be expected: `tt(r)' for read access, `tt(w)' for write access,
`tt(s)' for the setuid and setgid bits, and `tt(t)' for the sticky
bit.
Thus, `tt(*(o70?))' gives the files for which the owner has read,
Thus, `tt(*(f70?))' gives the files for which the owner has read,
write, and execute permission, and for which other group members have
no rights, independent of the permissions for other user. The pattern
`tt(*(o-100))' gives all files for which the owner does not have
execute permission, and `tt(*(o:gu+w,o-rx))' gives the files for which
`tt(*(f-100))' gives all files for which the owner does not have
execute permission, and `tt(*(f:gu+w,o-rx))' gives the files for which
the owner and the other members of the group have at least write
permission, and fo which other users don't have read or execute
permission.
@ -1205,7 +1218,7 @@ item(tt(D))(
sets the tt(GLOB_DOTS) option for the current pattern
pindex(GLOB_DOTS, setting in pattern)
)
item(tt(O)var(c))(
item(tt(o)var(c))(
specifies how the names of the files should be sorted. If var(c) is
tt(n) they are sorted by name (the default), if var(c) is tt(L) they
are sorted depending on the size (length) of the files, tt(l) makes
@ -1214,16 +1227,20 @@ make them be sorted by the time of the last access, modification, and
inode change respectively. Note that tt(a), tt(m), and tt(c) compare
the age to the current time, so the first name in the list is the
one of the youngest file. Also note that the modifiers tt(^) and tt(-) are
used, so `tt(*(^-OL))' gives a list of all files sorted by file size in
used, so `tt(*(^-oL))' gives a list of all files sorted by file size in
descending order working not on symbolic links but on the files they
point to.
)
item(tt(O)var(c))(
like `tt(o)', but sorts in descending order; i.e. `tt(*(^oc))' is the
same as `tt(*(Oc))' and `tt(*(^Oc))' is the same as `tt(*(oc))'
)
item(tt([)var(beg)[tt(,)var(end)]tt(]))(
specifies which of the matched filenames should be included in the
returned list. The syntax is the same as for array
subscripts. var(beg) and the optional var(end) may be mathematical
expressions. As in parameter subscripting they may be negative to make
them count from the last match backward. E.g.: `tt(*(^-OL[1,3]))'
them count from the last match backward. E.g.: `tt(*(-OL[1,3]))'
gives a list of the names of three biggest files.
)
enditem()

View file

@ -20,6 +20,12 @@ commands are read from tt(/etc/zshrc) and then tt($ZDOTDIR/.zshrc).
Finally, if the shell is a login shell, tt(/etc/zlogin) and
tt($ZDOTDIR/.zlogin) are read.
When a login shell exits, the files tt($ZDOTDIR/.zlogout) and then
tt(/etc/zlogout) are read. This happens with either an explicit exit
via the tt(exit) or tt(logout) commands, or an implict exit by reading
end-of-file from the terminal. However, if the shell terminates due
to tt(exec)'ing another process, the logout files are not read.
If tt(ZDOTDIR) is unset, tt(HOME) is used instead.
Those files listed above as being in tt(/etc) may be in another
directory, depending on the installation.

View file

@ -91,28 +91,30 @@ cindex(mailing lists)
Zsh has 3 mailing lists:
startitem()
item(tt(<zsh-announce@math.gatech.edu>))(
item(tt(<zsh-announce@sunsite.auc.dk>))(
Announcements about releases, major changes in the shell and the
monthly posting of the Zsh FAQ. (moderated)
)
item(tt(<zsh-users@math.gatech.edu>))(
item(tt(<zsh-users@sunsite.auc.dk>))(
User discussions.
)
item(tt(<zsh-workers@math.gatech.edu>))(
item(tt(<zsh-workers@sunsite.auc.dk>))(
Hacking, development, bug reports and patches.
)
enditem()
To subscribe, send mail with the SUBJECT `tt(subscribe) var(<e-mail-address>)'
To subscribe or unsubscribe, send mail
to the associated administrative address for the mailing list.
startlist()
list(tt(<zsh-announce-request@math.gatech.edu>))
list(tt(<zsh-users-request@math.gatech.edu>))
list(tt(<zsh-workers-request@math.gatech.edu>))
endlist()
list(tt(<zsh-announce-subscribe@sunsite.auc.dk>))
list(tt(<zsh-users-subscribe@sunsite.auc.dk>))
list(tt(<zsh-workers-subscribe@sunsite.auc.dk>))
Unsubscribing is done similarly.
list(tt(<zsh-announce-unsubscribe@sunsite.auc.dk>))
list(tt(<zsh-users-unsubscribe@sunsite.auc.dk>))
list(tt(<zsh-workers-unsubscribe@sunsite.auc.dk>))
endlist()
YOU ONLY NEED TO JOIN ONE OF THE MAILING LISTS AS THEY ARE NESTED.
All submissions to bf(zsh-announce) are automatically forwarded to
@ -121,7 +123,7 @@ forwarded to bf(zsh-workers).
If you have problems subscribing/unsubscribing to any of the mailing
lists, send mail to tt(<listmaster@zsh.org>). The mailing lists are
maintained by Richard Coleman tt(<coleman@zsh.org>).
maintained by Karsten Thygesen tt(<karthy@kom.auc.dk>).
The mailing lists are archived; the archives can be accessed via the
administrative addresses listed above. There is also a hypertext

View file

@ -131,12 +131,20 @@ written as `tt(^?)'. Note that `tt(\M^?)' and `tt(^\M?)' are not the same.
findex(vared)
cindex(parameters, editing)
cindex(editing parameters)
item(tt(vared) [ tt(-ch) ] [ tt(-p) var(prompt) ] [ tt(-r) var(rprompt) ] var(name))(
item(tt(vared) [ tt(-Aach) ] [ tt(-p) var(prompt) ] [ tt(-r) var(rprompt) ] var(name))(
The value of the parameter var(name) is loaded into the edit
buffer, and the line editor is invoked. When the editor exits,
var(name) is set to the string value returned by the editor.
If the tt(-c) flag is given, the parameter is created if it doesn't
already exist.
When the tt(-c) flag is given, the parameter is created if it doesn't
already exist. The tt(-a) flag may be given with tt(-c) to create
an array parameter, or the tt(-A) flag to create an associative array.
If the type of an existing parameter does not match the type to be
created, the parameter is unset and recreated.
Individual elements of existing array or associative array parameters
may be edited by using subscript syntax on var(name). New elements are
created automatically, even without tt(-c).
If the tt(-p) flag is given, the following string will be taken as
the prompt to display at the left. If the tt(-r) flag is given,
the following string gives the prompt to display at the right. If the

View file

@ -150,6 +150,17 @@ In a glob pattern, treat a trailing set of parentheses as a qualifier
list, if it contains no `tt(|)', `tt(LPAR())' or (if special) `tt(~)'
characters. See noderef(Filename Generation).
)
pindex(BASH_AUTO_LIST)
cindex(completion, listing choices, bash style)
item(tt(BASH_AUTO_LIST))(
On an ambiguous completion, automatically list choices when the
completion function is called twice in succession. This takes
precedence over tt(AUTO_LIST). The setting of tt(LIST_AMBIGUOUS) is
respected. If tt(AUTO_MENU) is set, the menu behaviour will then start
with the third press. Note that this will not work with
tt(MENU_COMPLETE), since repeated completion calls immediately cycle
through the list in that case.
)
pindex(BEEP)
cindex(beep, enabling)
cindex(enabling the beep)
@ -331,11 +342,12 @@ will be an array or a scalar.
pindex(GLOB_COMPLETE)
item(tt(GLOB_COMPLETE))(
When the current word has a glob pattern, do not insert all the words
resulting from the expansion but cycle through them like
tt(MENU_COMPLETE). If no matches are found, a `tt(*)' is added to the end of the
word or inserted at the cursor if tt(COMPLETE_IN_WORD) is set, and expansion
is attempted again. Using patterns works not only for files but for all
completions, such as options, user names, etc.
resulting from the expansion but generate matches as for completion and
cycle through them like tt(MENU_COMPLETE). If no matches are found, a
`tt(*)' is added to the end of the word or inserted at the cursor if
tt(COMPLETE_IN_WORD) is set, and completion is attempted again using
pattern matching. Since this doesn't use globbing, it works not only for
files but for all completions, such as options, user names, etc.
)
pindex(GLOB_DOTS)
cindex(globbing, of . files)
@ -488,9 +500,12 @@ pindex(LIST_AMBIGUOUS)
cindex(ambiguous completion)
cindex(completion, ambiguous)
item(tt(LIST_AMBIGUOUS))(
If this option is set, completions are shown only if the completions
don't have a unambiguous prefix or suffix that could be inserted in
the command line.
This option works when tt(AUTO_LIST) or tt(BASH_AUTO_LIST) is also
set. If there is an unambiguous prefix to insert on the command line,
that is done without a completion list being displayed; in other
words, auto-listing behaviour only takes place when nothing would be
inserted. In the case of tt(BASH_AUTO_LIST), this means that the list
will be delayed to the third call of the function.
)
pindex(LIST_BEEP)
cindex(beep, ambiguous completion)

View file

@ -40,7 +40,8 @@ Shell function executions delimit scopes for shell parameters.
(Parameters are dynamically scoped.) The tt(typeset) builtin, and its
alternative forms tt(declare), tt(integer), tt(local) and tt(readonly)
(but not tt(export)), can be used to declare a parameter as being local
to the innermost scope.
to the innermost scope. Note that em(special) parameters cannot be made
local.
When a parameter is read or assigned to, the
innermost existing parameter of that name is used. (That is, the
@ -49,9 +50,8 @@ to a non-existent parameter, or declaring a new parameter with tt(export),
causes it to be created in the em(outer)most scope.
Local parameters disappear when their scope ends.
tt(unset) can be used to delete a parameter while it is still in scope; this
will reveal the next outer parameter of the same name. However, em(special)
parameters are still special when unset.
tt(unset) can be used to delete a parameter while it is still in scope;
any outer parameter of the same name remains hidden.
texinode(Array Parameters)(Positional Parameters)(Local Parameters)(Parameters)
sect(Array Parameters)
The value of an array parameter may be assigned by writing:

View file

@ -55,6 +55,11 @@ Linux: Linux (i386) [3.1.4]
process reports that there is no lstat, edit config.h and change
HAVE_LSTAT to 1. libc-5.2.18 or later does not have this problem.
Various problems have been reported when using optimisation
with the experimental GNU compiler, egcs. In particular,
on Linux Alpha with egcs 1.0.3a and 1.1.1 using -O1 or greater,
the completion code is not correctly compiled.
NetBSD: NetBSD 1.*
Should build `out-of-the-box'.

View file

@ -32,7 +32,7 @@ local time=mtime tmod=m
if ((! ARGC)) then
if [[ $opts = *t* ]]; then
set *(O$tmod)
set *(o$tmod)
else
set *
fi
@ -44,7 +44,7 @@ elif [[ $opts = *t* && $ARGC -gt 1 ]]; then
for (( f = 2; f <= $ARGC; f++ )); do
n="$n|\$$f"
done
eval "argv=(($n)(O$tmod))"
eval "argv=(($n)(o$tmod))"
fi
for f in $*

View file

@ -1,7 +1,7 @@
# Define a new widget behaving like `expand-or-complete' but calling the
# function `main-complete' to generate matches.
zle -c my-comp expand-or-complete main-complete
zle -C my-comp expand-or-complete main-complete
bindkey '\C-i' my-comp
@ -75,11 +75,8 @@ compalso() {
# the arguments from the command line as its arguments.
call-complete() {
local var
eval var\=\$\{\+$1\}
if (( var )); then
eval complist \$\{${1}\[\@\]\}
if [[ ${(P)+${1}} -eq 1 ]] then
complist ${(@P)${1}}
else
"$@"
fi
@ -96,15 +93,6 @@ main-complete() {
setopt localoptions nullglob rcexpandparam globdots
unsetopt markdirs globsubst shwordsplit nounset
# 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 this produces any matches, we don't try new style completion. If you
# want to have that tried anyway, remove the `[[ -nmatches ... ]] ...'
# below.
compcall
[[ -nmatches 0 ]] || return
# An entry for `--first--' is the replacement for `compctl -T'
# The `|| return 1' is used throughout: if a function producing matches
# returns non-zero this is interpreted as `do not try to produce more matches'
@ -117,6 +105,15 @@ main-complete() {
# convenience alias `compsub'.
if [[ $CONTEXT == argument || $CONTEXT == command ]] then
# 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 this produces any matches, we don't try new style completion. If you
# want to have that tried anyway, remove the `[[ -nmatches ... ]] ...'
# below.
compcall
[[ -nmatches 0 ]] || return
compsub
else
# Let's see if we have a special completion definition for the other
@ -191,7 +188,8 @@ do-complete() {
# This is intended as a replacement for `complist -f', `complist -/', and
# `complist -g ...' (but don't use it with other options).
# This function behaves as if you have a matcher definition like:
# compctl -M 'r:|[-.,_/]=* r:|=* m:{a-z}={A-Z} m:-=_ m:.=,'
# 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.
pfiles() {
@ -205,7 +203,7 @@ pfiles() {
if [[ "$a[1]" = '(' ]] then
ppres=( $a[2,-2]/ )
else
eval ppres\=\( \$$a/ \)
ppres=( ${(P)${a}} )
[[ $#ppres -eq 0 ]] && ppres=( $a/ )
fi
[[ $#ppres -eq 0 ]] && ppres=( '' )
@ -214,7 +212,7 @@ pfiles() {
ppres=( '' )
fi
str="$PREFIX*$SUFFIX"
str="${PREFIX:q}*${SUFFIX:q}"
if [[ -z "$a[1]" || "$str[1]" = [~/] || "$str" = (.|..)/* ]] then
a=()
@ -259,7 +257,12 @@ pfiles() {
str="${str#*/}"
done
ostr="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*."
if [[ -matcher 1 ]] then
ostr="$str:gs/,/*,/:gs/_/*_/:gs./.*/.:gs/-/*[-_]/:gs/./*[.,]/:gs-*[.,]*[.,]*/-../-:gs.**.*."
else
ostr="${str%/*}/*${str##*/}*"
ostr="$ostr:gs./.*/.:gs.**.*."
fi
for ppre in "$ppres[@]"; do
str="$ostr"
@ -276,7 +279,6 @@ pfiles() {
s=( "${(@)s:gs.**.*.}" )
for i in $a; do
b=( $~i/(#l)$~s )
eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \)
[[ $#b -ne 0 ]] && c=( $c $i )
done
if [[ $#c -eq 0 ]] then
@ -284,10 +286,9 @@ pfiles() {
elif [[ $#c -ne 1 ]] then
a="$ppre$epre$pa"
c=( $~c/(#l)$~s )
eval c\=\( \$\{c:/\*\(${(j:|:)fignore}\)\} \)
c=( ${c#$a} )
for i in $c; do
compadd -p "$pre$pa" -W "$a" -s "/${i#*/}" -f "${i%%/*}"
compadd -p "$pre$pa" -W "$a" -s "/${i#*/}" -fF -- "${i%%/*}"
done
continue 2
fi
@ -301,8 +302,7 @@ pfiles() {
s=( $str$@ )
s=( "${(@)s:gs.**.*.}" )
b=( $~a(#l)$~s )
eval b\=\( \$\{b:/\*\(${(j:|:)fignore}\)\} \)
compadd -p "$pre$pa" -W "$ppre$epre$pa" -f ${b#$a}
compadd -p "$pre$pa" -W "$ppre$epre$pa" -fF -- ${b#$a}
done
}
@ -332,11 +332,20 @@ __vars=( -v )
defcomp __subscr --subscr--
__subscr() {
local t
eval t\=\$\{\(t\)$COMMAND\}
compalso --math-- "$@"
[[ $t = assoc* ]] && eval complist -k \"\(\$\{\(k\)$COMMAND\}\)\"
[[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"
}
defcomp __cond --cond--
__cond() {
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
}
# Do sub-completion for pre-command modifiers.

View file

@ -210,6 +210,7 @@ struct cmatch {
int flags; /* see CMF_* below */
int brpl; /* the place where to put the brace prefix */
int brsl; /* ...and the suffix */
char *rems; /* when to remove the suffix */
};
#define CMF_FILE 1 /* this is a file */
@ -272,3 +273,12 @@ struct cline {
#define CFN_FIRST 1
#define CFN_DEFAULT 2
/* Flags for compadd and addmatches(). */
#define CAF_QUOTE 1
#define CAF_MENU 2
#define CAF_NOSORT 4
#define CAF_ALT 8
#define CAF_FIGNORE 16
#define CAF_MATCH 32

View file

@ -49,7 +49,7 @@ void (*makecompparamsptr) _((void));
/* pointers to functions required by compctl and defined by zle */
/**/
void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, int, int, int, int, int, char **));
void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char **));
/**/
char *(*comp_strptr) _((int*,int*));
@ -95,7 +95,8 @@ int incompfunc;
/**/
long compcurrent,
compnmatches;
compnmatches,
compmatcher;
/**/
char *compcontext,
@ -104,14 +105,8 @@ char *compcontext,
*compsuffix,
*compiprefix;
/* This variable and the functions rembslash() and quotename() came from *
* zle_tricky.c, but are now used in compctl.c, too. */
/* 1 if we are completing in a string */
/**/
int instring;
/* The function rembslash() came from zle_tricky.c, but is now used *
* in compctl.c, too. */
/**/
static void
@ -395,70 +390,6 @@ rembslash(char *s)
return t;
}
/* Quote the string s and return the result. If e is non-zero, the *
* pointer it points to may point to a position in s and in e the position *
* of the corresponding character in the quoted string is returned. Like *
* e, te may point to a position in the string and pl is used to return *
* the position of the character pointed to by te in the quoted string. *
* The string is metafied and may contain tokens. */
/**/
char *
quotename(const char *s, char **e, char *te, int *pl)
{
const char *u, *tt;
char *v, buf[PATH_MAX * 2];
int sf = 0;
tt = v = buf;
u = s;
for (; *u; u++) {
if (e && *e == u)
*e = v, sf |= 1;
if (te == u)
*pl = v - tt, sf |= 2;
if (ispecial(*u) &&
(!instring || (isset(BANGHIST) &&
*u == (char)bangchar) ||
(instring == 2 &&
(*u == '$' || *u == '`' || *u == '\"')) ||
(instring == 1 && *u == '\''))) {
if (*u == '\n' || (instring == 1 && *u == '\'')) {
if (unset(RCQUOTES)) {
*v++ = '\'';
if (*u == '\'')
*v++ = '\\';
*v++ = *u;
*v++ = '\'';
} else if (*u == '\n')
*v++ = '"', *v++ = '\n', *v++ = '"';
else
*v++ = '\'', *v++ = '\'';
continue;
} else
*v++ = '\\';
}
if(*u == Meta)
*v++ = *u++;
*v++ = *u;
}
*v = '\0';
if (strcmp(buf, s))
tt = dupstring(buf);
else
tt = s;
v += tt - buf;
if (e && (sf & 1))
*e += tt - buf;
if (e && *e == u)
*e = v;
if (te == u)
*pl = v - tt;
return (char *) tt;
}
/**/
int
setup_comp1(Module m)

View file

@ -14,6 +14,7 @@ compcontext
compctltab
compcurrent
compiprefix
compmatcher
compnmatches
compprefix
comp_strptr
@ -30,5 +31,4 @@ makecomplistcallptr
makecomplistctlptr
makecompparamsptr
patcomps
quotename
rembslash

View file

@ -1385,7 +1385,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
untokenize(p);
quotedzputs(p, stdout);
} else
quotedzputs(quotename(s, NULL, NULL, NULL), stdout);
quotedzputs(bslashquote(s, NULL, NULL, NULL, 0), stdout);
}
/* loop through flags w/o args that are set, printing them if so */
@ -1515,7 +1515,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
char *p = dupstring(s);
untokenize(p);
quotedzputs(quotename(p, NULL, NULL, NULL), stdout);
quotedzputs(bslashquote(p, NULL, NULL, NULL, 0), stdout);
}
}
putchar('\n');
@ -1547,8 +1547,6 @@ bin_compctl(char *name, char **argv, char *ops, int func)
cclist = 0;
showmask = 0;
instring = 0;
/* Parse all the arguments */
if (*argv) {
/* Let's see if this is a global matcher definition. */
@ -1671,8 +1669,9 @@ bin_compadd(char *name, char **argv, char *ops, int func)
{
char *p, **sp, *e;
char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
char *pre = NULL, *suf = NULL, *group = NULL;
int f = 0, q = 0, m = 0, ns = 0, a = 0;
char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
int f = 0, a = 0, dm;
Cmatcher match = NULL;
if (incompfunc != 1) {
zerrnam(name, "can only be called from completion function", NULL, 0);
@ -1681,21 +1680,25 @@ bin_compadd(char *name, char **argv, char *ops, int func)
for (; *argv && **argv == '-'; argv++) {
for (p = *argv + 1; *p; p++) {
sp = NULL;
dm = 0;
switch (*p) {
case 'q':
f |= CMF_REMOVE;
break;
case 'Q':
q = 1;
a |= CAF_QUOTE;
break;
case 'f':
f |= CMF_FILE;
break;
case 'F':
a |= CAF_FIGNORE;
break;
case 'n':
f |= CMF_NOLIST;
break;
case 'U':
m = 1;
a |= CAF_MENU;
break;
case 'P':
sp = &pre;
@ -1711,7 +1714,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
break;
case 'V':
if (!group)
ns = 1;
a |= CAF_NOSORT;
sp = &group;
e = "group name expected after -%c";
break;
@ -1732,7 +1735,19 @@ bin_compadd(char *name, char **argv, char *ops, int func)
e = "string expected after -%c";
break;
case 'a':
a = 1;
a |= CAF_ALT;
break;
case 'm':
a |= CAF_MATCH;
break;
case 'M':
sp = &m;
e = "matching specification expected after -%c";
dm = 1;
break;
case 'r':
sp = &rs;
e = "string expected after -%c";
break;
case '-':
argv++;
@ -1756,6 +1771,10 @@ bin_compadd(char *name, char **argv, char *ops, int func)
zerrnam(name, e, NULL, *p);
return 1;
}
if (dm && (match = parse_cmatcher(name, m)) == pcm_err) {
match = NULL;
return 1;
}
}
}
}
@ -1764,7 +1783,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
return 1;
addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
f, q, m, ns, a, argv);
rs, f, a, match, argv);
return 0;
}
@ -1794,6 +1813,7 @@ static struct compparam {
{ "SUFFIX", PM_SCALAR, VAR(compsuffix) },
{ "IPREFIX", PM_SCALAR, VAR(compiprefix) },
{ "NMATCHES", PM_INTEGER, VAR(compnmatches) },
{ "MATCHER", PM_INTEGER, VAR(compmatcher) },
{ NULL, 0, NULL }
};
@ -2096,6 +2116,15 @@ cond_nmatches(char **a, int id)
return 0;
}
/**/
static int
cond_matcher(char **a, int id)
{
if (comp_check())
return compmatcher == cond_val(a, 0);
return 0;
}
static struct builtin bintab[] = {
BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL),
@ -2119,6 +2148,7 @@ static struct conddef cotab[] = {
CONDDEF("after", 0, cond_range, 1, 1, 0),
CONDDEF("mafter", 0, cond_range, 1, 1, 1),
CONDDEF("nmatches", 0, cond_nmatches, 1, 1, 0),
CONDDEF("matcher", 0, cond_matcher, 1, 1, 0),
};
static struct funcwrap wrapper[] = {

View file

@ -663,6 +663,11 @@ doisearch(int dir)
static char *previous_search = NULL;
static int previous_search_len = 0;
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
strcpy(ibuf, ISEARCH_PROMPT);
memcpy(ibuf + NORM_PROMPT_POS, (dir == 1) ? "fwd" : "bck", 3);
remember_edits();
@ -943,6 +948,10 @@ getvisrchstr(void)
zsfree(visrchstr);
visrchstr = NULL;
}
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
statusline = sbuf;
sbuf[0] = (visrchsense == -1) ? '?' : '/';
selectkeymap("main", 1);

View file

@ -661,10 +661,17 @@ bin_vared(char *name, char **args, char *ops, int func)
{
char *s;
char *t;
Param pm;
Value v;
Param pm = 0;
int create = 0;
int type = PM_SCALAR;
char *p1 = NULL, *p2 = NULL;
if (zleactive) {
zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0);
return 1;
}
/* all options are handled as arguments */
while (*args && **args == '-') {
while (*++(*args))
@ -674,6 +681,12 @@ bin_vared(char *name, char **args, char *ops, int func)
yet exist */
create = 1;
break;
case 'a':
type = PM_ARRAY;
break;
case 'A':
type = PM_HASHED;
break;
case 'p':
/* -p option -- set main prompt string */
if ((*args)[1])
@ -709,6 +722,9 @@ bin_vared(char *name, char **args, char *ops, int func)
}
args++;
}
if (type && !create) {
zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A", 0);
}
/* check we have a parameter name */
if (!*args) {
@ -716,17 +732,17 @@ bin_vared(char *name, char **args, char *ops, int func)
return 1;
}
/* handle non-existent parameter */
if (!(s = getsparam(args[0]))) {
if (create)
createparam(args[0], PM_SCALAR);
else {
zwarnnam(name, "no such variable: %s", args[0], 0);
return 1;
}
}
if(zleactive) {
zwarnnam(name, "ZLE cannot be used recursively (yet)", NULL, 0);
s = args[0];
v = fetchvalue(&s, (!create || type == PM_SCALAR),
SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY);
if (!v && !create) {
zwarnnam(name, "no such variable: %s", args[0], 0);
return 1;
} else if (v) {
s = getstrvalue(v);
pm = v->pm;
} else if (*s) {
zwarnnam(name, "invalid parameter name: %s", args[0], 0);
return 1;
}
@ -744,14 +760,24 @@ bin_vared(char *name, char **args, char *ops, int func)
if (t[strlen(t) - 1] == '\n')
t[strlen(t) - 1] = '\0';
/* final assignment of parameter value */
pm = (Param) paramtab->getnode(paramtab, args[0]);
if (pm && PM_TYPE(pm->flags) == PM_ARRAY) {
if (create && (!pm || (type && PM_TYPE(pm->flags) != type))) {
if (pm)
unsetparam(args[0]);
createparam(args[0], type);
pm = 0;
}
if (!pm)
pm = (Param) paramtab->getnode(paramtab, args[0]);
if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) {
char **a;
PERMALLOC {
a = spacesplit(t, 1);
} LASTALLOC;
setaparam(args[0], a);
if (PM_TYPE(pm->flags) == PM_ARRAY)
setaparam(args[0], a);
else
sethparam(args[0], a);
} else
setsparam(args[0], t);
return 0;
@ -766,6 +792,10 @@ describekeybriefly(void)
if (statusline)
return;
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
statusline = "Describe key briefly: _";
statusll = strlen(statusline);
zrefresh();

View file

@ -612,6 +612,10 @@ executenamedcommand(char *prmt)
char *ptr;
char *okeymap = curkeymapname;
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
cmdbuf = halloc(l + NAMLEN + 2);
strcpy(cmdbuf, prmt);
statusline = cmdbuf;
@ -792,6 +796,49 @@ makeparamsuffix(int br, int n)
}
}
/* Set up suffix given a string containing the characters on which to *
* remove the suffix. */
/**/
void
makesuffixstr(char *s, int n)
{
if (s) {
int inv, i, v, z = 0;
if (*s == '^' || *s == '!') {
inv = 1;
s++;
} else
inv = 0;
s = getkeystring(s, &i, 5, &z);
s = metafy(s, i, META_USEHEAP);
if (inv) {
v = 0;
for (i = 0; i < 257; i++)
suffixlen[i] = n;
} else
v = n;
if (z)
suffixlen[256] = v;
while (*s) {
if (s[1] == '-' && s[2]) {
int b = (int) *s, e = (int) s[2];
while (b <= e)
suffixlen[b++] = v;
s += 2;
} else
suffixlen[STOUC(*s)] = v;
s++;
}
} else
makesuffix(n);
}
/* Remove suffix, if there is one, when inserting character c. */
/**/

View file

@ -390,7 +390,7 @@ scanlistwidgets(HashNode hn, int list)
if(w->flags & WIDGET_INT)
return;
if(list) {
fputs("zle -N ", stdout);
printf("zle -%c ", (w->flags & WIDGET_NCOMP) ? 'C' : 'N');
if(t->nam[0] == '-')
fputs("-- ", stdout);
quotedzputs(t->nam, stdout);
@ -406,7 +406,7 @@ scanlistwidgets(HashNode hn, int list)
} else {
nicezputs(t->nam, stdout);
if (w->flags & WIDGET_NCOMP) {
fputs(" -c ", stdout);
fputs(" -C ", stdout);
nicezputs(w->u.comp.wid, stdout);
fputc(' ', stdout);
nicezputs(w->u.comp.func, stdout);

View file

@ -223,7 +223,7 @@ typedef struct aminfo *Aminfo;
struct aminfo {
int cpl, csl, icpl, icsl; /* common prefix/suffix lengths */
int prerest; /* minimum prefix rest */
int minlen; /* minimum match length */
int suflen; /* minimum suffix length */
Cmatch firstm; /* the first match */
char *pprefix; /* common part of the -P prefixes */
@ -270,6 +270,19 @@ enum { COMP_COMPLETE,
COMP_LIST_EXPAND };
#define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
/* Non-zero if the last completion done was ambiguous (used to find *
* out if AUTOMENU should start). More precisely, it's nonzero after *
* successfully doing any completion, unless the completion was *
* unambiguous and did not cause the display of a completion list. *
* From the other point of view, it's nonzero iff AUTOMENU (if set) *
* should kick in on another completion. *
* *
* If both AUTOMENU and BASHAUTOLIST are set, then we get a listing *
* on the second tab, a` la bash, and then automenu kicks in when *
* lastambig == 2. */
static int lastambig;
/**/
void
completecall(void)
@ -287,8 +300,13 @@ completeword(void)
useglob = isset(GLOBCOMPLETE);
if (c == '\t' && usetab())
selfinsert();
else
docomplete(COMP_COMPLETE);
else {
if (lastambig == 1 && isset(BASHAUTOLIST) && !usemenu && !menucmp) {
docomplete(COMP_LIST_COMPLETE);
lastambig = 2;
} else
docomplete(COMP_COMPLETE);
}
}
/**/
@ -358,8 +376,13 @@ expandorcomplete(void)
useglob = isset(GLOBCOMPLETE);
if (c == '\t' && usetab())
selfinsert();
else
docomplete(COMP_EXPAND_COMPLETE);
else {
if (lastambig == 1 && isset(BASHAUTOLIST) && !usemenu && !menucmp) {
docomplete(COMP_LIST_COMPLETE);
lastambig = 2;
} else
docomplete(COMP_EXPAND_COMPLETE);
}
}
/**/
@ -451,15 +474,6 @@ static int lincmd, linredir;
static char *rdstr;
/* Non-zero if the last completion done was ambiguous (used to find *
* out if AUTOMENU should start). More precisely, it's nonzero after *
* successfully doing any completion, unless the completion was *
* unambiguous and did not cause the display of a completion list. *
* From the other point of view, it's nonzero iff AUTOMENU (if set) *
* should kick in on another completion. */
static int lastambig;
/* This holds the name of the current command (used to find the right *
* compctl). */
@ -473,6 +487,16 @@ static char *varname;
static int insubscr;
/* 1 if we are completing in a string */
/**/
int instring;
/* Convenience macro for calling bslashquote() (formerly quotename()). *
* This uses the instring variable above. */
#define quotename(s, e, te, pl) bslashquote(s, e, te, pl, instring)
/* Check if the given string is the name of a parameter and if this *
* parameter is one worth expanding. */
@ -569,7 +593,8 @@ docomplete(int lst)
/* Check if we have to start a menu-completion (via automenu). */
if ((amenu = (isset(AUTOMENU) && lastambig)))
if ((amenu = (isset(AUTOMENU) && lastambig &&
(!isset(BASHAUTOLIST) || lastambig == 2))))
usemenu = 1;
/* Expand history references before starting completion. If anything *
@ -919,7 +944,7 @@ unmetafy_line(void)
static char *
get_comp_string(void)
{
int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins;
int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, inarr, ia, parct;
char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
zsfree(brbeg);
@ -982,7 +1007,7 @@ get_comp_string(void)
inpush(dupstrspace((char *) linptr), 0, NULL);
strinbeg();
stophist = 2;
i = tt0 = cp = rd = ins = oins = 0;
i = tt0 = cp = rd = ins = oins = inarr = parct = ia = 0;
/* This loop is possibly the wrong way to do this. It goes through *
* the previously massaged command line using the lexer. It stores *
@ -1001,7 +1026,21 @@ get_comp_string(void)
linredir = (inredir && !ins);
oins = ins;
/* Get the next token. */
if (inarr)
incmdpos = 0;
ctxtlex();
if (tok == ENVARRAY) {
inarr = 1;
zsfree(varname);
varname = ztrdup(tokstr);
} else if (tok == INPAR)
parct++;
else if (tok == OUTPAR) {
if (parct)
parct--;
else
inarr = 0;
}
if (inredir)
rdstr = tokstrings[tok];
if (tok == DINPAR)
@ -1043,6 +1082,7 @@ get_comp_string(void)
clwpos = i;
cp = lincmd;
rd = linredir;
ia = inarr;
if (inwhat == IN_NOTHING && incond)
inwhat = IN_COND;
} else if (linredir)
@ -1084,8 +1124,13 @@ get_comp_string(void)
zsfree(clwords[clwnum]);
clwords[clwnum] = NULL;
t0 = tt0;
lincmd = cp;
linredir = rd;
if (ia) {
lincmd = linredir = 0;
inwhat = IN_ENV;
} else {
lincmd = cp;
linredir = rd;
}
strinend();
inpop();
errflag = zleparse = 0;
@ -1789,9 +1834,17 @@ inst_cline(Cline l, int pl, int sl)
pl += brpl;
i = cs - wb;
if (pl >= 0 && i >= pl && brbeg && *brbeg) {
inststrlen(brbeg, 1, -1);
pl = -1;
hb = 1;
}
if (sl >= 0 && i >= sl && brend && *brend) {
inststrlen(brend, 1, -1);
sl = -1;
hb = 1;
}
while (l) {
if (d < 0 && (l->flags & CLF_DIFF))
d = cs;
if (m < 0 && (l->flags & (CLF_MISS | CLF_SUF)) == (CLF_MISS | CLF_SUF))
m = cs;
if (l->flags & CLF_MID) {
@ -1805,6 +1858,8 @@ inst_cline(Cline l, int pl, int sl)
} else {
inststrlen(l->line, 1, l->llen);
}
if (d < 0 && (l->flags & CLF_DIFF))
d = cs;
if (m < 0 && (l->flags & CLF_MISS))
m = cs;
i += l->llen;
@ -1893,8 +1948,10 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp,
while (ll && lw) {
for (ms = mstack; ms; ms = ms->next) {
for (mp = ms->matcher; mp; mp = mp->next) {
if (nm == mp || lm == mp)
if (nm == mp || lm == mp) {
nm = NULL;
continue;
}
t = 1;
/* Try to match the prefix, if any. */
if (mp->flags & CMF_LEFT) {
@ -1930,7 +1987,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp,
NULL, NULL, mp))
break;
}
if (k) {
if (k && i) {
if (nlp) {
nw = addtoword(&rw, &rwlen, nw, mp,
l, w, i, 0);
@ -2106,8 +2163,10 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm)
while (ll && lw) {
for (ms = mstack; ms; ms = ms->next) {
for (mp = ms->matcher; mp; mp = mp->next) {
if (nm == mp || lm == mp)
if (nm == mp || lm == mp) {
nm = NULL;
continue;
}
t = 1;
if (mp->flags & CMF_RIGHT) {
if (il < mp->ralen || iw < mp->ralen)
@ -2135,13 +2194,13 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm)
if (t) {
int i = 0, j = iw, k = lw;
int jj = il + mp->llen, kk = ll - mp->llen;
char *p = l - mp->llen, *q = w;
char *p = l - mp->llen - 1, *q = w - 1;
for (; k; i++, j++, k--, q--)
if (match_sfx(p, q, NULL, NULL,
NULL, mp))
if (match_pfx(p, q, NULL, NULL,
NULL, NULL, mp))
break;
if (k) {
if (k && i) {
if (nlp) {
nw = addtoword(&rw, &rwlen, nw, mp,
l - mp->llen, w - i,
@ -2151,10 +2210,10 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp, Cmatcher nm)
((mp->flags & CMF_LEFT) ?
CLF_SUF : 0));
}
w = q;
w = q + 1;
iw = j;
lw = k;
l = p;
l = p + 1;
il = jj;
ll = kk;
bc -= i;
@ -2395,20 +2454,45 @@ instmatch(Cmatch m)
/**/
void
addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
char *suf, char *group,
int flags, int quote, int menu, int nosort, int alt, char **argv)
char *suf, char *group, char *rems,
int flags, int aflags, Cmatcher match, char **argv)
{
char *s, *t;
int lpl, lsl, i;
Aminfo ai = (alt ? fainfo : ainfo);
char *s, *t, *e, *te, *ms, *lipre = NULL, *lpre, *lsuf;
int lpl, lsl, i, pl, sl, test, bpl, bsl, lsm, llpl;
Aminfo ai;
Cline lc = NULL;
LinkList l;
Cmatch cm;
struct cmlist mst;
Cmlist oms = mstack;
if (menu && isset(AUTOMENU))
if (aflags & CAF_ALT) {
l = fmatches;
ai = fainfo;
} else {
l = matches;
ai = ainfo;
}
if (match) {
mst.next = mstack;
mst.matcher = match;
mstack = &mst;
}
if ((aflags & CAF_MENU) && isset(AUTOMENU))
usemenu = 1;
SWITCHHEAPS(compheap) {
HEAPALLOC {
if (aflags & CAF_MATCH) {
ctokenize(lipre = dupstring(compiprefix));
remnulargs(lipre);
ctokenize(lpre = dupstring(compprefix));
remnulargs(lpre);
llpl = strlen(lpre);
ctokenize(lsuf = dupstring(compsuffix));
remnulargs(lsuf);
}
if (ipre)
ipre = dupstring(ipre);
ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre));
if (ppre) {
ppre = dupstring(ppre);
lpl = strlen(ppre);
@ -2419,6 +2503,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
lsl = strlen(psuf);
} else
lsl = 0;
if (aflags & CAF_MATCH)
lsm = (psuf ? !strcmp(psuf, lsuf) : (!lsuf || !*lsuf));
if (pre)
pre = dupstring(pre);
if (suf)
@ -2430,10 +2516,12 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
prpre = dupstring(prpre);
if (group) {
endcmgroup(NULL);
begcmgroup(group, nosort);
if (nosort)
begcmgroup(group, (aflags & CAF_NOSORT));
if (aflags & CAF_NOSORT)
mgroup->flags |= CGF_NOSORT;
}
if (rems)
rems = dupstring(rems);
if (ai->pprefix) {
if (pre)
ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0';
@ -2442,10 +2530,54 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
} else
ai->pprefix = dupstring(pre ? pre : "");
for (; (s = *argv); argv++) {
if (ai->firstm) {
if ((i = pfxlen(ai->firstm->str, s)) < ai->prerest)
ai->prerest = i;
for (; (s = dupstring(*argv)); argv++) {
sl = strlen(s);
ms = NULL;
bpl = brpl;
bsl = brsl;
if ((!psuf || !*psuf) && (aflags & CAF_FIGNORE)) {
char **pt = fignore;
int filell;
for (test = 1; test && *pt; pt++)
if ((filell = strlen(*pt)) < sl
&& !strcmp(*pt, s + sl - filell))
test = 0;
if (!test) {
l = fmatches;
ai = fainfo;
} else {
l = matches;
ai = ainfo;
}
}
if (aflags & CAF_MATCH) {
t = (ppre ? dyncat(ppre, s) : s);
pl = sl + lpl;
if ((test = (llpl <= pl && !strncmp(t, lpre, pl))))
test = lsm;
if (!test && mstack &&
(ms = comp_match(lpre, lsuf,
(psuf ? dyncat(t, psuf) : t),
&lc, (aflags & CAF_QUOTE),
&bpl, &bsl)))
test = 1;
if (!test)
continue;
e = s + sl;
} else {
e = s;
pl = lpl;
}
if (!(aflags & CAF_QUOTE)) {
te = s + pl;
s = quotename(s, &e, te, &pl);
sl = strlen(s);
}
if (!ms && ai->firstm) {
if (sl < ai->minlen)
ai->minlen = sl;
if ((i = sfxlen(ai->firstm->str, s)) < ai->suflen)
ai->suflen = i;
}
@ -2453,15 +2585,20 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
if (ppre)
t = dyncat(ppre, t);
if (ipre && *ipre) {
Cline tlc = prepend_cline(ipre, lc);
ai->noipre = 0;
if (ai->icpl > lpl)
ai->icpl = lpl;
if (ai->icsl > lsl)
ai->icsl = lsl;
if (ai->iaprefix)
ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0';
else
ai->iaprefix = dupstring(t);
if (!ms) {
if ((aflags & CAF_MATCH) || ai->icpl > pl)
ai->icpl = pl;
if ((aflags & CAF_MATCH) || ai->icsl > lsl)
ai->icsl = lsl;
if (ai->iaprefix)
ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0';
else
ai->iaprefix = dupstring(t);
} else
ai->ilinecl = join_clines(ai->ilinecl, lc);
if (ai->iprefix) {
if (strcmp(ipre, ai->iprefix))
ai->iprefix = "";
@ -2469,16 +2606,21 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
ai->iprefix = dupstring(ipre);
t = dyncat(ipre, t);
lc = tlc;
} else
ai->iprefix = "";
if (ai->cpl > lpl)
ai->cpl = lpl;
if (ai->csl > lsl)
ai->csl = lsl;
if (ai->aprefix)
ai->aprefix[pfxlen(ai->aprefix, t)] = '\0';
else
ai->aprefix = dupstring(t);
if (!ms) {
if ((aflags & CAF_MATCH) || ai->cpl > pl)
ai->cpl = pl;
if ((aflags & CAF_MATCH) || ai->csl > lsl)
ai->csl = lsl;
if (ai->aprefix)
ai->aprefix[pfxlen(ai->aprefix, t)] = '\0';
else
ai->aprefix = dupstring(t);
} else
ai->linecl = join_clines(ai->linecl, lc);
mnum++;
ai->count++;
@ -2486,25 +2628,41 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
cm->ppre = ppre;
cm->psuf = psuf;
cm->prpre = prpre;
if (!quote)
s = quotename(s, NULL, NULL, NULL);
cm->str = dupstring(s);
cm->str = (ms ? ms : dupstring(s));
cm->ipre = cm->ripre = ipre;
cm->pre = pre;
cm->suf = suf;
cm->flags = flags;
cm->brpl = brpl;
cm->brsl = brsl;
addlinknode((alt ? fmatches : matches), cm);
cm->brpl = bpl;
cm->brsl = bsl;
cm->rems = rems;
addlinknode(l, cm);
if (expl)
expl->fcount++;
if (!ai->firstm)
ai->firstm = cm;
if (expl) {
if (l == matches)
expl->count++;
else
expl->fcount++;
}
if (!ms) {
if (!ai->firstm)
ai->firstm = cm;
if ((aflags & CAF_MATCH) && !(e - (s + pl))) {
if (!ai->exact)
ai->exact = 1;
else {
ai->exact = 2;
cm = NULL;
}
ai->exactm = cm;
}
}
}
compnmatches = mnum;
} LASTALLOC;
} SWITCHBACKHEAPS;
mstack = oms;
}
/* This adds a match to the list of matches. The string to add is given *
@ -2685,8 +2843,8 @@ addmatch(char *s, char *t)
if (!test)
return;
if (!ms && !ispattern && ai->firstm) {
if ((test = sl - pfxlen(ai->firstm->str, s)) < ai->prerest)
ai->prerest = test;
if (sl < ai->minlen)
ai->minlen = sl;
if ((test = sfxlen(ai->firstm->str, s)) < ai->suflen)
ai->suflen = test;
}
@ -2716,8 +2874,7 @@ addmatch(char *s, char *t)
ai->iaprefix[pfxlen(ai->iaprefix, t)] = '\0';
else
ai->iaprefix = dupstring(t);
}
else
} else
ai->ilinecl = join_clines(ai->ilinecl, lc);
if (ai->iprefix) {
if (strcmp(ipre, ai->iprefix))
@ -2737,8 +2894,7 @@ addmatch(char *s, char *t)
ai->aprefix[pfxlen(ai->aprefix, t)] = '\0';
else
ai->aprefix = dupstring(t);
}
else
} else
ai->linecl = join_clines(ai->linecl, lc);
mnum++;
@ -2780,6 +2936,7 @@ addmatch(char *s, char *t)
cm->flags = mflags | isf;
cm->brpl = bpl;
cm->brsl = bsl;
cm->rems = NULL;
addlinknode(l, cm);
/* One more match for this explanation. */
@ -3211,7 +3368,12 @@ callcompfunc(char *s, char *fn)
case IN_ENV:
compcontext = "value";
compcommand = varname;
usea = 0;
if (!clwpos) {
clwpos = 1;
zsfree(clwords[1]);
clwords[1] = ztrdup(s);
}
aadd = 1;
break;
case IN_COND:
compcontext = "condition";
@ -3305,17 +3467,19 @@ makecomplist(char *s, int incmd, int lst)
if (validlist)
return !nmatches;
compmatcher = 1;
for (;;) {
if (m) {
ms.next = NULL;
ms.matcher = m->matcher;
mstack = &ms;
}
} else
mstack = NULL;
ainfo = (Aminfo) hcalloc(sizeof(struct aminfo));
fainfo = (Aminfo) hcalloc(sizeof(struct aminfo));
ainfo->prerest = ainfo->suflen =
fainfo->prerest = fainfo->suflen = 10000;
ainfo->minlen = ainfo->suflen =
fainfo->minlen = fainfo->suflen = 10000;
ainfo->noipre = fainfo->noipre= 1;
freecl = NULL;
@ -3358,12 +3522,14 @@ makecomplist(char *s, int incmd, int lst)
break;
errflag = 0;
compmatcher++;
}
return 1;
}
/* This should probably be moved into tokenize(). */
/**/
static char *
ctokenize(char *p)
{
@ -3564,10 +3730,11 @@ makecomplistcmd(char *os, int incmd, int flags)
}
/* Then search the pattern compctls, with the command name and the *
* full pathname of the command. */
makecomplistpc(os, incmd);
if (!(ccont & CC_CCCONT))
return;
if (cmdstr) {
makecomplistpc(os, incmd);
if (!(ccont & CC_CCCONT))
return;
}
/* If the command string starts with `=', try the path name of the *
* command. */
if (cmdstr && cmdstr[0] == Equals) {
@ -5057,6 +5224,7 @@ dupmatch(Cmatch m)
r->flags = m->flags;
r->brpl = m->brpl;
r->brsl = m->brsl;
r->rems = ztrdup(m->rems);
return r;
}
@ -5168,6 +5336,7 @@ freematch(Cmatch m)
zsfree(m->ppre);
zsfree(m->psuf);
zsfree(m->prpre);
zsfree(m->rems);
zfree(m, sizeof(m));
}
@ -5325,10 +5494,11 @@ do_ambiguous(void)
* on the next call to completion the inserted string would be *
* taken as a match and no menu completion would be started. */
if (isset(RECEXACT) && !lc && !ainfo->prerest)
if (isset(RECEXACT) && !lc && ps && ainfo->minlen == strlen(ps))
am = 1;
/* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
/*
* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
* if the completion is completely ambiguous') is set, and some *
* prefix was inserted, return now, bypassing the list-displaying *
* code. On the way, invalidate the list and note that we don't *
@ -5344,7 +5514,8 @@ do_ambiguous(void)
* if it is needed. */
if (isset(LISTBEEP))
feep();
if (isset(AUTOLIST) && !amenu && !showinglist && smatches >= 2)
if (isset(AUTOLIST) && !isset(BASHAUTOLIST) && !amenu && !showinglist &&
smatches >= 2)
showinglist = -2;
if (am)
lastambig = 1;
@ -5420,7 +5591,7 @@ do_single(Cmatch m)
if (menuwe) {
menuend += menuinsc;
if (m->flags & CMF_REMOVE) {
makesuffix(menuinsc);
makesuffixstr(m->rems, menuinsc);
if (menuinsc == 1)
suffixlen[STOUC(m->suf[0])] = 1;
}

View file

@ -816,6 +816,10 @@ viswapcase(void)
void
vicapslockpanic(void)
{
invalidatelist();
moveto(0, 0);
clearflag = 0;
resetneeded = 1;
zbeep();
statusline = "press a lowercase key to continue";
statusll = strlen(statusline);

View file

@ -1036,6 +1036,9 @@ fixdir(char *src)
{
char *dest = src;
char *d0 = dest;
#ifdef __CYGWIN__
char *s0 = src;
#endif
/*** if have RFS superroot directory ***/
#ifdef HAVE_SUPERROOT
@ -1052,6 +1055,11 @@ fixdir(char *src)
for (;;) {
/* compress multiple /es into single */
if (*src == '/') {
#ifdef __CYGWIN__
/* allow leading // under cygwin */
if (src == s0 && src[1] == '/')
*dest++ = *src++;
#endif
*dest++ = *src++;
while (*src == '/')
src++;
@ -1657,7 +1665,8 @@ bin_typeset(char *name, char **argv, char *ops, int func)
if (on & PM_TIED) {
Param apm;
char *name1;
struct asgment asg0;
char *oldval = NULL;
if (ops['m']) {
zwarnnam(name, "incompatible options for -T", NULL, 0);
@ -1669,36 +1678,61 @@ bin_typeset(char *name, char **argv, char *ops, int func)
return 1;
}
if (!(asg = getasg(argv[0])))
return 1;
asg0 = *asg;
if (!(asg = getasg(argv[1])))
return 1;
if (!strcmp(asg0.name, asg->name)) {
zerrnam(name, "can't tie a variable to itself", NULL, 0);
return 1;
}
/*
* Keep the old value of the scalar. We need to do this
* here as if it is already tied to the same array it
* will be unset when we retie the array. This is all
* so that typeset -T is idempotent.
*
* We also need to remember here whether the damn thing is
* exported and pass that along. Isn't the world complicated?
*/
if ((pm = (Param) paramtab->getnode(paramtab, asg0.name))
&& !(pm->flags & PM_UNSET)
&& (locallevel == pm->level || func == BIN_EXPORT)) {
if (!asg0.value && !(PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)))
oldval = ztrdup(getsparam(asg0.name));
on |= (pm->flags & PM_EXPORTED);
}
/*
* Create the tied array; this is normal except that
* it has the PM_TIED flag set. Do it first because
* we need the address.
*/
if (!(asg = getasg(argv[1])))
return 1;
name1 = ztrdup(asg->name);
if (!(apm=typeset_single(name, asg->name,
(Param)paramtab->getnode(paramtab,
asg->name),
func, on | PM_ARRAY, off, roff,
asg->value, NULL)))
func, (on | PM_ARRAY) & ~PM_EXPORTED,
off, roff, asg->value, NULL)))
return 1;
/*
* Create the tied colonarray. We make it as a normal scalar
* and fix up the oddities later.
*/
if (!(asg = getasg(argv[0])) ||
!(pm=typeset_single(name, asg->name,
if (!(pm=typeset_single(name, asg0.name,
(Param)paramtab->getnode(paramtab,
asg->name),
func, on, off, roff, asg->value, apm))) {
asg0.name),
func, on, off, roff, asg0.value, apm))) {
if (oldval)
zsfree(oldval);
unsetparam_pm(apm, 1, 1);
return 1;
}
pm->ename = name1;
apm->ename = ztrdup(asg->name);
pm->ename = ztrdup(asg->name);
apm->ename = ztrdup(asg0.name);
if (oldval)
setsparam(asg0.name, oldval);
return 0;
}
@ -1928,14 +1962,39 @@ bin_unset(char *name, char **argv, char *ops, int func)
/* do not glob -- unset the given parameter */
while ((s = *argv++)) {
char *ss = strchr(s, '[');
char *sse = ss;
if (ss) {
if (skipparens('[', ']', &sse) || *sse) {
zerrnam(name, "%s: invalid parameter name", s, 0);
returnval = 1;
continue;
}
*ss = 0;
}
pm = (Param) paramtab->getnode(paramtab, s);
if (!pm)
returnval = 1;
else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
zerrnam(name, "%s: restricted", pm->nam, 0);
returnval = 1;
} else if (ss) {
if (PM_TYPE(pm->flags) == PM_HASHED) {
HashTable tht = paramtab;
if ((paramtab = pm->gets.hfn(pm))) {
*--sse = 0;
unsetparam(ss+1);
*sse = ']';
}
paramtab = tht;
} else {
zerrnam(name, "%s: invalid element for unset", s, 0);
returnval = 1;
}
} else
unsetparam(s);
unsetparam_pm(pm, 0, 1);
if (ss)
*ss = '[';
}
return returnval;
}

View file

@ -111,12 +111,17 @@ zgetdir(struct dirsav *d)
{
char nbuf[PATH_MAX+3];
char *buf;
int bufsiz, pos, len;
int bufsiz, pos;
struct stat sbuf;
ino_t pino;
dev_t pdev;
#ifndef __CYGWIN__
struct dirent *de;
DIR *dir;
ino_t ino, pino;
dev_t dev, pdev;
dev_t dev;
ino_t ino;
int len;
#endif
buf = halloc(bufsiz = PATH_MAX);
pos = bufsiz - 1;
@ -137,6 +142,7 @@ zgetdir(struct dirsav *d)
#ifdef HAVE_FCHDIR
else
#endif
#ifndef __CYGWIN__
holdintr();
for (;;) {
@ -221,6 +227,21 @@ zgetdir(struct dirsav *d)
if (*buf)
zchdir(buf + pos + 1);
noholdintr();
#else /* __CYGWIN__ case */
if (!getcwd(buf, bufsiz)) {
if (d) {
return NULL;
}
} else {
if (d) {
return d->dirname = ztrdup(buf);
}
return buf;
}
#endif
buf[0] = '.';
buf[1] = '\0';
return buf;

View file

@ -148,6 +148,7 @@ parse_string(char *s)
return l;
}
/**/
#ifdef HAVE_GETRLIMIT
/* the resource limits for the shell and its children */
@ -184,6 +185,7 @@ setlimits(char *nam)
return ret;
}
/**/
#endif /* HAVE_GETRLIMIT */
/* fork and set limits */

View file

@ -1432,7 +1432,7 @@ glob(LinkList list, LinkNode np)
}
}
break;
case 'o':
case 'f':
/* Match modes with chmod-spec. */
func = qualmodeflags;
data = qgetmodespec(&s);
@ -1501,6 +1501,7 @@ glob(LinkList list, LinkNode np)
data = qgetnum(&s);
break;
case 'o':
case 'O':
{
int t;
@ -1524,7 +1525,7 @@ glob(LinkList list, LinkNode np)
}
gf_sorts |= t;
gf_sortlist[gf_nsorts++] = t |
((sense & 1) ? GS_DESC : 0);
(((sense & 1) ^ (s[-1] == 'O')) ? GS_DESC : 0);
s++;
break;
}

View file

@ -28,11 +28,12 @@
*/
#include "zsh.mdh"
#include "init.pro"
#include "zshpaths.h"
#include "zshxmods.h"
#include "init.pro"
/**/
int noexitct = 0;
@ -300,22 +301,19 @@ init_io(void)
/* Make sure the tty is opened read/write. */
if (isatty(0)) {
#ifdef TIOCNXCL
/*
* See if the terminal claims to be busy. If so, and fd 0
* is a terminal, try and set non-exclusive use for that.
* This is something to do with Solaris over-cleverness.
*/
int tmpfd;
if ((tmpfd = open("/dev/tty", O_RDWR | O_NOCTTY)) < 0) {
if (errno == EBUSY)
ioctl(0, TIOCNXCL, 0);
} else
close(tmpfd);
#endif
zsfree(ttystrname);
if ((ttystrname = ztrdup(ttyname(0))))
if ((ttystrname = ztrdup(ttyname(0)))) {
SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY));
#ifdef TIOCNXCL
/*
* See if the terminal claims to be busy. If so, and fd 0
* is a terminal, try and set non-exclusive use for that.
* This is something to do with Solaris over-cleverness.
*/
if (SHTTY == -1 && errno == EBUSY)
ioctl(0, TIOCNXCL, 0);
#endif
}
/*
* xterm, rxvt and probably all terminal emulators except
* dtterm on Solaris 2.6 & 7 have a bug. Applications are
@ -936,6 +934,7 @@ noop_function_int(int nothing)
/* do nothing */
}
/**/
# ifdef UNLINKED_XMOD_zle
/**/
@ -947,6 +946,7 @@ autoload_zleread(char *lp, char *rp, int ha)
return zleread(lp, rp, ha);
}
/**/
# endif /* UNLINKED_XMOD_zle */
/**/

View file

@ -40,6 +40,13 @@ BEGIN {
aborting = 1
exit 1
}
if (line == "" && $0 ~ /^[ \t]*#/) {
# Directly after the /**/ was a preprocessor line.
# Spit it out and re-start the outer loop.
printf "%s\n", $0
locals = locals $0 "\n"
next
}
gsub(/\t/, " ")
line = line " " $0
gsub(/\/\*([^*]|\*+[^*\/])*\*+\//, " ", line)

View file

@ -90,6 +90,7 @@ static struct optname optns[] = {
{NULL, "badpattern", OPT_EMULATE|OPT_NONBOURNE, BADPATTERN},
{NULL, "banghist", OPT_EMULATE|OPT_NONBOURNE, BANGHIST},
{NULL, "bareglobqual", OPT_EMULATE|OPT_ZSH, BAREGLOBQUAL},
{NULL, "bashautolist", 0, BASHAUTOLIST},
{NULL, "beep", OPT_ALL, BEEP},
{NULL, "bgnice", OPT_EMULATE|OPT_NONBOURNE, BGNICE},
{NULL, "braceccl", 0, BRACECCL},

View file

@ -1500,7 +1500,7 @@ setsparam(char *s, char *val)
} else {
if (!(v = getvalue(&s, 1)))
createparam(t, PM_SCALAR);
else if (PM_TYPE(v->pm->flags) == PM_ARRAY &&
else if ((PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
!(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) {
unsetparam(t);
createparam(t, PM_SCALAR);

View file

@ -718,10 +718,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
int copied = 0;
int arrasg = 0;
int eval = 0;
int aspar = 0;
int nojoin = 0;
char inbrace = 0; /* != 0 means ${...}, otherwise $... */
char hkeys = 0;
char hvals = 0;
int subexp;
*s++ = '\0';
if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@ -813,6 +815,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
case 'e':
eval = 1;
break;
case 'P':
aspar = 1;
break;
case 'c':
whichlen = 1;
@ -949,7 +954,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
} else
globsubst = 1;
} else if (*s == '+') {
if (iident(s[1]))
if (iident(s[1]) || (aspar && isstring(s[1]) &&
(s[2] == Inbrace || s[2] == Inpar)))
chkset = 1, s++;
else if (!inbrace) {
*aptr = '$';
@ -965,7 +971,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
globsubst = globsubst && !qt;
idbeg = s;
if (s[-1] && isstring(*s) && (s[1] == Inbrace || s[1] == Inpar)) {
if ((subexp = (s[-1] && isstring(*s) &&
(s[1] == Inbrace || s[1] == Inpar)))) {
int sav;
int quoted = *s == Qstring;
@ -973,17 +980,28 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
skipparens(*s, *s == Inpar ? Outpar : Outbrace, &s);
sav = *s;
*s = 0;
if (multsub(&val, &aval, &isarr, NULL) && quoted) {
if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) {
isarr = -1;
aval = alloc(sizeof(char *));
}
aspar = 0;
} else if (aspar)
idbeg = val;
if (isarr)
isarr = -1;
copied = 1;
*s = sav;
v = (Value) NULL;
} else {
if (!(v = fetchvalue(&s, (wantt ? -1 :
} else if (aspar) {
if ((v = getvalue(&s, 1))) {
val = idbeg = getstrvalue(v);
subexp = 1;
} else
vunset = 1;
}
if (!subexp || aspar) {
char *ov = val;
if (!(v = fetchvalue((subexp ? &ov : &s), (wantt ? -1 :
((unset(KSHARRAYS) || inbrace) ? 1 : -1)),
hkeys|hvals)))
vunset = 1;
@ -1690,6 +1708,7 @@ modify(char **str, char **ptr)
case 't':
case 'l':
case 'u':
case 'q':
c = **ptr;
break;
@ -1808,6 +1827,9 @@ modify(char **str, char **ptr)
if (hsubl && hsubr)
subst(&copy, hsubl, hsubr, gbal);
break;
case 'q':
copy = bslashquote(copy, NULL, NULL, NULL, 0);
break;
}
tc = *tt;
*tt = '\0';
@ -1859,6 +1881,9 @@ modify(char **str, char **ptr)
}
}
break;
case 'q':
*str = bslashquote(*str, NULL, NULL, NULL, 0);
break;
}
}
if (rec < 0) {

View file

@ -446,7 +446,8 @@ finddir_scan(HashNode hn, int flags)
{
Nameddir nd = (Nameddir) hn;
if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full)) {
if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full)
&& !(nd->flags & ND_NOABBREV)) {
finddir_last=nd;
finddir_best=nd->diff;
}
@ -514,9 +515,8 @@ adduserdir(char *s, char *t, int flags, int always)
* with always==0. Unless the AUTO_NAME_DIRS option is set, we *
* don't let such assignments actually create directory names. *
* Instead, a reference to the parameter as a directory name can *
* cause the actual creation of the hash table entry. Never hash *
* PWD unless it was explicitly requested (or already hashed). */
if (!always && (unset(AUTONAMEDIRS) || !strcmp(s, "PWD")) &&
* cause the actual creation of the hash table entry. */
if (!always && unset(AUTONAMEDIRS) &&
!nameddirtab->getnode2(nameddirtab, s))
return;
@ -534,6 +534,9 @@ adduserdir(char *s, char *t, int flags, int always)
nd = (Nameddir) zcalloc(sizeof *nd);
nd->flags = flags;
nd->dir = ztrdup(t);
/* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */
if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD"))
nd->flags |= ND_NOABBREV;
nameddirtab->addnode(nameddirtab, ztrdup(s), nd);
}
@ -1150,11 +1153,24 @@ checkrmall(char *s)
return (getquery("ny", 1) == 'y');
}
/**/
int
read1char(void)
{
char c;
while (read(SHTTY, &c, 1) != 1) {
if (errno != EINTR)
return -1;
}
return STOUC(c);
}
/**/
int
getquery(char *valid_chars, int purge)
{
char c, d;
int c, d;
int isem = !strcmp(term, "emacs");
#ifdef FIONREAD
@ -1177,7 +1193,7 @@ getquery(char *valid_chars, int purge)
return 'n';
}
#endif
while (read(SHTTY, &c, 1) == 1) {
while ((c = read1char()) >= 0) {
if (c == 'Y' || c == '\t')
c = 'y';
else if (c == 'N')
@ -1199,13 +1215,13 @@ getquery(char *valid_chars, int purge)
}
if (isem) {
if (c != '\n')
while (read(SHTTY, &d, 1) == 1 && d != '\n');
while ((d = read1char()) >= 0 && d != '\n');
} else {
settyinfo(&shttyinfo);
if (c != '\n' && !valid_chars)
write(SHTTY, "\n", 1);
}
return (int)c;
return c;
}
static int d;
@ -3109,6 +3125,73 @@ hasspecial(char const *s)
return 0;
}
/* Quote the string s and return the result. If e is non-zero, the *
* pointer it points to may point to a position in s and in e the position *
* of the corresponding character in the quoted string is returned. Like *
* e, te may point to a position in the string and pl is used to return *
* the position of the character pointed to by te in the quoted string. *
* The last argument should be zero if this is to be used outside a string, *
* one if it is to be quoted for the inside of a single quoted string, and *
* two if it is for the inside of double quoted string. *
* The string may be metafied and contain tokens. */
/**/
char *
bslashquote(const char *s, char **e, char *te, int *pl, int instring)
{
const char *u, *tt;
char *v, buf[PATH_MAX * 2];
int sf = 0;
tt = v = buf;
u = s;
for (; *u; u++) {
if (e && *e == u)
*e = v, sf |= 1;
if (te == u)
*pl = v - tt, sf |= 2;
if (ispecial(*u) &&
(!instring || (isset(BANGHIST) &&
*u == (char)bangchar) ||
(instring == 2 &&
(*u == '$' || *u == '`' || *u == '\"')) ||
(instring == 1 && *u == '\''))) {
if (*u == '\n' || (instring == 1 && *u == '\'')) {
if (unset(RCQUOTES)) {
*v++ = '\'';
if (*u == '\'')
*v++ = '\\';
*v++ = *u;
*v++ = '\'';
} else if (*u == '\n')
*v++ = '"', *v++ = '\n', *v++ = '"';
else
*v++ = '\'', *v++ = '\'';
continue;
} else
*v++ = '\\';
}
if(*u == Meta)
*v++ = *u++;
*v++ = *u;
}
*v = '\0';
if (strcmp(buf, s))
tt = dupstring(buf);
else
tt = s;
v += tt - buf;
if (e && (sf & 1))
*e += tt - buf;
if (e && *e == u)
*e = v;
if (te == u)
*pl = v - tt;
return (char *) tt;
}
/* Unmetafy and output a string, quoted if it contains special characters. */
/**/
@ -3349,12 +3432,19 @@ getkeystring(char *s, int *len, int fromwhere, int *misc)
case Meta:
*t++ = '\\', s--;
break;
case '-':
if (fromwhere == 5) {
*misc = 1;
break;
}
goto def;
case 'c':
if (fromwhere < 2) {
*misc = 1;
break;
}
default:
def:
if ((idigit(*s) && *s < '8') || *s == 'x') {
if (!fromwhere) {
if (*s == '0')
@ -3386,7 +3476,7 @@ getkeystring(char *s, int *len, int fromwhere, int *misc)
} else if (fromwhere == 4 && *s == Snull) {
for (u = t; (*u++ = *s++););
return t + 1;
} else if (*s == '^' && fromwhere == 2) {
} else if (*s == '^' && (fromwhere == 2 || fromwhere == 5)) {
control = 1;
continue;
} else if (*s == Meta)

View file

@ -14,6 +14,7 @@ attachtty
bangchar
bin_notavail
breaks
bslashquote
bufstack
builtintab
chline
@ -55,6 +56,7 @@ exlast
expanding
fallback_compctlread
fallback_zleread
fetchvalue
fignore
file_type
filesub
@ -72,6 +74,7 @@ getkeystring
getlinknode
getshfunc
getsparam
getstrvalue
gettempname
glob_pre
glob_suf
@ -228,6 +231,7 @@ ugetnode
uinsertlinknode
unmeta
unmetafy
unsetparam
unsetparam_pm
untokenize
uremnode

View file

@ -963,6 +963,7 @@ struct nameddir {
/* flags for named directories */
/* DISABLED is defined (1<<0) */
#define ND_USERNAME (1<<1) /* nam is actually a username */
#define ND_NOABBREV (1<<2) /* never print as abbrev (PWD or OLDPWD) */
/* flags for controlling printing of hash table nodes */
@ -1056,6 +1057,7 @@ enum {
BADPATTERN,
BANGHIST,
BAREGLOBQUAL,
BASHAUTOLIST,
BEEP,
BGNICE,
BRACECCL,

View file

@ -328,3 +328,66 @@ Me: fix for unsetting special zle variables, 5111
Drazen Kacar, modified by me: unlock terminal device on Solaris, 5118
(5117 was wrong)
pws-7
Me: patch for zls, 5054 (appeared in pws-6 but not in corresponding
patchlist).
Bart: finally added missing hunk from 4965 which allowed unsetting an
assoc array when it was assigned to as a scalar which should have been
there all along
Bart: vared to edit associative arrays and array elements, 5129
Matt Armstrong: makepro.awk can spit out preprocessor lines, 5132
(+ move init.pro inclusion, 5151)
Matt: cygwin needs to use native getcwd(), 5133
Sven: partial word completion fix, 5144
Sven: compadd -m, -F, -r, 5145, 5204
Bart: unset can unset assoc array elements, 5174
Sven: fix for command completion and pattern completions, 5178
Sven: ${(P)...} 5183, 5199, 5200
Me: compctl documentation tidy-up, 5185, 5198
Sven: zle commands which use the minibuffer erase completion listings,
5201
Sven: glob qualifiers o -> f, O -> o, new O = ^o, 5203
Sven: completion in arrays, 5206
Sven: new completion in conditions, 5207
Sven: ${foo:q}, 5208, preliminary
Sven: use ${foo:q} for quoting prefix and suffix in new completion, 5120
Me: bashautolist option, 5229; Sven's addition, 5234, and doc 5235; 5269
Me: .zlogout doc, 5233
Me: added note on Linux Alpha with egcs to Etc/MACHINES, not posted
Me: typeset -T fix, 5247
Bart: parameter scoping docs, 5258
Bart: new mailing lists in Meta-FAQ, 5260
Sven: GLOB_COMPLETE docs, 5261, 5268
Sven: compctl -M and REC_EXACT fixes, 5262
Sven: rewrite of $foo:q, 5265
Sven: get matcher number in new completion function, 5266
Me: interrupts in getquery() weren't gracefully handled, 5281