From 53d36e795b26a945048e7a87a1a91224f8e1663a Mon Sep 17 00:00:00 2001 From: Tanaka Akira Date: Sun, 2 May 1999 15:19:50 +0000 Subject: zsh-3.1.5-pws-17 --- Completion/Builtins/_stat | 10 ++ Completion/Core/.distfiles | 7 +- Completion/Core/_closequotes | 11 ++ Completion/Core/_menu | 21 +++ Completion/Core/_multi_parts | 3 +- Completion/Core/_oldlist | 29 ++++ Completion/Core/_path_files | 17 +-- Completion/Core/compinstall | 216 ++++++++++++++++++++++++++++++ Completion/User/_make | 2 +- Config/version.mk | 4 +- Doc/Zsh/builtins.yo | 10 +- Doc/Zsh/compsys.yo | 47 +++++++ Doc/Zsh/compwid.yo | 15 ++- Doc/Zsh/expn.yo | 8 +- Doc/Zsh/options.yo | 2 +- Doc/Zsh/redirect.yo | 2 +- Src/Modules/example.c | 39 +++++- Src/Modules/example.mdd | 1 + Src/Modules/zftp.c | 3 + Src/Zle/comp.h | 30 ++++- Src/Zle/comp1.c | 8 +- Src/Zle/comp1.export | 1 + Src/Zle/compctl.c | 86 ++++++------ Src/Zle/compctl.mdd | 2 +- Src/Zle/zle_main.c | 14 +- Src/Zle/zle_misc.c | 10 +- Src/Zle/zle_refresh.c | 17 ++- Src/Zle/zle_tricky.c | 306 +++++++++++++++++++++++++++---------------- Src/builtin.c | 14 +- Src/glob.c | 8 +- Src/mkbltnmlst.sh | 5 +- Src/mkmakemod.sh | 3 +- Src/module.c | 160 +++++++++++++++++++++- Src/params.c | 42 +++++- Src/prompt.c | 19 ++- Src/zsh.export | 2 + Src/zsh.h | 24 ++++ Util/zsh-development-guide | 75 ++++++++++- patchlist.txt | 51 +++++++- 39 files changed, 1103 insertions(+), 221 deletions(-) create mode 100644 Completion/Builtins/_stat create mode 100644 Completion/Core/_closequotes create mode 100644 Completion/Core/_menu create mode 100644 Completion/Core/_oldlist create mode 100644 Completion/Core/compinstall diff --git a/Completion/Builtins/_stat b/Completion/Builtins/_stat new file mode 100644 index 000000000..3cdbb2618 --- /dev/null +++ b/Completion/Builtins/_stat @@ -0,0 +1,10 @@ +#compdef stat + +if [[ "$words[CURRENT-1]" = -[AH] ]]; then + compgen -A +else + [[ "$PREFIX[1]" = + ]] && + compadd - +device +inode +mode +nlink +uid +gid +rdev +size \ + +atime +mtime +ctime +blksize +block +link + _files +fi diff --git a/Completion/Core/.distfiles b/Completion/Core/.distfiles index 6babe9701..9a9e87d7c 100644 --- a/Completion/Core/.distfiles +++ b/Completion/Core/.distfiles @@ -1,6 +1,7 @@ DISTFILES_SRC=' .distfiles - _approximate _compalso _complete _correct _expand _files _list - _main_complete _match _multi_parts _normal _options _parameters - _path_files _sep_parts _set_options _unset_options compdump compinit + _approximate _closequotes _compalso _complete _correct _expand _files + _list _main_complete _match _menu _multi_parts _normal _oldlist _options + _parameters _path_files _sep_parts _set_options _unset_options + compdump compinit compinstall ' diff --git a/Completion/Core/_closequotes b/Completion/Core/_closequotes new file mode 100644 index 000000000..2c4b390e5 --- /dev/null +++ b/Completion/Core/_closequotes @@ -0,0 +1,11 @@ +#autoload + +# If the current completion is in quotes, add the closing quote. +# This can clash with some of the more sophisticated forms of completion + +if [[ -n $compstate[quote] && $RBUFFER != *${compstate[quote]}* ]]; then + compstate[restore]='' + ISUFFIX="$ISUFFIX$compstate[quote]" +fi + +return 1 diff --git a/Completion/Core/_menu b/Completion/Core/_menu new file mode 100644 index 000000000..4cbda4e14 --- /dev/null +++ b/Completion/Core/_menu @@ -0,0 +1,21 @@ +#autoload + +# This completer is an example showing how menucompletion can be +# implemented with the new completion system. +# Use this one before the normal _complete completer, as in: +# +# compconf completer=_menu:_complete + +if [[ -n "$compstate[old_list]" ]]; then + + # We have an old list, keep it and insert the next match. + + compstate[old_list]=keep + compstate[insert]=$((compstate[old_insert]+1)) +else + # No old list, make completion insert the first match. + + compstate[insert]=1 +fi + +return 1 diff --git a/Completion/Core/_multi_parts b/Completion/Core/_multi_parts index b49c41e22..392277f94 100644 --- a/Completion/Core/_multi_parts +++ b/Completion/Core/_multi_parts @@ -83,8 +83,7 @@ while true; do else # No exact match, see how many strings match what's on the line. - tmp2=( "${(@)matches%%${sep}*}" ) - compadd -O tmp1 - "$tmp2[@]" + compadd -O tmp1 - "${(@)matches%%${sep}*}" if [[ $#tmp1 -eq 1 ]]; then diff --git a/Completion/Core/_oldlist b/Completion/Core/_oldlist new file mode 100644 index 000000000..f42197695 --- /dev/null +++ b/Completion/Core/_oldlist @@ -0,0 +1,29 @@ +#autoload + +# If this is a listing widget and there is already an old list, +# and either the compconfig key oldlist_list is `always', or it is not `never' +# and the list is not already shown, then use the existing list for listing +# (even if it was generated by another widget). +if [[ -n $compstate[old_list] && $compconfig[oldlist_list] != never && + $WIDGET = *list* && + ( $compconfig[oldlist_list] = always || $compstate[old_list] != shown ) ]] +then + compstate[old_list]=keep + return 0 +fi + +# If this is a completion widget, and we have a completion inserted already, +# and the compconfig key oldlist_menu is not never, then we cycle through the +# existing list (even if it was generated by another widget). +if [[ -n $compstate[old_insert] && $WIDGET = *complete(|-prefix|-word) && + $compconfig[oldlist_menu] != never ]]; then + compstate[old_list]=keep + if [[ $WIDGET = *reverse* ]]; then + compstate[insert]=$(( compstate[old_insert] - 1 )) + else + compstate[insert]=$(( compstate[old_insert] + 1 )) + fi + return 0 +fi + +return 1 diff --git a/Completion/Core/_path_files b/Completion/Core/_path_files index ed799be84..16666909b 100644 --- a/Completion/Core/_path_files +++ b/Completion/Core/_path_files @@ -230,14 +230,15 @@ for prepath in "$prepaths[@]"; do if [[ -n "$PREFIX$SUFFIX" ]]; then # See which of them match what's on the line. - compadd -O tmp2 "$ignore[@]" - "${(@)tmp1##*/}" + tmp2=("$tmp1[@]") + compadd -D tmp1 "$ignore[@]" - "${(@)tmp1##*/}" # If no file matches, save the expanded path and continue with # the outer loop. - if [[ $#tmp2 -eq 0 ]]; then - if [[ "$tmp1[1]" = */* ]]; then - tmp2=( "${(@)tmp1#${prepath}${realpath}}" ) + if [[ $#tmp1 -eq 0 ]]; then + if [[ "$tmp2[1]" = */* ]]; then + tmp2=( "${(@)tmp2#${prepath}${realpath}}" ) if [[ "$tmp2[1]" = */* ]]; then exppaths=( "$exppaths[@]" ${^tmp2%/*}/${tpre}${tsuf} ) else @@ -246,14 +247,6 @@ for prepath in "$prepaths[@]"; do fi continue 2 fi - - # Remove all files that weren't matched. - - if [[ "$tmp1[1]" = */* ]]; then - tmp1=( "${(@M)tmp1:#*/(${(j:|:)~${(@)tmp2:q}})}" ) - else - tmp1=( "${(@M)tmp1:#(${(j:|:)~${(@)tmp2:q}})}" ) - fi elif (( ! $#tmp1 )); then continue 2 fi diff --git a/Completion/Core/compinstall b/Completion/Core/compinstall new file mode 100644 index 000000000..d96121cf2 --- /dev/null +++ b/Completion/Core/compinstall @@ -0,0 +1,216 @@ +# This script is to be run by a user to setup the new function based +# completion system. The functions themselves are assumed to be already +# available in some directory; they should have been installed with the +# the shell (except we haven't written that yet). +# +# Run it as a script under zsh and answer the questions. +# You can run it as `zsh compinstall $FPATH' and it will be able to check +# your function path for the completion functions. +# +# Normally, this will alter ~/.zshrc (or wherever ZDOTDIR puts it), +# but you can make that unwritable and it will leave the lines in a +# temporary file instead. +# +# You can use this script to modify what compinstall previously +# added to ~/.zshrc. +# +# It is safe to abort with ^C any time you are being prompted for +# information; your .zshrc will not be altered. +# +# To do: +# - Maybe this should be sourced, then it can check the user's current +# setup better. But then there is a potentially horrendous option +# setting/resetting problem. (Maybe we need another way of doing that.) +# - Should probably offer to set different options for _approximate than +# for _complete if both are used. +# - Could add code for setting other completers and options. +# - Could add keys for context-sensitive help. +# - Probably should allow a set of directories to be added to $fpath, +# like Core, Base, etc. + +# In case a startup script changed options +emulate zsh + +[[ -n $1 ]] && FPATH=$1 + +for f in $fpath; do + if [[ $f != . && -f $f/compinit && -f $f/compdump ]]; then + fdir=$f + break + fi +done + +if [[ -z $fdir ]]; then + print "Trying to find where the completion functions are..." + if [[ $0 = */* && -f $0:h/compinit && -f $0:h/compdump ]]; then + fdir=$0:h + else + # more guesses? + print \ +"Please edit the name of the directory where the completion functions are +installed. If they are not installed, you will need to find them in the +Completion/* directories of the zsh distribution and install them yourself, +or insult your system manager for incompetence." + vared -c fdir + while [[ ! -d ${~fdir} || ! -f ${~fdir}/compinit || + ! -f ${~fdir}/compdump ]]; do + print "I can't find them in that directory. Try again or abort." + vared fdir + done + fi + eval "fpath=($fdir \$fpath)" + fdir=${fdir/#$HOME/\~} + lines="fpath=($fdir \$fpath)\n" +else + print "Found completion functions in your fpath, will not alter it." +fi + +files=( ${^~fpath:/.}/_(|*[^~])(N:t) ) +if [[ $#files -lt 20 ]]; then + print " +Hmmm, completion functions seem a bit thin on the ground. There should +be lots of files with names beginning with an underscore (_). You should +look and see what's happened to these. +[Hit return to continue]" + read +fi + +if [[ -w ${~fdir} && ( ! -f ${~fdir}/compinit.dump || + -w ${~fdir}/compinit.dump ) ]] +then + print " +Using standard dumpfile + ${~fdir}/compinit.dump +to speed up initialisation. +[Hit return to continue]" + read +else + print " +I will force completion to dump its status, which will speed up the shell's +start-up considerably. However, I can't write the file I'd like to, namely +$fdir/compinit.dump. Please edit a replacement." + dumpfile='~/.compinit.dump' + vared dumpfile + while ! touch ${~dumpfile} >& /dev/null; do + print "Sorry, I can't write that either. Try again." + vared dumpfile + done + [[ -s $dumpfile ]] || rm -f $dumpfile + dumpfile=" $dumpfile" +fi + +fdir=${fdir/#$HOME/\~} + +lines="${lines}. $fdir/compinit -d$dumpfile\n" + + +print " +In addition to completion, zsh can also perform correction of the +current word, or approximate completion, i.e. completion where the part of +the word typed so far can be corrected; or it can try correction, then +approximate completion if that fails. Would you like: + 0: Just ordinary completion + C: Correction + A: Approximate completion + B: Both? +Please type one of the keys above:" +while read -k type; do + print + case $type in + 0*) completer=_complete + break + ;; + [cC]*) completer=_complete:_correct + break + ;; + [aA]*) completer=_complete:_approximate + break; + ;; + [bB]*) completer=_complete:_correct:_approximate + break + ;; + *) print Try again + ;; + esac +done + +lines="${lines}compconf completer=$completer" + + +if [[ $completer = *(correct|approx)* ]]; then + print " +Correction and approximation will normally allow up to two errors, +and you will be able to use a numeric prefix (e.g. 4) to allow +more. The standard prompt is \`correct to:'. Do you want to change +any of this? [n]" + if read -q; then + print "Number of errors to accept normally (0 is OK):" + read accept + while [[ $accept != <-> ]]; do + read accept"?Please enter a number: " + done + print \ +"How would you like the numeric prefix to be treated: + 0: Not used by correction + U: Used to given the number of errors + I: If present, and not 1, do not perform correction? +Please type one of the keys above:" + while read -k type; do + print + case $type in + 0*) break + ;; + [uU]*) accept="${accept}n" + break + ;; + [Ii]*) accept="${accept}!n" + break + ;; + *) print Try again + ;; + esac + done + lines="$lines \\\\ + correct_accept='$accept'" + print " +Instead of the prompt \`correct to:', you can have no prompt, or a +prompt of your choosing which can display the number of errors found by +containing the string \`%e'. Do you wish to change the correction +prompt? [n]" + if read -q; then + cprompt='' + print "Edit a new prompt (may be empty):" + vared cprompt + lines="$lines \\\\ + correct_prompt='${cprompt//\'/\'\\\'\'}'" + fi + fi +fi + +lines="$lines\n" + + +startline='# The following lines were added by compinstall' +endline='# End of lines added by compinstall' + +ifile=${ZDOTDIR:-~}/.zshrc +[[ -f $ifile ]] || touch $ifile +tmpf=${TMPPPREFIX:-/tmp/zsh}compinstall$$ + +if [[ ! -w $ifile ]]; then + print "\nI can't write to $ifile. I will leave the lines to add in +\`$tmpf' and you must add them by hand." + print "\n$startline\n$lines\n$endline" >$tmpf + return 0 +fi + +if grep $endline $ifile >& /dev/null; then + print -- "$startline\n$lines$endline" >$tmpf + sed -e "/^$endline/r $tmpf +/^$startline/,/^$endline/d" $ifile >${tmpf}2 && mv ${tmpf}2 $ifile && + print "\nSuccesfully modified old compinstall lines in $ifile." + rm -f $tmpf ${tmpf}2 +else + print "\n$startline\n$lines\n$endline" >>$ifile && + print "\nSuccessfully appended lines to $ifile." +fi diff --git a/Completion/User/_make b/Completion/User/_make index acaa56b8e..a30ca4b7a 100644 --- a/Completion/User/_make +++ b/Completion/User/_make @@ -1,3 +1,3 @@ #compdef make gmake pmake -compgen -s "\$(awk '/^[a-zA-Z0-9][^\/ ]+:/ {print \$1}' FS=: [mM]akefile /dev/null)" +compgen -s "\$(awk '/^[a-zA-Z0-9][^\/ ]+:/ {print \$1}' FS=: [mM]akefile /dev/null)" diff --git a/Config/version.mk b/Config/version.mk index a5a52f6c1..be39ecad4 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -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-16 -VERSION_DATE='April 25, 1999' +VERSION=3.1.5-pws-17 +VERSION_DATE='April 30, 1999' diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index ffc9f3cfe..e9bc2ab16 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1175,9 +1175,12 @@ xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) [ var(dep) ... ] ]) xitem(tt(zmodload) tt(-du) var(name) [ var(dep) ... ]) xitem(tt(zmodload) tt(-a) [ tt(-iL) ] [ var(name) [ var(builtin) ... ] ]) xitem(tt(zmodload) tt(-au) [ tt(-i) ] var(builtin) ...) -xitem(tt(zmodload) tt(-c) [ tt(-iI) ] [ var(name) [ var(cond) ... ] ]) +xitem(tt(zmodload) tt(-c) [ tt(-iI) ] var(name) [ var(cond) ... ]) xitem(tt(zmodload) tt(-cu) [ tt(-iI) ] var(cond) ...) -item(tt(zmodload) tt(-c) [ tt(-IL) ])( +xitem(tt(zmodload) tt(-c) [ tt(-IL) ]) +xitem(tt(zmodload) tt(-p) [ tt(-i) ] var(name) [ var(parameter) ... ]) +xitem(tt(zmodload) tt(-pu) [ tt(-i) ] var(parameter) ... ]) +item(tt(zmodload) tt(-p) [ tt(-L) ])( tt(zmodload) performs operations relating to zsh's loadable modules. This feature is not available on all operating systems, or on all installations on a particular operating system. @@ -1253,5 +1256,8 @@ names. Without this option prefix condition names are defined. Together with the tt(-u) option definitions for autoloaded conditions are removed. If given no condition names all defined names are listed (as a series of tt(zmodload) commands if the tt(-L) option is given). + +The tt(-p) option is like the tt(-c) option, but makes tt(zmodload) +work on autoloaded parameters instead of condition codes. ) enditem() diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 159f944c3..cedc4ec8c 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -528,6 +528,53 @@ tt(MENU_COMPLETE) option and does not work with the other menucompletion widgets such as tt(reverse-menu-complete), or tt(accept-and-menu-complete). ) +item(tt(_oldlist))( +This completer controls how the standard completion widgets behave when +there is an existing list of completions which may have been generated by a +special completion (i.e. a separately-bound completion command). It should +appear in the list of completers before any of the widgets which generate +matches. It understands two configuration keys: + +startitem() +item(tt(oldlist_list))( +If this is set to tt(always), then standard widgets which perform listing +will retain the current list of matches, however they were generated. If +it is set to tt(never), this will not be done (the behaviour without the +tt(_oldlist) completer). If it is unset, or any other value, then the +existing list of completions will be displayed if it is not already; +otherwise, the standard completion list will be generated: this is the +default behaviour of tt(_oldlist). + +For example, suppose you type tt(^Xc) to use the tt(_correct_word) +widget, which generates a list of corrections for the word under the +cursor. Usually, typing tt(^D) would generate a standard list of +completions for the word on the command line, and show that. With +tt(_oldlist), it will instead show the list of corrections already +generated. +) +item(tt(oldlist_menu))( +Controls how menu completion behaves when a completion has already been +inserted and the user types a standard completion key type as tt(TAB). +The default behaviour of tt(_oldlist) is that menu completion always +continues with the existing list of completions. If this key is set to +tt(never), however, a new completion is started if the old list was +generated by a different completion command (the behaviour without the +tt(_oldlist) completer). +For example, suppose you type tt(^Xc) to generate a list of corrections, +and menu completion is started in one of the usual ways. Usually, typing +tt(TAB) at this point would start trying to complete the line as it now +appears. With tt(_oldlist), it will instead continue to cycle through the +list of completions. +) +enditem() +) +item(tt(_closequotes))( +When a completion starts in quotes, this completer will recognise the fact +and insert a matching closing quote if there is not already one later on +the line. It should come earlier in the list of completers than any of the +completers which generate matches. It can be confused by some of the more +sophisticated forms of completion. +) enditem() texinode(Completion Functions)()(Control Functions)(Completion System) diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index 34f1140b9..79577d13d 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -140,6 +140,12 @@ with tt(${). ) enditem() ) +item(tt(vared))( +If completion is called while editing a line using the tt(vared) +builtin, the value of this key is set to the name of the parameter +given as argument to tt(vared). If tt(vared) is not currently used, +this key is unset. +) item(tt(parameter))( The name of the parameter when completing in a subscript or in the value of a parameter assignment. @@ -340,7 +346,7 @@ xitem([ tt(-W) var(file-prefix) ]) xitem([ tt(-J) var(name) ] [ tt(-V) var(name) ] [ tt(-X) var(explanation) ]) xitem([ tt(-r) var(remove-chars) ] [ tt(-R) var(remove-func) ]) xitem([ tt(-M) var(match-spec) ] [ tt(-O) var(array) ] [ tt(-A) var(array) ]) -item([ tt(--) ] [ var(words) ... ])( +item([ tt(-D) var(array) ] [ tt(--) ] [ var(words) ... ])( This builtin command can be used to add matches directly and control all the information the completion code stores with each possible @@ -518,6 +524,13 @@ on the command line and the string `tt(foo)' as one of the var(words), this option stores the string `tt(nofoo)' in the array, whereas the tt(-O) option stores the `tt(foo)' originally given. ) +item(tt(-D) var(array))( +As with tt(-O), the var(words) are not added to the set of possible +completions. Instead, the completion code tests every var(word) if +it matches what is on the line. If the var(n)'th var(word) does not +match, the var(n)'th element of the var(array) is removed. Elements +for which the corresponding var(word) is matched are retained. +) item(tt(-), tt(--))( This flag ends the list of flags and options. All arguments after it will be taken as the words to use as matches even if they begin with diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 1dced5b7d..0326e646d 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -361,6 +361,7 @@ the parameter is then substituted. item(tt(${)var(name)tt(:?)var(word)tt(}))( If var(name) is set and is non-null, then substitute its value; otherwise, print var(word) and exit from the shell. +Interactive shells do not exit. If var(word) is omitted, then a standard message is printed. ) item(tt(${)var(name)tt(:PLUS())var(word)tt(}))( @@ -596,11 +597,12 @@ Pad the resulting words on the left. Each word will be truncated if required and placed in a field var(expr) characters wide. The space to the left will be filled with var(string1) (concatenated as often as needed) or spaces if var(string1) is not given. If both -var(string1) and var(string2) are given, this string will be placed -exactly once directly to the left of the resulting word. +var(string1) and var(string2) are given, this string is inserted +once directly to the left of each word, before padding. ) item(tt(r:)var(expr)tt(::)var(string1)tt(::)var(string2)tt(:))( -As tt(l), but pad the words on the right. +As tt(l), but pad the words on the right and insert var(string2) +on the right. ) item(tt(j:)var(string)tt(:))( Join the words of arrays together using var(string) as a separator. diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index c4a8a084e..92de8c2d8 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -670,7 +670,7 @@ tt(trap) and tt(unset). ) pindex(PRINT_EIGHT_BIT) -cindex(exit status, printing) +cindex(eight bit characters, printing) item(tt(PRINT_EIGHT_BIT))( Print eight bit characters literally in completion lists, etc. This option is not necessary if your system correctly returns the diff --git a/Doc/Zsh/redirect.yo b/Doc/Zsh/redirect.yo index 71f03f4cf..b642f1b5f 100644 --- a/Doc/Zsh/redirect.yo +++ b/Doc/Zsh/redirect.yo @@ -180,4 +180,4 @@ the command named in the shell variable tt(READNULLCMD) is assumed. nofill(tt(< file)) -prints the contents of tt(file). +copies the contents of tt(file) to the standard output. diff --git a/Src/Modules/example.c b/Src/Modules/example.c index 95545172f..50b8c1626 100644 --- a/Src/Modules/example.c +++ b/Src/Modules/example.c @@ -30,22 +30,45 @@ #include "example.mdh" #include "example.pro" +/* parameters */ + +static long intparam; +static char *strparam; +static char **arrparam; + + /**/ static int bin_example(char *nam, char **args, char *ops, int func) { unsigned char c; + char **oargs = args, **p = arrparam; + long i = 0; printf("Options: "); for (c = 32; ++c < 128;) if (ops[c]) putchar(c); printf("\nArguments:"); - for (; *args; args++) { + for (; *args; i++, args++) { putchar(' '); fputs(*args, stdout); } printf("\nName: %s\n", nam); + printf("\nInteger Parameter: %ld\n", intparam); + printf("String Parameter: %s\n", strparam ? strparam : ""); + printf("Array Parameter:"); + if (p) + while (*p) printf(" %s", *p++); + printf("\n"); + + intparam = i; + zsfree(strparam); + strparam = ztrdup(*oargs ? *oargs : ""); + freearray(arrparam); + PERMALLOC { + arrparam = arrdup(oargs); + } LASTALLOC; return 0; } @@ -103,6 +126,12 @@ static struct conddef cotab[] = { CONDDEF("ex", CONDF_INFIX, cond_i_ex, 0, 0, 0), }; +static struct paramdef patab[] = { + INTPARAMDEF("exint", &intparam), + STRPARAMDEF("exstr", &strparam), + ARRPARAMDEF("exarr", &arrparam), +}; + static struct funcwrap wrapper[] = { WRAPDEF(ex_wrapper), }; @@ -120,8 +149,15 @@ setup_example(Module m) int boot_example(Module m) { + intparam = 42; + strparam = ztrdup("example"); + arrparam = (char **) zalloc(3 * sizeof(char *)); + arrparam[0] = ztrdup("example"); + arrparam[1] = ztrdup("array"); + arrparam[2] = NULL; return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) | + addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) | !addwrapper(m, wrapper)); } @@ -133,6 +169,7 @@ cleanup_example(Module m) { deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); + deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)); deletewrapper(m, wrapper); return 0; } diff --git a/Src/Modules/example.mdd b/Src/Modules/example.mdd index f2cd50693..5ed55e6f1 100644 --- a/Src/Modules/example.mdd +++ b/Src/Modules/example.mdd @@ -2,5 +2,6 @@ autobins="example" autoinfixconds="ex" autoprefixconds="len" +autoparams="exint exstr exarr" objects="example.o" diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 126aa061e..651a5c952 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -71,6 +71,9 @@ #ifdef HAVE_POLL_H # include #endif +#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM) +# undef HAVE_POLL +#endif /* pinch the definition from for deficient headers */ #ifndef INADDR_NONE diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index c9d6aa859..caeb4d6c3 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -270,6 +270,31 @@ struct cpattern { #define CAF_ALT 4 #define CAF_MATCH 8 +/* Data for compadd and addmatches() */ + +typedef struct cadata *Cadata; + +struct cadata { + char *ipre; /* ignored prefix (-i) */ + char *isuf; /* ignored suffix (-I) */ + char *ppre; /* `path' prefix (-p) */ + char *psuf; /* `path' suffix (-s) */ + char *prpre; /* expanded `path' prefix (-W) */ + char *pre; /* prefix to insert (-P) */ + char *suf; /* suffix to insert (-S) */ + char *group; /* name of the group (-[JV]) */ + char *rems; /* remove suffix on chars... (-r) */ + char *remf; /* function to remove suffix (-R) */ + char *ign; /* ignored suffixes (-F) */ + int flags; /* CMF_* flags (-[fqn]) */ + int aflags; /* CAF_* flags (-[QUa]) */ + Cmatcher match; /* match spec (parsed from -M) */ + char *exp; /* explanation (-X) */ + char *apar; /* array to store matches in (-A) */ + char *opar; /* array to store originals in (-O) */ + char *dpar; /* array to delete non-matches in (-D) */ +}; + /* Flags for special parameters. */ #define CP_WORDS (1 << 0) @@ -306,7 +331,8 @@ struct cpattern { #define CP_TOEND (1 << 28) #define CP_OLDLIST (1 << 29) #define CP_OLDINS (1 << 30) +#define CP_VARED (1 << 31) -#define CP_NUM 31 +#define CP_NUM 32 -#define CP_ALLMASK ((int) ((((unsigned int) 1) << CP_NUM) - 1)) +#define CP_ALLMASK ((unsigned int) 0xffffffff) diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c index fe21b1dfc..c51aad297 100644 --- a/Src/Zle/comp1.c +++ b/Src/Zle/comp1.c @@ -52,7 +52,7 @@ void (*comp_setunsetptr) _((int, int)); /* pointers to functions required by compctl and defined by zle */ /**/ -int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **)); +int (*addmatchesptr) _((Cadata, char **)); /**/ char *(*comp_strptr) _((int *, int *, int)); @@ -129,7 +129,8 @@ char **compwords, *complastprompt, *comptoend, *compoldlist, - *compoldins; + *compoldins, + *compvared; /**/ Param *comppms; @@ -445,7 +446,7 @@ setup_comp1(Module m) compquoting = comprestore = complist = compinsert = compexact = compexactstr = comppatmatch = comppatinsert = compforcelist = complastprompt = comptoend = - compoldlist = compoldins = NULL; + compoldlist = compoldins = compvared = NULL; makecompparamsptr = NULL; comp_setunsetptr = NULL; return 0; @@ -497,6 +498,7 @@ finish_comp1(Module m) zsfree(comptoend); zsfree(compoldlist); zsfree(compoldins); + zsfree(compvared); return 0; } diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export index 4f9fb143d..2dc285d3a 100644 --- a/Src/Zle/comp1.export +++ b/Src/Zle/comp1.export @@ -41,6 +41,7 @@ comp_setunsetptr comp_strptr compsuffix comptoend +compvared compwords freecmatcher freecmlist diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 28c7cb7b7..a06d558e3 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1691,17 +1691,22 @@ bin_compgen(char *name, char **argv, char *ops, int func) static int bin_compadd(char *name, char **argv, char *ops, int func) { - char *p, **sp, *e; - char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL; - char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL; - char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL; - int f = 0, a = CAF_MATCH, dm; + struct cadata dat; + char *p, **sp, *e, *m = NULL; + int dm; Cmatcher match = NULL; if (incompfunc != 1) { zerrnam(name, "can only be called from completion function", NULL, 0); return 1; } + dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = + dat.pre = dat.suf = dat.group = dat.rems = dat.remf = + dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL; + dat.match = NULL; + dat.flags = 0; + dat.aflags = CAF_MATCH; + for (; *argv && **argv == '-'; argv++) { if (!(*argv)[1]) { argv++; @@ -1713,64 +1718,64 @@ bin_compadd(char *name, char **argv, char *ops, int func) dm = 0; switch (*p) { case 'q': - f |= CMF_REMOVE; + dat.flags |= CMF_REMOVE; break; case 'Q': - a |= CAF_QUOTE; + dat.aflags |= CAF_QUOTE; break; case 'f': - f |= CMF_FILE; + dat.flags |= CMF_FILE; break; case 'F': - sp = &ign; + sp = &(dat.ign); e = "string expected after -%c"; break; case 'n': - f |= CMF_NOLIST; + dat.flags |= CMF_NOLIST; break; case 'U': - a &= ~CAF_MATCH; + dat.aflags &= ~CAF_MATCH; break; case 'P': - sp = ⪯ + sp = &(dat.pre); e = "string expected after -%c"; break; case 'S': - sp = &suf; + sp = &(dat.suf); e = "string expected after -%c"; break; case 'J': - sp = &group; + sp = &(dat.group); e = "group name expected after -%c"; break; case 'V': - if (!group) - a |= CAF_NOSORT; - sp = &group; + if (!dat.group) + dat.aflags |= CAF_NOSORT; + sp = &(dat.group); e = "group name expected after -%c"; break; case 'i': - sp = &ipre; + sp = &(dat.ipre); e = "string expected after -%c"; break; case 'I': - sp = &isuf; + sp = &(dat.isuf); e = "string expected after -%c"; break; case 'p': - sp = &ppre; + sp = &(dat.ppre); e = "string expected after -%c"; break; case 's': - sp = &psuf; + sp = &(dat.psuf); e = "string expected after -%c"; break; case 'W': - sp = &prpre; + sp = &(dat.prpre); e = "string expected after -%c"; break; case 'a': - a |= CAF_ALT; + dat.aflags |= CAF_ALT; break; case 'M': sp = &m; @@ -1778,25 +1783,29 @@ bin_compadd(char *name, char **argv, char *ops, int func) dm = 1; break; case 'X': - sp = &expl; + sp = &(dat.exp); e = "string expected after -%c"; break; case 'r': - f |= CMF_REMOVE; - sp = &rs; + dat.flags |= CMF_REMOVE; + sp = &(dat.rems); e = "string expected after -%c"; break; case 'R': - f |= CMF_REMOVE; - sp = &rf; + dat.flags |= CMF_REMOVE; + sp = &(dat.remf); e = "function name expected after -%c"; break; case 'A': - sp = &apar; + sp = &(dat.apar); e = "parameter name expected after -%c"; break; case 'O': - sp = ⦷ + sp = &(dat.opar); + e = "parameter name expected after -%c"; + break; + case 'D': + sp = &(dat.dpar); e = "parameter name expected after -%c"; break; case '-': @@ -1830,12 +1839,11 @@ bin_compadd(char *name, char **argv, char *ops, int func) if (!*argv) return 1; - match = cpcmatcher(match); - a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group, - rs, rf, ign, f, a, match, expl, apar, opar, argv); + dat.match = match = cpcmatcher(match); + dm = addmatchesptr(&dat, argv); freecmatcher(match); - return a; + return dm; } #define CVT_RANGENUM 0 @@ -2165,6 +2173,7 @@ static struct compparam { { "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL }, { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL }, { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL }, + { "vared", PM_SCALAR, VAL(compvared), NULL, NULL }, { NULL, 0, NULL, NULL, NULL } }; @@ -2308,7 +2317,7 @@ compunsetfn(Param pm, int exp) /**/ void -comp_setunset(int set, int unset) +comp_setunset(unsigned int set, unsigned int unset) { Param *p; @@ -2334,11 +2343,11 @@ comp_wrapper(List list, FuncWrap w, char *name) else { char *orest, *opre, *osuf, *oipre, *oisuf, **owords; long ocur; - int unset = 0, m, sm; + unsigned int unset = 0, m, sm; Param *pp; m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | - CP_IPREFIX | CP_RESTORE; + CP_IPREFIX | CP_ISUFFIX | CP_RESTORE; for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) { if ((m & 1) && ((*pp)->flags & PM_UNSET)) unset |= sm; @@ -2373,7 +2382,8 @@ comp_wrapper(List list, FuncWrap w, char *name) } LASTALLOC; comp_setunset(CP_COMPSTATE | (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX | - CP_SUFFIX | CP_IPREFIX | CP_RESTORE)), + CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX | + CP_RESTORE)), unset); } else comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE), diff --git a/Src/Zle/compctl.mdd b/Src/Zle/compctl.mdd index 113eef27e..e7b2cfb68 100644 --- a/Src/Zle/compctl.mdd +++ b/Src/Zle/compctl.mdd @@ -1,6 +1,6 @@ moddeps="comp1" -autobins="compctl complist compadd compset" +autobins="compctl compgen compadd compset" autoprefixconds="prefix suffix between after" diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 4d9c99f87..a5da84b66 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -413,7 +413,6 @@ zleread(char *lp, char *rp, int flags) baud = getiparam("BAUD"); costmult = (baud) ? 3840000L / baud : 0; - tv.tv_sec = 0; #endif /* ZLE doesn't currently work recursively. This is needed in case a * @@ -523,6 +522,7 @@ zleread(char *lp, char *rp, int flags) #ifdef HAVE_SELECT if (baud && !(lastcmd & ZLE_MENUCMP)) { FD_SET(SHTTY, &foofd); + tv.tv_sec = 0; if ((tv.tv_usec = cost * costmult) > 500000) tv.tv_usec = 500000; if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd, @@ -656,14 +656,18 @@ handleprefixes(void) initmodifier(&zmod); } +/* this exports the argument we are currently vared'iting if != NULL */ + +/**/ +char *varedarg; + /* vared: edit (literally) a parameter value */ /**/ static int bin_vared(char *name, char **args, char *ops, int func) { - char *s; - char *t; + char *s, *t, *ova = varedarg; Value v; Param pm = 0; int create = 0; @@ -753,7 +757,9 @@ bin_vared(char *name, char **args, char *ops, int func) PERMALLOC { pushnode(bufstack, ztrdup(s)); } LASTALLOC; + varedarg = *args; t = (char *) zleread(p1, p2, ops['h'] ? ZLRF_HISTORY : 0); + varedarg = ova; if (!t || errflag) { /* error in editing */ errflag = 0; @@ -927,6 +933,8 @@ setup_zle(Module m) /* initialise the keymap system */ init_keymaps(); + varedarg = NULL; + return 0; } diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index e7f1744d5..30c31c358 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -611,7 +611,7 @@ Thingy executenamedcommand(char *prmt) { Thingy cmd; - int len, l = strlen(prmt); + int len, l = strlen(prmt), ols = listshown; char *ptr; char *okeymap = curkeymapname; @@ -629,6 +629,10 @@ executenamedcommand(char *prmt) if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) { statusline = NULL; selectkeymap(okeymap, 1); + if ((listshown = ols)) + showinglist = -2; + else + clearlist = 1; return NULL; } if(cmd == Th(z_clearscreen)) { @@ -669,6 +673,10 @@ executenamedcommand(char *prmt) unrefthingy(r); statusline = NULL; selectkeymap(okeymap, 1); + if ((listshown = ols)) + showinglist = -2; + else + clearlist = 1; return r; } unrefthingy(r); diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 6b0239961..2377b70fa 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -96,6 +96,7 @@ static int more_start, /* more text before start of screen? */ olnct, /* previous number of lines */ ovln, /* previous video cursor position line */ lpromptw, rpromptw, /* prompt widths on screen */ + lpromptwof, /* left prompt width with real end position */ lprompth, /* lines taken up by the prompt */ rprompth, /* right prompt height */ vcs, vln, /* video cursor position column & line */ @@ -141,8 +142,14 @@ resetvideo(void) *obuf[ln] = '\0'; } - countprompt(lpromptbuf, &lpromptw, &lprompth); - countprompt(rpromptbuf, &rpromptw, &rprompth); + countprompt(lpromptbuf, &lpromptwof, &lprompth, 1); + countprompt(rpromptbuf, &rpromptw, &rprompth, 0); + if (lpromptwof != winw) + lpromptw = lpromptwof; + else { + lpromptw = 0; + lprompth++; + } if (lpromptw) { memset(nbuf[0], ' ', lpromptw); @@ -271,7 +278,7 @@ zrefresh(void) clearflag = 0; resetneeded = 1; } - listshown = 0; + listshown = showinglist = 0; } clearlist = 0; @@ -327,7 +334,7 @@ zrefresh(void) vcs = 0; else if (!clearflag && lpromptbuf[0]) { zputs(lpromptbuf, shout); - if (lpromptw == 0 && lprompth == 1) + if (lpromptwof == winw) zputs("\n", shout); /* works with both hasam and !hasam */ } if (clearflag) { @@ -947,7 +954,7 @@ tc_rightcurs(int cl) zputc('\r', shout); tc_upcurs(lprompth - 1); zputs(lpromptbuf, shout); - if (lpromptw == 0 && lprompth == 1) + if (lpromptwof == winw) zputs("\n", shout); /* works with both hasam and !hasam */ } i = lpromptw; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 92b167cfe..8db571d0b 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -87,6 +87,10 @@ static int usemenu, useglob, useexact, useline, uselist; static int oldlist, oldins; +/* Non-zero if we have to redisplay the list of matches. */ + +static int showagain = 0; + /* The match and group number to insert when starting menucompletion. */ static int insmnum, insgnum, insgroup; @@ -555,7 +559,7 @@ acceptandmenucomplete(void) /* These are flags saying if we are completing in the command * * position, in a redirection, or in a parameter expansion. */ -static int lincmd, linredir, ispar, linwhat; +static int lincmd, linredir, ispar, linwhat, linarr; /* The string for the redirection operator. */ @@ -758,10 +762,14 @@ docomplete(int lst) char *s, *ol; int olst = lst, chl = 0, ne = noerrs, ocs; + if (showagain && validlist) + showinglist = -2; + showagain = 0; + /* If we are doing a menu-completion... */ - if (menucmp && lst != COMP_LIST_EXPAND && compwidget && - compwidget == lastcompwidget) { + if (menucmp && lst != COMP_LIST_EXPAND && + (!compwidget || compwidget == lastcompwidget)) { do_menucmp(lst); return; } @@ -872,7 +880,7 @@ docomplete(int lst) } if (lst == COMP_EXPAND_COMPLETE) do { - /* check if there is a parameter expresiion. */ + /* Check if there is a parameter expression. */ for (; *q && *q != String; q++); if (*q == String && q[1] != Inpar && q[1] != Inbrack) { if (*++q == Inbrace) { @@ -1128,7 +1136,7 @@ unmetafy_line(void) static char * get_comp_string(void) { - int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, inarr, ia, parct; + int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct; char *s = NULL, *linptr, *tmp, *p, *tt = NULL; zsfree(brbeg); @@ -1192,7 +1200,7 @@ get_comp_string(void) inpush(dupstrspace((char *) linptr), 0, NULL); strinbeg(); stophist = 2; - i = tt0 = cp = rd = ins = oins = inarr = parct = ia = 0; + i = tt0 = cp = rd = ins = oins = linarr = 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 * @@ -1211,11 +1219,11 @@ get_comp_string(void) linredir = (inredir && !ins); oins = ins; /* Get the next token. */ - if (inarr) + if (linarr) incmdpos = 0; ctxtlex(); if (tok == ENVARRAY) { - inarr = 1; + linarr = 1; zsfree(varname); varname = ztrdup(tokstr); } else if (tok == INPAR) @@ -1224,7 +1232,7 @@ get_comp_string(void) if (parct) parct--; else - inarr = 0; + linarr = 0; } if (inredir) rdstr = tokstrings[tok]; @@ -1267,7 +1275,7 @@ get_comp_string(void) clwpos = i; cp = lincmd; rd = linredir; - ia = inarr; + ia = linarr; if (inwhat == IN_NOTHING && incond) inwhat = IN_COND; } else if (linredir) @@ -1515,12 +1523,53 @@ get_comp_string(void) */ for (i = 0, p = s; *p; p++, i++) { /* careful, ${... is not a brace expansion... - * in fact, if it's got a substitution in it's too - * hard for us anyway. sorry. + * we try to get braces after a parameter expansion right, + * but this may fail sometimes. sorry. */ if (*p == String || *p == Qstring) { - tt = NULL; - break; + if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) { + char *tp = p + 1; + if (skipparens(*tp, (*tp == Inbrace ? Outbrace : + (*tp == Inpar ? Outpar : Outbrack)), + &tp)) { + tt = NULL; + break; + } + i += tp - p; + p = tp; + } else { + char *tp = p + 1; + + for (; *tp == '^' || *tp == Hat || + *tp == '=' || *tp == Equals || + *tp == '~' || *tp == Tilde || + *tp == '#' || *tp == Pound || *tp == '+'; + tp++); + if (*tp == Quest || *tp == Star || *tp == String || + *tp == Qstring || *tp == '?' || *tp == '*' || + *tp == '$' || *tp == '-' || *tp == '!' || + *tp == '@') + p++, i++; + else { + if (idigit(*tp)) + while (idigit(*tp)) + tp++; + else if (iident(*tp)) + while (iident(*tp)) + tp++; + else { + tt = NULL; + break; + } + if (*tp == Inbrace) { + tt = NULL; + break; + } + tp--; + i += tp - p; + p = tp; + } + } } else if (*p == Inbrace) { if (tt) { /* too many inbraces */ @@ -3472,14 +3521,10 @@ set_param(char *name, LinkList l) /**/ int -addmatches(char *ipre, char *isuf, - char *ppre, char *psuf, char *prpre, char *pre, - char *suf, char *group, char *rems, char *remf, char *ign, - int flags, int aflags, Cmatcher match, char *exp, - char *apar, char *opar, char **argv) +addmatches(Cadata dat, char **argv) { char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL; - char **aign = NULL; + char **aign = NULL, **dparr; int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum; int oisalt = 0, isalt, isexact, doadd; Cline lc = NULL; @@ -3487,45 +3532,52 @@ addmatches(char *ipre, char *isuf, struct cmlist mst; Cmlist oms = mstack; Comp cp = NULL; - LinkList aparl = NULL, oparl = NULL; + LinkList aparl = NULL, oparl = NULL, dparl = NULL; /* Switch back to the heap that was used when the completion widget * was invoked. */ SWITCHHEAPS(compheap) { HEAPALLOC { - doadd = (!apar && !opar); - if (apar) + doadd = (!dat->apar && !dat->opar && !dat->dpar); + if (dat->apar) aparl = newlinklist(); - if (opar) + if (dat->opar) oparl = newlinklist(); - if (exp) { + if (dat->dpar) { + if (*(dat->dpar) == '(') + dparr = NULL; + else if ((dparr = get_user_var(dat->dpar)) && !*dparr) + dparr = NULL; + dparl = newlinklist(); + } + if (dat->exp) { expl = (Cexpl) zhalloc(sizeof(struct cexpl)); expl->count = expl->fcount = 0; - expl->str = dupstring(exp); + expl->str = dupstring(dat->exp); } else expl = NULL; /* Store the matcher in our stack of matchers. */ - if (match) { + if (dat->match) { mst.next = mstack; - mst.matcher = match; + mst.matcher = dat->match; mstack = &mst; if (!mnum) - add_bmatchers(match); + add_bmatchers(dat->match); - addlinknode(matchers, match); - match->refc++; + addlinknode(matchers, dat->match); + dat->match->refc++; } if (mnum && (mstack || bmatchers)) update_bmatchers(); /* Get the suffixes to ignore. */ - if (ign) - aign = get_user_var(ign); + if (dat->ign) + aign = get_user_var(dat->ign); /* Get the contents of the completion variables if we have * to perform matching. */ - if (aflags & CAF_MATCH) { + if (dat->aflags & CAF_MATCH) { lipre = dupstring(compiprefix); lisuf = dupstring(compisuffix); lpre = dupstring(compprefix); @@ -3533,8 +3585,8 @@ addmatches(char *ipre, char *isuf, llpl = strlen(lpre); llsl = strlen(lsuf); /* Test if there is an existing -P prefix. */ - if (pre && *pre) { - pl = pfxlen(pre, lpre); + if (dat->pre && *dat->pre) { + pl = pfxlen(dat->pre, lpre); llpl -= pl; lpre += pl; } @@ -3557,79 +3609,76 @@ addmatches(char *ipre, char *isuf, } } /* Now duplicate the strings we have from the command line. */ - if (ipre) - ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre)); + if (dat->ipre) + dat->ipre = (lipre ? dyncat(lipre, dat->ipre) : + dupstring(dat->ipre)); else if (lipre) - ipre = lipre; - if (isuf) - isuf = (lisuf ? dyncat(lisuf, isuf) : dupstring(isuf)); + dat->ipre = lipre; + if (dat->isuf) + dat->isuf = (lisuf ? dyncat(lisuf, dat->isuf) : + dupstring(dat->isuf)); else if (lisuf) - isuf = lisuf; - if (ppre) { - ppre = dupstring(ppre); - lpl = strlen(ppre); + dat->isuf = lisuf; + if (dat->ppre) { + dat->ppre = dupstring(dat->ppre); + lpl = strlen(dat->ppre); } else lpl = 0; - if (psuf) { - psuf = dupstring(psuf); - lsl = strlen(psuf); + if (dat->psuf) { + dat->psuf = dupstring(dat->psuf); + lsl = strlen(dat->psuf); } else lsl = 0; - if (aflags & CAF_MATCH) { - s = ppre ? ppre : ""; - if (llpl <= lpl && strpfx(lpre, s)) { - llpl = 0; + if (dat->aflags & CAF_MATCH) { + s = dat->ppre ? dat->ppre : ""; + if (llpl <= lpl && strpfx(lpre, s)) lpre = ""; - } else if (llpl > lpl && strpfx(s, lpre)) { - llpl -= lpl; + else if (llpl > lpl && strpfx(s, lpre)) lpre += lpl; - } else + else *argv = NULL; - s = psuf ? psuf : ""; - if (llsl <= lsl && strsfx(lsuf, s)) { - llsl = 0; + s = dat->psuf ? dat->psuf : ""; + if (llsl <= lsl && strsfx(lsuf, s)) lsuf = ""; - } else if (llsl > lsl && strsfx(s, lsuf)) { + else if (llsl > lsl && strsfx(s, lsuf)) lsuf[llsl - lsl] = '\0'; - llsl -= lsl; - } else + else *argv = NULL; } if (*argv) { - if (pre) - pre = dupstring(pre); - if (suf) - suf = dupstring(suf); - if (!prpre && (prpre = ppre)) { - singsub(&prpre); - untokenize(prpre); + if (dat->pre) + dat->pre = dupstring(dat->pre); + if (dat->suf) + dat->suf = dupstring(dat->suf); + if (!dat->prpre && (dat->prpre = dat->ppre)) { + singsub(&(dat->prpre)); + untokenize(dat->prpre); } else - prpre = dupstring(prpre); + dat->prpre = dupstring(dat->prpre); /* Select the group in which to store the matches. */ - if (group) { + if (dat->group) { endcmgroup(NULL); - begcmgroup(group, (aflags & CAF_NOSORT)); - if (aflags & CAF_NOSORT) + begcmgroup(dat->group, (dat->aflags & CAF_NOSORT)); + if (dat->aflags & CAF_NOSORT) mgroup->flags |= CGF_NOSORT; } else { endcmgroup(NULL); begcmgroup("default", 0); } /* Select the set of matches. */ - oisalt = (aflags & CAF_ALT); + oisalt = (dat->aflags & CAF_ALT); - if (remf) { - remf = dupstring(remf); - rems = NULL; - } else if (rems) - rems = dupstring(rems); + if (dat->remf) { + dat->remf = dupstring(dat->remf); + dat->rems = NULL; + } else if (dat->rems) + dat->rems = dupstring(dat->rems); /* Probably quote the prefix and suffix for testing. */ - if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) { + if (!cp && (dat->aflags & CAF_MATCH) && + !(dat->aflags & CAF_QUOTE)) { lpre = quotename(lpre, NULL); lsuf = quotename(lsuf, NULL); - llpl = strlen(lpre); - llsl = strlen(lsuf); } } /* Walk through the matches given. */ @@ -3638,7 +3687,7 @@ addmatches(char *ipre, char *isuf, bpl = brpl; bsl = brsl; isalt = oisalt; - if ((!psuf || !*psuf) && aign) { + if ((!dat->psuf || !*(dat->psuf)) && aign) { /* Do the suffix-test. If the match has one of the * suffixes from ign, we put it in the alternate set. */ char **pt = aign; @@ -3649,39 +3698,52 @@ addmatches(char *ipre, char *isuf, && !strcmp(*pt, s + sl - filell)) isalt = 1; - if (isalt && !doadd) + if (isalt && !doadd) { + if (dparr && !*++dparr) + dparr = NULL; continue; + } } - if (!(aflags & CAF_MATCH)) { + if (!(dat->aflags & CAF_MATCH)) { ms = dupstring(s); lc = bld_parts(ms, sl, -1, NULL); isexact = 0; } else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc, - !(aflags & CAF_QUOTE), - &bpl, &bsl, &isexact))) + !(dat->aflags & CAF_QUOTE), + &bpl, &bsl, &isexact))) { + if (dparr && !*++dparr) + dparr = NULL; continue; - + } if (doadd) { - cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, - prpre, ppre, psuf, suf, bpl, bsl, - flags, isexact); - cm->rems = rems; - cm->remf = remf; + cm = add_match_data(isalt, ms, lc, dat->ipre, dat->ipre, + dat->isuf, dat->pre, dat->prpre, + dat->ppre, dat->psuf, dat->suf, + bpl, bsl, dat->flags, isexact); + cm->rems = dat->rems; + cm->remf = dat->remf; } else { - if (apar) + if (dat->apar) addlinknode(aparl, ms); - if (opar) + if (dat->opar) addlinknode(oparl, s); + if (dat->dpar && dparr) { + addlinknode(dparl, *dparr); + if (!*++dparr) + dparr = NULL; + } free_cline(lc); } } compnmatches = mnum; - if (exp) + if (dat->exp) addexpl(); - if (apar) - set_param(apar, aparl); - if (opar) - set_param(opar, oparl); + if (dat->apar) + set_param(dat->apar, aparl); + if (dat->opar) + set_param(dat->opar, oparl); + if (dat->dpar) + set_param(dat->dpar, dparl); } LASTALLOC; } SWITCHBACKHEAPS; @@ -4128,6 +4190,7 @@ docompletion(char *s, int lst, int incmd) (unset(ALWAYSLASTPROMPT) && zmult != 1)) ? "yes" : ""); movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1); + showinglist = 0; /* Make sure we have the completion list and compctl. */ if (makecomplist(s, incmd, lst)) { @@ -4217,14 +4280,22 @@ callcompfunc(char *s, char *fn) if ((list = getshfunc(fn)) != &dummy_list) { char **p, *tmp; - int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; + int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext; + unsigned int set; Param *ocpms = comppms; comppms = (Param *) zalloc(CP_NUM * sizeof(Param)); - set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING | - CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS | - (useglob ? 0 : CP_PATMATCH)); + set = CP_ALLMASK & + ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING | + CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS | + (useglob ? 0 : CP_PATMATCH)); + zsfree(compvared); + if (varedarg) { + compvared = ztrdup(varedarg); + set |= CP_VARED; + } else + compvared = ztrdup(""); if (!*complastprompt) set &= ~CP_LASTPROMPT; zsfree(compcontext); @@ -4257,7 +4328,7 @@ callcompfunc(char *s, char *fn) } else switch (linwhat) { case IN_ENV: - compcontext = "array_value"; + compcontext = (linarr ? "array_value" : "value"); compparameter = varname; set |= CP_PARAMETER; if (!clwpos) { @@ -4551,6 +4622,7 @@ makecomplist(char *s, int incmd, int lst) insmnum = insgnum = 1; insgroup = oldlist = oldins = 0; begcmgroup("default", 0); + menucmp = 0; ccused = newlinklist(); ccstack = newlinklist(); @@ -6717,11 +6789,13 @@ unambig_data(int *cp) return scache; } -/* Insert the given match. This returns the number of characters inserted.*/ +/* Insert the given match. This returns the number of characters inserted. + * scs is used to return the position where a automatically created suffix + * has to be inserted. */ /**/ static int -instmatch(Cmatch m) +instmatch(Cmatch m, int *scs) { int l, r = 0, ocs, a = cs; @@ -6771,6 +6845,7 @@ instmatch(Cmatch m) } else brscs = -1; /* -S suffix */ + *scs = cs; if (m->suf) { inststrlen(m->suf, 1, (l = strlen(m->suf))); r += l; @@ -6842,13 +6917,13 @@ do_ambiguous(void) /* If REC_EXACT and AUTO_MENU are set and what we inserted is an * * exact match, we want menu completion the next time round * - * so we set fromcomp,to ensure that the word on the line is not * + * so we set fromcomp, to ensure that the word on the line is not * * taken as an exact match. Also we remember if we just moved the * * cursor into the word. */ fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) | ((atend && cs != lastend) ? FC_INWORD : 0)); - /* Probably move the cursor to then end. */ + /* Probably move the cursor to the end. */ if (movetoend == 3) cs = lastend; @@ -6907,7 +6982,7 @@ ztat(char *nam, struct stat *buf, int ls) static void do_single(Cmatch m) { - int l, sr = 0; + int l, sr = 0, scs; int havesuff = 0; char *str = m->str, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre; @@ -6937,7 +7012,7 @@ do_single(Cmatch m) foredel(l); /* And then we insert the new string. */ - menulen = instmatch(m); + menulen = instmatch(m, &scs); menuend = cs; cs = menupos + menulen; @@ -6956,6 +7031,7 @@ do_single(Cmatch m) } else { /* There is no user-specified suffix, * * so generate one automagically. */ + cs = scs; if (m->ripre && (m->flags & CMF_PARBR)) { /*{{*/ /* Completing a parameter in braces. Add a removable `}' suffix. */ @@ -7006,6 +7082,8 @@ do_single(Cmatch m) } } } + if (!menuinsc) + cs = menupos + menulen; } /* If completing in a brace expansion... */ if (brbeg) { @@ -7018,7 +7096,7 @@ do_single(Cmatch m) } else if (!menucmp) { /*{{*/ /* Otherwise, add a `,' suffix, and let `}' remove it. */ - cs = menuend; + cs = scs; havesuff = 1; inststrlen(",", 1, 1); menuinsc++; @@ -7492,7 +7570,12 @@ listlist(LinkList l) struct cmgroup dg; Cmgroup am = amatches; int vl = validlist, sm = smatches; + char *oclp = complastprompt; + + if (listshown) + showagain = 1; + complastprompt = ((zmult == 1) == !!isset(ALWAYSLASTPROMPT) ? "yes" : NULL); smatches = 1; validlist = 1; amatches = &dg; @@ -7503,6 +7586,7 @@ listlist(LinkList l) amatches = am; validlist = vl; smatches = sm; + complastprompt = oclp; } /* Expand the history references. */ diff --git a/Src/builtin.c b/Src/builtin.c index c042537f4..9ffcad1b3 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -120,7 +120,7 @@ static struct builtin builtins[] = BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), #ifdef DYNAMIC - BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicI", NULL), + BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicIp", NULL), #endif }; @@ -1485,7 +1485,7 @@ typeset_single(char *cname, char *pname, Param pm, int func, int usepm, tc, keeplocal = 0; /* use the existing pm? */ - usepm = pm && !(pm->flags & PM_UNSET); + usepm = pm && !(pm->flags & (PM_UNSET | PM_AUTOLOAD)); /* Always use an existing pm if special at current locallevel */ if (pm && (pm->flags & PM_SPECIAL) && pm->level == locallevel) @@ -1793,7 +1793,9 @@ bin_typeset(char *name, char **argv, char *ops, int func) continue; } if (!typeset_single(name, asg->name, - (Param)paramtab->getnode(paramtab, asg->name), + (Param) (paramtab == realparamtab ? + gethashnode2(paramtab, asg->name) : + paramtab->getnode(paramtab, asg->name)), func, on, off, roff, asg->value, NULL)) returnval = 1; } @@ -1945,7 +1947,7 @@ bin_unset(char *name, char **argv, char *ops, int func) next = (Param) pm->next; if ((!(pm->flags & PM_RESTRICTED) || unset(RESTRICTED)) && domatch(pm->nam, com, 0)) { - unsetparam(pm->nam); + unsetparam_pm(pm, 0, 1); match++; } } @@ -1974,7 +1976,9 @@ bin_unset(char *name, char **argv, char *ops, int func) } *ss = 0; } - pm = (Param) paramtab->getnode(paramtab, s); + pm = (Param) (paramtab == realparamtab ? + gethashnode2(paramtab, s) : + paramtab->getnode(paramtab, s)); if (!pm) returnval = 1; else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) { diff --git a/Src/glob.c b/Src/glob.c index 47ca1d659..79a86bbef 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -3379,16 +3379,14 @@ tokenize(char *s) *t = Inang; *s = Outang; break; - case '^': - case '#': - case '~': - if (unset(EXTENDEDGLOB)) - break; case '(': case '|': case ')': if (isset(SHGLOB)) break; + case '^': + case '#': + case '~': case '[': case ']': case '*': diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh index b58d1e1dd..c174cbac6 100644 --- a/Src/mkbltnmlst.sh +++ b/Src/mkbltnmlst.sh @@ -24,7 +24,7 @@ for x_mod in $x_mods; do *" $x_mod "*) ;; *) echo "/* non-linked-in known module \`$x_mod' */" eval "loc=\$loc_$x_mod" - unset moddeps autobins autoinfixconds autoprefixconds + unset moddeps autobins autoinfixconds autoprefixconds autoparams . $srcdir/../$loc/${x_mod}.mdd for bin in $autobins; do echo " add_autobin(\"$bin\", \"$x_mod\");" @@ -35,6 +35,9 @@ for x_mod in $x_mods; do for cond in $autoprefixconds; do echo " add_autocond(\"$cond\", 0, \"$x_mod\");" done + for param in $autoparams; do + echo " add_autoparam(\"$param\", \"$x_mod\");" + done for dep in $moddeps; do case $bin_mods in *" $dep "*) diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh index 2f79acbc3..cd92c7f07 100644 --- a/Src/mkmakemod.sh +++ b/Src/mkmakemod.sh @@ -24,6 +24,7 @@ # autoinfixconds infix condition codes defined by the module, for # autoloading (without the leading `-') # autoprefixconds like autoinfixconds, but for prefix condition codes +# autoparams parameters defined by the module, for autoloading # objects .o files making up this module (*must* be defined) # proto .pro files for this module (default generated from $objects) # headers extra headers for this module (default none) @@ -170,7 +171,7 @@ if $first_stage; then for module in $here_modules; do unset moddeps nozshdep alwayslink hasexport - unset autobins autoinfixconds autoprefixconds + unset autobins autoinfixconds autoprefixconds autoparams unset objects proto headers hdrdeps otherincs . $top_srcdir/$the_subdir/${module}.mdd test -n "${moddeps+set}" || moddeps= diff --git a/Src/module.c b/Src/module.c index ff386c630..09f1fd5db 100644 --- a/Src/module.c +++ b/Src/module.c @@ -539,18 +539,24 @@ load_module(char const *name) m = zcalloc(sizeof(*m)); m->nam = ztrdup(name); m->handle = handle; + m->flags |= MOD_SETUP; + PERMALLOC { + node = addlinknode(modules, m); + } LASTALLOC; if (setup_module(m) || init_module(m)) { finish_module(m); + remnode(modules, node); zsfree(m->nam); zfree(m, sizeof(*m)); + m->flags &= ~MOD_SETUP; return NULL; } - PERMALLOC { - addlinknode(modules, m); - } LASTALLOC; + m->flags &= ~MOD_SETUP; return m; } m = (Module) getdata(node); + if (m->flags & MOD_SETUP) + return m; if (m->flags & MOD_UNLOAD) m->flags &= ~MOD_UNLOAD; else if (m->handle) @@ -570,17 +576,22 @@ load_module(char const *name) if (!m->handle) { if (!(m->handle = do_load_module(name))) return NULL; + m->flags |= MOD_SETUP; if (setup_module(m)) { finish_module(m->handle); m->handle = NULL; + m->flags &= ~MOD_SETUP; return NULL; } } + m->flags |= MOD_SETUP; if (init_module(m)) { finish_module(m->handle); m->handle = NULL; + m->flags &= ~MOD_SETUP; return NULL; } + m->flags &= ~MOD_SETUP; return m; } @@ -690,6 +701,8 @@ bin_zmodload(char *nam, char **args, char *ops, int func) return bin_zmodload_auto(nam, args, ops); else if (ops['c'] || ops['C']) return bin_zmodload_cond(nam, args, ops); + else if (ops['p']) + return bin_zmodload_param(nam, args, ops); else return bin_zmodload_load(nam, args, ops); } @@ -888,6 +901,66 @@ bin_zmodload_cond(char *nam, char **args, char *ops) } } +static void +printautoparams(HashNode hn, int lon) +{ + Param pm = (Param) hn; + + if (pm->flags & PM_AUTOLOAD) { + if (lon) + printf("zmodload -p %s %s\n", pm->u.str, pm->nam); + else + printf("%s (%s)\n", pm->nam, pm->u.str); + } +} + +/**/ +static int +bin_zmodload_param(char *nam, char **args, char *ops) +{ + int ret = 0; + + if (ops['u']) { + /* remove autoloaded parameters */ + for (; *args; args++) { + Param pm = (Param) gethashnode2(paramtab, *args); + + if (!pm) { + if (!ops['i']) { + zwarnnam(nam, "%s: no such parameter", *args, 0); + ret = 1; + } + } else if (!(pm->flags & PM_AUTOLOAD)) { + zwarnnam(nam, "%s: parameter is already defined", *args, 0); + ret = 1; + } else + unsetparam_pm(pm, 0, 1); + } + return ret; + } else if (!*args) { + scanhashtable(paramtab, 1, 0, 0, printautoparams, ops['L']); + return 0; + } else { + /* add autoloaded parameters */ + char *modnam; + + modnam = *args++; + if(isset(RESTRICTED) && strchr(modnam, '/')) { + zwarnnam(nam, "%s: restricted", modnam, 0); + return 1; + } + do { + char *pnam = *args ? *args++ : modnam; + if (strchr(pnam, '/')) { + zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam, 0); + ret = 1; + } else + add_autoparam(pnam, modnam); + } while(*args); + return ret; + } +} + /**/ int unload_module(Module m, LinkNode node) @@ -1114,6 +1187,71 @@ addconddefs(char const *nam, Conddef c, int size) return hadf ? hads : 1; } +/* This adds the given parameter definition. The return value is zero on * + * success and 1 on failure. */ + +/**/ +int +addparamdef(Paramdef d) +{ + Param pm; + + if ((pm = (Param) gethashnode2(paramtab, d->name))) + unsetparam_pm(pm, 0, 1); + + if (!(pm = createparam(d->name, d->flags)) && + !(pm = (Param) paramtab->getnode(paramtab, d->name))) + return 1; + + pm->level = 0; + pm->u.data = d->var; + pm->sets.ifn = (void (*)(Param, long)) d->set; + pm->gets.ifn = (long (*)(Param)) d->get; + pm->unsetfn = (void (*)(Param, int)) d->unset; + + return 0; +} + +/* This adds multiple parameter definitions. This is like addbuiltins(). */ + +/**/ +int +addparamdefs(char const *nam, Paramdef d, int size) +{ + int hads = 0, hadf = 0; + + while (size--) { + if (addparamdef(d)) { + zwarnnam(nam, "error when adding parameter `%s'", d->name, 0); + hadf = 1; + } else + hads = 2; + d++; + } + return hadf ? hads : 1; +} + +/* Delete parameters defined. No error checking yet. */ + +/**/ +int +deleteparamdef(Paramdef d) +{ + unsetparam(d->name); + return 0; +} + +/**/ +int +deleteparamdefs(char const *nam, Paramdef d, int size) +{ + while (size--) { + deleteparamdef(d); + d++; + } + return 1; +} + #ifdef DYNAMIC /* This adds a definition for autoloading a module for a condition. */ @@ -1188,4 +1326,20 @@ deleteconddefs(char const *nam, Conddef c, int size) return hadf ? hads : 1; } +/* This adds a definition for autoloading a module for a parameter. */ + +/**/ +void +add_autoparam(char *nam, char *module) +{ + Param pm; + + if ((pm = (Param) gethashnode2(paramtab, nam))) + unsetparam_pm(pm, 0, 1); + + pm = setsparam(ztrdup(nam), ztrdup(module)); + + pm->flags |= PM_AUTOLOAD; +} + #endif diff --git a/Src/params.c b/Src/params.c index dbc6ce8d8..d60f91990 100644 --- a/Src/params.c +++ b/Src/params.c @@ -255,7 +255,11 @@ static Param argvparam; /* hash table containing the parameters */ /**/ -HashTable paramtab; +HashTable paramtab, realparamtab; + +#ifndef DYNAMIC +#define getparamnode gethashnode2 +#endif /* DYNAMIC */ /**/ HashTable @@ -267,8 +271,8 @@ newparamtable(int size, char const *name) ht->emptytable = emptyhashtable; ht->filltable = NULL; ht->addnode = addhashnode; - ht->getnode = gethashnode2; - ht->getnode2 = gethashnode2; + ht->getnode = getparamnode; + ht->getnode2 = getparamnode; ht->removenode = removehashnode; ht->disablenode = NULL; ht->enablenode = NULL; @@ -278,6 +282,25 @@ newparamtable(int size, char const *name) return ht; } +#ifdef DYNAMIC +/**/ +static HashNode +getparamnode(HashTable ht, char *nam) +{ + HashNode hn = gethashnode2(ht, nam); + Param pm = (Param) hn; + + if (pm && pm->u.str && (pm->flags & PM_AUTOLOAD)) { + char *mn = dupstring(pm->u.str); + + if (!load_module(mn)) + return NULL; + hn = gethashnode2(ht, nam); + } + return hn; +} +#endif /* DYNAMIC */ + /* Copy a parameter hash table */ static HashTable outtable; @@ -402,7 +425,7 @@ createparamtable(void) char buf[50], *str, *iname; int num_env; - paramtab = newparamtable(151, "paramtab"); + paramtab = realparamtab = newparamtable(151, "paramtab"); /* Add the special parameters to the hash table */ for (ip = special_params; ip->nam; ip++) @@ -542,7 +565,9 @@ createparam(char *name, int flags) Param pm, oldpm; if (name != nulstring) { - oldpm = (Param) paramtab->getnode(paramtab, name); + oldpm = (Param) (paramtab == realparamtab ? + gethashnode2(paramtab, name) : + paramtab->getnode(paramtab, name)); if (oldpm && oldpm->level == locallevel) { if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) { @@ -2703,6 +2728,8 @@ printparamnode(HashNode hn, int printflags) /* Print the attributes of the parameter */ if (printflags & PRINT_TYPE) { + if (p->flags & PM_AUTOLOAD) + printf("undefined "); if (p->flags & PM_INTEGER) printf("integer "); else if (p->flags & PM_ARRAY) @@ -2736,6 +2763,11 @@ printparamnode(HashNode hn, int printflags) } quotedzputs(p->nam, stdout); + + if (p->flags & PM_AUTOLOAD) { + putchar('\n'); + return; + } if (printflags & PRINT_KV_PAIR) putchar(' '); else diff --git a/Src/prompt.c b/Src/prompt.c index 69823a5e3..ad7cdbc31 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -232,7 +232,7 @@ putpromptchar(int doprint, int endchar) break; case 'l': *bp = '\0'; - countprompt(bufline, &t0, 0); + countprompt(bufline, &t0, 0, 0); if (t0 >= arg) test = 1; break; @@ -678,11 +678,15 @@ putstr(int d) /**/ void -countprompt(char *str, int *wp, int *hp) +countprompt(char *str, int *wp, int *hp, int overf) { int w = 0, h = 1; int s = 1; for(; *str; str++) { + if(w >= columns) { + w = 0; + h++; + } if(*str == Meta) str++; if(*str == Inpar) @@ -694,12 +698,15 @@ countprompt(char *str, int *wp, int *hp) else if(s) { if(*str == '\t') w = (w | 7) + 1; - else if(*str == '\n') - w = columns; - else + else if(*str == '\n') { + w = 0; + h++; + } else w++; } - if(w >= columns) { + } + if(w >= columns) { + if (!overf || w > columns) { w = 0; h++; } diff --git a/Src/zsh.export b/Src/zsh.export index dcee683f6..7f994bf29 100644 --- a/Src/zsh.export +++ b/Src/zsh.export @@ -4,6 +4,7 @@ addbuiltins addconddefs addedx addhashnode +addparamdefs addwrapper arrvargetfn arrvarsetfn @@ -40,6 +41,7 @@ current_limits deletebuiltins deleteconddefs deletehashtable +deleteparamdefs deletewrapper domatch doshfunc diff --git a/Src/zsh.h b/Src/zsh.h index c3c853dfd..1eefc51c1 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -231,6 +231,7 @@ typedef struct hashtable *HashTable; typedef struct reswd *Reswd; typedef struct alias *Alias; typedef struct param *Param; +typedef struct paramdef *Paramdef; typedef struct cmdnam *Cmdnam; typedef struct shfunc *Shfunc; typedef struct funcwrap *FuncWrap; @@ -850,6 +851,7 @@ struct module { #define MOD_BUSY (1<<0) #define MOD_UNLOAD (1<<1) +#define MOD_SETUP (1<<2) /* node used in parameter hash table (paramtab) */ @@ -923,6 +925,7 @@ struct param { #define PM_RESTRICTED (1<<15) /* cannot be changed in restricted mode */ #define PM_UNSET (1<<16) /* has null value */ #define PM_REMOVABLE (1<<17) /* special can be removed from paramtab */ +#define PM_AUTOLOAD (1<<18) /* autoloaded from module */ /* Flags for extracting elements of arrays and associative arrays */ #define SCANPM_WANTVALS (1<<0) @@ -955,6 +958,27 @@ struct param { #define PF_ASSIGN 0x02 /* argument handled like the RHS of foo=bar */ #define PF_SINGLE 0x04 /* single word substitution */ +struct paramdef { + char *name; + int flags; + void *var; + void *set; + void *get; + void *unset; +}; + +#define PARAMDEF(name, flags, var, set, get, unset) \ + { name, flags, (void *) var, (void *) set, (void *) get, (void *) unset } +#define INTPARAMDEF(name, var) \ + { name, PM_INTEGER, (void *) var, (void *) intvarsetfn, \ + (void *) intvargetfn, (void *) stdunsetfn } +#define STRPARAMDEF(name, var) \ + { name, PM_SCALAR, (void *) var, (void *) strvarsetfn, \ + (void *) strvargetfn, (void *) stdunsetfn } +#define ARRPARAMDEF(name, var) \ + { name, PM_ARRAY, (void *) var, (void *) arrvarsetfn, \ + (void *) arrvargetfn, (void *) stdunsetfn } + /* node for named directory hash table (nameddirtab) */ struct nameddir { diff --git a/Util/zsh-development-guide b/Util/zsh-development-guide index f779b17b3..3775f43b7 100644 --- a/Util/zsh-development-guide +++ b/Util/zsh-development-guide @@ -127,6 +127,7 @@ variables: - autoinfixconds infix condition codes defined by the module, for autoloading (without the leading `-') - autoprefixconds like autoinfixconds, but for prefix condition codes + - autoparams parameters defined by the module, for autoloading - objects .o files making up this module (*must* be defined) - proto .pro files for this module (default generated from $objects) - headers extra headers for this module (default none) @@ -137,7 +138,7 @@ Be sure to put the values in quotes. For further enlightenment have a look at the `mkmakemod.sh' script in the Src directory of the distribution. -Modules have to define four functions which will automatically called +Modules have to define four functions which will be called automatically by the zsh core. The first one, named `setup_foo' for a module named `foo', should set up any data needed in the module, at least any data other modules may be interested in. The second one, named `boot_foo', @@ -323,6 +324,78 @@ almost exactly the same as for builtins, using the functions Arguments and return values are the same as for the functions for builtins. +For defining parameters, a module can call `createparam()' directly or +use a table to describe them, e.g.: + + static struct paramdef patab[] = { + PARAMDEF("foo", PM_INTEGER, NULL, get_foo, set_foo, unset_foo), + INTPARAMDEF("exint", &intparam), + STRPARAMDEF("exstr", &strparam), + ARRPARAMDEF("exarr", &arrparam), + }; + +There are four macros used: + + - PARAMDEF() gets as arguments: + - the name of the parameter + - the parameter flags to set for it (from the PM_* flags defined + in zsh.h) + - optionally a pointer to a variable holding the value of the + parameter + - three functions that will be used to get the value of the + parameter, store a value in the parameter, and unset the + parameter + - the other macros provide simple ways to define the most common + types of parameters; they get the name of the parameter and a + pointer to a variable holding the value as arguments; they are + used to define integer-, scalar-, and array-parameters, so the + variables whose addresses are given should be of type `long', + `char *', and `char **', respectively + +For a description of how to write functions for getting or setting the +value of parameters, or how to write a function to unset a parameter, +see the description of the following functions in the `params.c' file: + + - `intvargetfn()' and `intvarsetfn()' for integer parameters + - `strvargetfn()' and `strvarsetfn()' for scalar parameters + - `arrvargetfn()' and `arrvarsetfn()' for array parameters + - `stdunsetfn()' for unsetting parameters + +Note that if one defines parameters using the last two macros (for +scalars and arrays), the variable holding the value should be +initialized to either `NULL' or to a a piece of memory created with +`zalloc()'. But this memory should *not* be freed in the +finish-function of the module because that will be taken care of by +the `deleteparamdefs()' function described below. + +To register the parameters in the zsh core, the function +`addparamdefs()' is called as in: + + /**/ + int + boot_example(Module m) + { + int ret; + + ret = addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) + ... + } + +The arguments and the return value are as for the functions used to +add builtins and condition codes and like these, it should be called +in the boot-function of the module. To remove the parameters defined, +the function `deleteparamdefs()' should be called, again with the same +arguments and the same return value as for the functions to remove +builtins and condition codes: + + /**/ + int + cleanup_example(Module m) + { + deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)); + ... + } + Finally, modules can define wrapper functions. These functions are called whenever a shell function is to be executed. diff --git a/patchlist.txt b/patchlist.txt index 9a07210b6..faeade93b 100644 --- a/patchlist.txt +++ b/patchlist.txt @@ -940,7 +940,7 @@ pws: 6053: compwid.yo Sven: 6056: compwid.yo -Sven: 6058: small changes +Sven: 6058: small changes in _path_files, compinit and documentation Sven: 6060: don't invalidatelist() in zle_main.c before calling completion functions @@ -967,3 +967,52 @@ Tanaka Akira: 6085: _make can hang when no [mM]akefile Tanaka Akira: 6092: _find, bad glob pattern pws: 6101: multi-line prompt ending in '\n' got another newline + + pws-17 + +Geoff: 6104: multi-line prompt fix (6101 backed off) + +Sven: 6105: _make patch whitespace + +Bart: 6106: short documentation fixes in expn.yo, options.yo, redirect.yo + +Sven: 6109: completion in parameter assignment should set context `value' + +Sven: 6113: compadd -D, nuke element in an array for each failed match + +Sven: 6117: position of ignored suffix in inserted match + +pws: 6118: _closequote and _oldlist completers + +Sven: 6119: don't insert word separator before ignored suffix + +Sven: 6121: try harder with braces after a parameter expansion + +Sven: 6124: menu completion wasn't consistent between tabs + +Sven: 6128: completion after an expansion; list after a non-completion list + +Sven: 6129: comments for struct cadata + +Ville Herva: 6131, see 6126: reset tv.tv_sec before select for Linux + +Sven: 6132: compctl.mdd + +Sven: 6133: autoloaded parameters + +Sven: 6150: alwayslastprompt sometimes failed in M-x + +Sven: 6152: compstate[vared] + +Sven: 6153: realparamtab to smooth access to autoloaded parameters + +Bart: 6162: autoloadable parameter code links without dynamic loading + +pws: 6165: globsubst'd foo='~/bin' depended on extendedglob being set + +Sven: 6167: show unloaded parameters as undefined + +Bart: 6171 as rewritten in 6174: old RedHat Linux doesn't have normall +definitions for poll. + +pws: 6180: Completion/Core/compinstall -- cgit 1.4.1