diff options
Diffstat (limited to 'Completion/compinstall')
-rw-r--r-- | Completion/compinstall | 1830 |
1 files changed, 1830 insertions, 0 deletions
diff --git a/Completion/compinstall b/Completion/compinstall new file mode 100644 index 000000000..ebae5bc43 --- /dev/null +++ b/Completion/compinstall @@ -0,0 +1,1830 @@ +emulate -L zsh +setopt extendedglob + +local key +local compcontext=-default- + +__ci_tidyup() { + unfunction -m __ci_\* 2>/dev/null + unfunction compinstall + autoload -U compinstall +} + +__ci_newline() { + read -k \ + key"?${1:---- Hit newline to continue or \`q' to exit without saving --- }" + print + if [[ $key = [qQ] ]]; then + print "compinstall aborted." + __ci_tidyup + return 1 + else + return 0 + fi +} + +typeset startline='# The following lines were added by compinstall' +typeset endline='# End of lines added by compinstall' +typeset ifile line fpath_line compinit_args +typeset -A styles +typeset match mbegin mend warn_unknown warn_old warn_comment +integer lines_found + +# +# Check the user's .zshrc, if any. +# +# This relies on the stuff we find being only minimally edited from +# the stuff we originally saved. A better way of doing this would +# almost certainly be to use the style mechanism directly: save the +# current styles in a variable, delete all styles, read in and evaluate +# any styles found, manipulate styles directly using zstyle, write out +# using zstyle -L, and if necessary restore the original styles. One +# day I may even do that. +# + +__ci_test_ifile() { + [[ -f $1 ]] && grep "$endline" $1 >/dev/null 2>&1 +} + +local foundold=false +if zstyle -s :compinstall filename ifile && + __ci_test_ifile $ifile; then + foundold=true +else + ifile=${ZDOTDIR:-~}/.zshrc + if __ci_test_ifile ${ZDOTDIR:-~}/.compinstall; then + ifile=${ZDOTDIR:-~}/.compinstall + foundold=true + elif __ci_test_ifile $ifile; then + foundold=true + fi +fi + +local newifile=$ifile +if [[ $foundold = true ]]; then + print "I have found completion definitions in $ifile. +If you want me to read these, just hit return. Otherwise, edit the file +name to look for definitions somewhere else, or delete the whole line +in order not to use existing definitions." + vared -ch -p 'file> ' newifile + [[ -z $newifile ]] && foundold=false +else + print "I haven't found any existing completion definitions. +If you have some already defined by compinstall, edit the name of the +file where these can be found. Note that this will only work if they +are exactly the form in which compinstall inserted them. If you leave +the line as it is, or empty, I won't search." + while true; do + vared -ch -p 'file> ' newifile || break + if [[ -n $newifile && $ifile != $newifile ]]; then + if __ci_test_ifile $newifile; then + foundold=true + break + fi + print "I couldn't find any definitions there. Edit a new filename, or +leave the line blank to ignore it." + else + break + fi + done +fi +ifile=$newifile + +if [[ $foundold = true ]]; then + sed -n "/^[ ]*$startline/,/^[ ]*$endline/p" $ifile | + # Use the default read behaviour to handle any continuation lines. + while read line; do + (( lines_found++ )) + if [[ $line = *'$fpath'* ]]; then + fpath_line=$line + if [[ $line != *\) ]]; then + while read -r line; do + fpath_line="$fpath_line +$line" + [[ $line = *\) ]] && break + done + fi + elif [[ $line = (#b)[[:blank:]]#zstyle[[:blank:]]##(\'[^\']#\')\ +[[:blank:]]##([^[:blank:]]##)[[:blank:]]##(*) ]]; then + styles[$match[2]]="${styles[$match[2]]:+${styles[$match[2]]} +}${(Q)match[1]} +${match[3]}" + elif [[ $line = [[:blank:]]#compconf* ]]; then + warn_old=1 + elif [[ $line == $startline || $line == $endline ]]; then + # no-op + elif [[ $line = [[:blank:]]#\#* ]]; then + warn_comment=1 + elif [[ $line = [[:blank:]]#compinit[[:blank:]]##(#b)([^[:blank:]]*) ]] + then + compinit_args=$match[1] + elif [[ $line != [[:blank:]]# && + $line != [[:blank:]]#'autoload -U compinit' && + $line != [[:blank:]]#compinit && + $line != [[:blank:]]#zstyle[[:blank:]]#:compinstall* ]]; then + warn_unknown="${warn_unknown:+$warn_unknown +}$line" + fi + done +fi + +# +# Print warnings about what we found in .zshrc. +# + +if [[ -n $warn_old ]]; then + print "\ +WARNING: your configuration appears to contain commands for the 3.1.6 +configuration system. You will have to reconfigure from scratch and the +existing configuration commands will be overwritten. If you wish to preserve +the old commands, you should quit, copy them somewhere else, then rerun +compinstall. Sorry." +elif [[ -n $warn_unknown ]]; then + print "\ +WARNING: your configuration contains bits not understood by compinstall, +which will not be retained (shown below). If you wish to retain these, you +should quit, copy them somewhere else, and then rerun compinstall. + +$warn_unknown" +elif [[ -n $warn_comment ]]; then + print "All the comments in your configuration section will be lost. +If you want to keep them, you should copy them somewhere else first." +elif (( ! $lines_found )); then + print "Starting a new completion configuration from scratch." + if [[ -n $ifile && ! -d $ifile ]]; then + print -n "This will be " + if [[ ! -f $ifile ]]; then + print "written to the new file $ifile." + elif [[ ! -w $ifile ]]; then + print "written to the file ~/.compinstall for copying to $ifile." + ifile=$HOME/.compinstall + else + print "appended to the file $ifile. It is up to you to ensure +that these lines are actually executed. They will not be if your .zshrc +usually returns before the end." + fi + fi +fi +print "Note that you will be given a chance to save the new setup +somewhere else at the end." + + +__ci_newline || return 1 + + +typeset d compdir subdirs lines + +# +# Make sure we have the completion functions in $fpath. +# + +__ci_set_compdir() { + for d in $*; do + # If we find both the functions more than once, assume the later + # one is the standard set. + if [[ -f $d/compinit && -f $d/compdump ]]; then + compdir=$d + fi + done +} + +__ci_set_compdir $fpath + +if [[ $compdir = */Core && -d $compdir/../Base ]]; then + subdirs=1 + compdir=${compdir:h} +fi + +if [[ -z $compdir ]]; then + # Start up a new zsh and get its default fpath. If some swine has + # tinkered with this in /etc/zshenv we're out of luck. + lines=${(f)"$(zsh -fc 'print -l $ZSH_VERSION $fpath')"} + lines=$lines[1] + shift lines + # If the zsh in that path isn't right, maybe the user's shell is elsewhere. + if [[ $line != $ZSH_VERSION && -x $SHELL ]]; then + lines=${(f)"$($SHELL -fc 'print -l $ZSH_VERSION $fpath' 2>/dev/null)"} + lines=$lines[1] + shift lines + fi + if [[ $line != $ZSH_VERSION ]]; then + print "Hmmm, the zsh in your path is not what's running, nor is \$SHELL. +That's bad. +" + fi + __ci_set_compdir $lines + if [[ -n $compdir ]]; then + print "\ +I've found the completion directories and will add them to your \$fpath, +but they should already be there at shell startup, so something (probably +an unconditional assignment in a startup file) is taking them out. You +might want to check this, although what I'm doing should work." + if [[ -n $fpath_line ]]; then + print "\ + +What's more, there is already an \$fpath assignment in your completion +setup. This gives me cause for concern. I will override this, but don't +be surprised if it doesn't go according to plan. If you have not +initialised completion in this shell, you should do so, then run +compinstall again." + fi + fi + if [[ -n $subdirs ]]; then + fpath_line=($compdir/[A-Z]*) + fpath_line="fpath=($fpath ${(F)fpath_line})" + fi +else + if [[ -n $subdirs ]]; then + print "Completion directories $compdir/* +are already in your \$fpath, good." + else + print "Completion directory $compdir +is already in your \$fpath, good." + fi + if [[ -n $fpath_line ]]; then + print "I shall keep the existing \$fpath=( ... ) assignment." + fi +fi + +if [[ -z $compdir ]]; then + print "\ +The zsh in your path doesn't seem to have completion directories in the +function autoload path (\$fpath). This suggests the shell wasn't installed +for completion. If you want to use it, you will need to locate all the +completion functions yourself and install them in your \$fpath. I will +continue, but don't expect this to have much effect until you do. + +If you are planning to continue using the old compctl system for +completion, compinstall won't do you any good anyway." +fi + +__ci_newline || return 1 + + +# +# Code for changing styles +# + +typeset defcontext=":completion:*" +typeset curcontext=$defcontext + +# +# Utility functions +# + +# +# Get the style $1 for $curcontext into $2. +# +__ci_get_this_style() { + typeset -A tassoc + local style=$1 scalar=$2 + + tassoc=(${(f)styles[$style]}) + eval "$scalar=\${tassoc[\$curcontext]}" +} + +# +# Set the style $1 for $curcontext using scalar $2 for the value for this +# context. If $2 is null, delete the context (this may not be correct for +# all styles). Don't do any extra quotation. +# $2 gives the name of the scalar for symmetry with __ci_get_this_style. +# +__ci_set_this_style() { + local style=$1 scalar=$2 k + typeset -A tassoc + tassoc=(${(f)styles[$style]}) + + if [[ -n ${(P)scalar} ]]; then + tassoc[$curcontext]=${(P)scalar} + else + unset "tassoc[$curcontext]" + fi + + styles[$style]= + for k in ${(ko)tassoc}; do + styles[$style]="${styles[$style]:+$styles[$style] +}$k +${tassoc[$k]}" + done +} + +# +# Functions displaying menus +# + +__ci_change_context() { + clear + print "\ + *** compinstall: change context *** + +The context tells the completion system under what circumstances your +value will be used. It has this form: + :completion:<function-name>:<completer>:<command>:<argument>:<tag> +See the documentation for more detail on each of these components. The +default context \`$defcontext' matches everywhere in completion, unless you +define a more specific pattern which matches the completion context being +used. \`More specific' means either a string instead of a pattern, or a +longer pattern instead of a shorter pattern. + +Edit a new context, or leave the line blank to reset the context to the +default value. Note that you do not require quotes around the context, +which will automatically be added later. Line editing and history are +available. +" + + vared -eh -p 'context> ' curcontext + [[ -z $curcontext ]] && curcontext=$defcontext +} + + +__ci_toggle_completer() { + # used locally within __ci_do_completers + if [[ -n $completers[$1] ]]; then + completers[$1]= + else + completers[$1]=1 + fi +} + +__ci_do_minor_completer_options() { + # Set the options for the minor completers. + local key cond word olist omenu moriginal aspace tmparr + __ci_get_this_style condition cond + [[ -n $cond ]] && cond=${(Q)cond} + __ci_get_this_style word word + __ci_get_this_style old-list olist + __ci_get_this_style old-menu omenu + __ci_get_this_style match-original moriginal + __ci_get_this_style add-space aspace + + while true; do + + # insert-unambiguous can be handled somewhere else. + clear + print "\ + *** compinstall: minor completer options *** + +Current context: $curcontext + +l. Set options for _list: condition for delay and comparison. +o. Set options for _oldlist: when to keep old list. +m. Set options for _match: whether to assume a \`*' at the cursor. +p. Set options for _prefix: whether to add a space before the suffix. + +q. Return to the without saving. +0. Done setting completer options. +" + + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + [lL]) print "\ +You can set a condition under which the _list completer will delay completion +until the second keypress. It should evaluate to a number; a non-zero value +turns this behaviour on. It can include parameters, in particular NUMERIC +to refer to a numeric argument. For example, \`NUMERIC != 1' forces the +delay unless you give an argument 1 to the command. Leave it blank to +assume the condition is true." + vared -eh -c -p 'condition> ' cond + print -n " +_list will usually compare the contents of the entire line with its previous +contents to decided if it has been changed since the last keypress. You +can instead perform this comparison on just the current word, ignoring +the rest of the command line. Do you want to do this? (y/n) [n] " + word= + read -q key && word=true + print + ;; + [oO]) print "\ +_oldlist can keep a generated completion list for reshowing in the usual +way, e.g. with ^D, even if the list was generated by some special completion +command. The default behaviour of _oldlist is to show this list if it was +not already visible, otherwise to generate the standard completion listing, +but you can force it always to be shown, or make it never shown. +Alternatively, you can specify a list of completers for which _oldlist will +be used. Choose: + +d. Default behaviour. +a. Always show old list. +n. Never show old list. +s. Specify a list of completers. +" + + while true; do + read -k key'?--- Hit selection --- ' + print + case $key in + [dD]) olist= + ;; + [aA]) olist=always + ;; + [nN]) olist=never + ;; + [sS]) olist= + tmparr=(_complete _approximate _correct _match _expand) + while true; do + clear + print "\ + *** compinstall: choosing completers to have _oldlist behaviour *** + +Type any of: + +1. _complete +2. _approximate +3. _correct +4. _match +5. _expand + +or 0 to end, or - to delete the last choice." + if [[ -n $olist ]]; then + print "\ +Current choices: + $olist" + fi + read -k key'?--- Hit selection --- ' + print + case $key in + 0) break + ;; + -) olist=(${olist[1,-2]}) + ;; + [1-5]) olist=($olist $tmparr[$key]) + ;; + esac + done + ;; + *) print "Type one of d, a, n or s." + continue + ;; + esac + break + done + + print -n " +_oldlist can keep the old completion list for use in menu completion, e.g. by +repeatedly hitting tab, even if the list was generated by some special +completion command. This is the default behaviour of _oldlist, but +you can turn it off, so that hitting tab would use the standard completion +list. + +Do you want to turn it off? (y/n) [n] " + omenu= + read -q key && omenu=false + ;; + [mM]) print "\ +The _match completer will usually assume there is a \`*' at the cursor +position when trying pattern matches. For example, \`f*n<TAB>e' would +be able to complete to \`filename', not just to patterns matching \`f*ne'. +(Note that this assumes you have the option COMPLETE_IN_WORD set, else all +completion takes place at the end of the word.) You can tell _match not +to assume there is a \`*', or to try first without the \`*', then with it. +Type one of: + +a. Always assume \`*' at cursor position. +n. Never assume \`*' at cursor position. +w. Try without the \`*', then with it if that fails." + while true; do + read -k key'?--- Hit selection --- ' + print + case $key in + a) moriginal= + ;; + n) moriginal=only + ;; + w) moriginal=both + ;; + *) print "Type one of a, n or w." + continue + ;; + esac + break + done + ;; + [pP]) print -n "\ +The _prefix completer completes only what is behind the cursor, ignoring +completely what is after, even if there is no space at the cursor position. +However, you can force it to add a space between the resulting completion +and the part ignored. For example, \`f<TAB>bar' might expand to \`filebar' +without this, and to \`file bar' with it. Do wish _prefix to add the +space? (y/n) [n] " + aspace= + read -q key && aspace=true + ;; + [qQ]) return 1 + ;; + esac + + done + + [[ -n $cond && $cond != [[:alnum:]]## ]] && cond=${(qq)cond} + __ci_set_this_style condition cond + __ci_set_this_style word word + __ci_set_this_style old-list olist + __ci_set_this_style old-menu omenu + __ci_set_this_style match-original moriginal + __ci_set_this_style add-space aspace + + return 0 +} + +__ci_do_minor_completers() { + # Set the minor completers not handled by __ci_do_completers. + # Called within __ci_do_completers, so inherits the environment. + # It's only divided off to keep the menus short. + + local key + + while true; do + + clear + print "\ + *** compinstall: minor completer menu *** + +Current context: $curcontext + +The following completers are available. Those marked \`(*)' are already +set for the context shown above. Note none of these are required for +normal completion behaviour. + +1. ${${completers[_ignored]:+(*)}:- } _ignored: $ckeys[_ignored] +2. ${${completers[_list]:+(*)}:- } _list: $ckeys[_list] +3. ${${completers[_oldlist]:+(*)}:- } _oldlist: $ckeys[_oldlist] +4. ${${completers[_match]:+(*)}:- } _match: $ckeys[_match] +5. ${${completers[_prefix]:+(*)}:- } _prefix: $ckeys[_prefix] + +o. Set options for the completers above. +q. Return without saving. +0. Done setting minor completers. +" + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + 1) __ci_toggle_completer _ignored + if [[ -n $completers[_ignored] ]]; then + print "\ +I am inserting the \`ignored' completer immediately after normal +completion. You can move it later in the list by hand, if you prefer, so +that ignored completions are only used after, for example, approximations. +To do this, edit $ifile, look for the zstyle ... completers line, and +move \`_ignored' to where you want it. This will be retained if you use +compinstall again provided you don't go into the completers menu. +" + # TODO: we could be more careful about keeping the user's + # order, particularly with multiple completers. + read -k key'?--- Hit any key to continue --- ' + print + fi + ;; + 2) __ci_toggle_completer _list + ;; + 3) __ci_toggle_completer _oldlist + ;; + 4) __ci_toggle_completer _match + ;; + 5) __ci_toggle_completer _prefix + ;; + o) __ci_do_minor_completer_options + ;; + q) return 1 + ;; + esac + + done + + return 0 +} + +__ci_do_completer_options() { + # Set options for the main completers; called from __ci_do_completers. + + local maxe errors prompt glob subst compl cond + + __ci_get_this_style max-errors errors + __ci_get_this_style prompt prompt + [[ -n $prompt ]] && prompt=${(Q)prompt} + __ci_get_this_style glob glob + [[ -n $glob ]] && glob=${(Q)glob} + __ci_get_this_style substitute subst + [[ -n $subst ]] && subst=${(Q)subst} + __ci_get_this_style completions compl + [[ -n $compl ]] && compl=${(Q)compl} + + while true; do + + clear + print "\ + *** compinstall: completer options *** + +Current context: $curcontext + +The following options are available. Note that these require the relevant +completers to be present, as set in the menu above this one. + +a. Set options for approximation or correction. +e. Set options for expansion. +q. Return without saving. + +0. Done setting options. +" + + read -k key'?--- Hit selection --- ' + print + + # We handle approximation and correction together to avoid having + # to be too particular about context. + case $key in + a) clear + print "\ +Approximation and correction can correct the errors in what you have typed, +up to a maximum number of errors which you can specify. Each \`error' +is the omission of a character, the addition of a superfluous character, +the substitution of one character by an incorrect one, or transposition of +two different characters. + +Current context: $curcontext + +To have different values for approximation and correction, you should +change the context appropriately. For approximation, use +\`:completion:*:approximate:*' and for correction use +\`:completion:*:correct:*'. + +Enter maximum number of errors allowed: +" + maxe= + while true; do + vared -eh -c -p "number> " maxe + [[ $maxe = [[:digit:]]## ]] && break + print "Please enter a number" + maxe= + done + while true; do + print "\nSelect behaviour of numeric prefix. + +1. Numeric prefix is not used by approximation or completion. +2. Numeric prefix, if provided, gives max number of errors allowed, + replacing the number you just typed for that one completion. +3. Numeric prefix, if provided, prevents approximation or completion + from taking place at all for that one completion. +" + read -k -- key'?--- Hit selection --- ' + print + [[ $key = [123] ]] || continue + case $key in + 2) maxe="$maxe numeric" + ;; + 3) maxe="$maxe not-numeric" + ;; + esac + print " +You can edit a prompt which will appear above lists of corrections. The +string \`%e' inside the prompt will be replaced with the number of errors +found. Leave blank for no prompt. Quotation marks will be added +automatically." + vared -eh -c -p "prompt> " prompt + break + done + errors=$maxe + ;; + e) while true; do + clear + print "\ +The _expand completer can be tuned to perform any of globbing (filename +generation), substitution (anything with a \`\$' or backquote), or +normal completion (which is useful for inserting all possible completions +into the command line). For each feature, a 1 turns it on, while a 0 turns +it off; if the feature is unset, that expansion will *not* be performed. + +You can also give more complicated mathematical expressions, which can use +the parameter NUMERIC to refer to the numeric argument. For example, the +expression \`NUMERIC == 2' means that the expansion takes effect if you +type ESC-2 (Emacs mode) or 2 (Vi command mode) before the expansion. +Quotes will be added automatically as needed. + +g. Set condition to perform globbing: ${glob:-unset} +s. Set condition to perform substitution: ${subst:-unset} +c. Set condition to perform completion: ${compl:-unset} +0. Done setting conditions (will not be saved until you leave options) +" + read -k key'?--- Enter selection --- ' + print + + case $key in + g) vared -eh -c -p 'globbing condition> ' glob + ;; + s) vared -eh -c -p 'substitution condition> ' subst + ;; + c) vared -eh -c -p 'completion condition> ' compl + ;; + esac + + [[ $key = 0 ]] && break + + done + ;; + q) return 1 + ;; + esac + + [[ $key = 0 ]] && break + done + + __ci_set_this_style max-errors errors + [[ -n $prompt ]] && prompt=${(qq)prompt} + __ci_set_this_style prompt prompt + [[ -n $glob && $glob != [[:alnum:]]## ]] && glob=${(qq)glob} + __ci_set_this_style glob glob + [[ -n $subst && $subst != [[:alnum:]]## ]] && subst=${(qq)subst} + __ci_set_this_style substitute subst + [[ -n $compl && $compl != [[:alnum:]]## ]] && compl=${(qq)compl} + __ci_set_this_style completions compl + + key= + return 0 +} + +__ci_do_completers() { + # Set the completers for the current context. + # This is mostly done via a series of toggles. + + typeset -A completers ckeys + local c clist newc + __ci_get_this_style completer newc + for c in ${=newc}; do + completers[$c]=1 + done + clist=(_list _oldlist _menu _expand _complete _ignored + _match _correct _approximate _prefix) + + # TODO: these are a bit brief, so could provide some more detailed help. + ckeys=(_complete 'Basic completion.' + _approximate +'Approximate completion: completion with correction of existing word.' + _correct +'Correction: correct existing word, no completion.' + _expand +'Expansion: use globbing and parameter substitution, if possible.' + + _ignored +'Use patterns that were previously ignored if no matches so far.' + _list +'Only list matches until the second time you hit TAB.' + _oldlist +'Keep matches generated by special completion functions.' + _match +'If completion fails, retry with pattern matching.' + _prefix +'If completion fails, retry ignoring the part after the cursor.' + ) + + # TODO: You'll need to handle the bindkey to make _expand work. + # TODO: _prefix completer should make sure completeinword is set. + + while true; do + + clear + print "\ + *** compinstall: completer menu *** + +Current context: $curcontext + +The following completers are available. Those marked \`(*)' are already +set for the context shown above. If none are selected, the completers will +not be set for this context at all. + +1. ${${completers[_complete]:+(*)}:- } $ckeys[_complete] +2. ${${completers[_approximate]:+(*)}:- } $ckeys[_approximate] +3. ${${completers[_correct]:+(*)}:- } $ckeys[_correct] +4. ${${completers[_expand]:+(*)}:- } $ckeys[_expand] + +o. Set options for the completers above. +m. Set completers that modify the behaviour of the four main ones above. +q. Return without saving. +0. Done setting completers. +" + read -k key'?--- Hit selection --- ' + print + + case $key in + 1) __ci_toggle_completer _complete + ;; + 2) __ci_toggle_completer _approximate + ;; + 3) __ci_toggle_completer _correct + ;; + 4) __ci_toggle_completer _expand + ;; + [mM]) __ci_do_minor_completers || return + continue + ;; + [oO]) __ci_do_completer_options || return + continue + ;; + q) return 1 + ;; + esac + + [[ $key = 0 ]] && break + done + + newc= + for c in $clist; do + [[ -n $completers[$c] ]] && newc="${newc:+$newc }$c" + done + [[ -z $newc ]] && newc="''" + __ci_set_this_style completer newc +} + +__ci_toggle_matcher() { + # Toggle on/off the matcher in array $1 for element $2 + if [[ ${${(P)1}[$2]} = ' ' ]]; then + # toggle on + eval "${1}[$2]=$2" + if [[ $1 = n* ]]; then + # no matcher turned on, turn off the others + c_list[$2]=' ' + C_list[$2]=' ' + p_list[$2]=' ' + s_list[$2]=' ' + else + # something else turned on, turn off no matcher + n_list[$2]=' ' + fi + return 0 + else + # toggle off + eval "${1}[$2]=' '" + if [[ $c_list[$2] == ' ' && $C_list[$2] == ' ' && \ + $p_list[$2] == ' ' && $s_list[$2] == ' ' ]]; then + a_or_r[$2]=' ' + fi + return 1 + fi +} + +__ci_do_matchers() { + # Set matchers via the matcher-list style. + # We just offer a pre-programmed set of possible matchers, but these + # cover the most common usages for matchers in a general context. + # More specific use of matchers is usually covered by completion functions. + + local mlist m_ci m_pw m_sub c_list C_list p_list s_list pw_seps key key2 elt + local pw_dstar a_or_r i + integer eltcnt lastnz + + __ci_get_this_style matcher-list mlist + # $mlist is the once and future list of matchers. We don't quote it + # until the end; the eval effectively does de-quoting. + eval "mlist=($mlist)" + # ?_list say whether the four possible matchers are set for passes 1, + # 2, 3, 4, in an easy-to-read manner, i.e. the Nth part of the string + # is one of N (on) or space (off). + a_or_r=" " # replace by default + n_list=" " # null completion, i.e. standard + c_list=" " # case match one way + C_list=" " # case match both ways + p_list=" " # partial word completion + s_list=" " # substring completion + # $pw_seps gives the separators used for partial-word completion + # by element of the matcher list; these can be edited separately. + pw_seps=('._-' '._-' '._-' '._-') + pw_dstar=('' '' '' '') + + # See what's in the matcher initially. If these have been edited, + # we're in trouble, but that's pretty much true of everything. + for (( eltcnt = 1; eltcnt <= $#mlist; eltcnt++ )); do + [[ $mlist[eltcnt] == "+"* ]] && a_or_r[$eltcnt]='+' + [[ -z $mlist[$eltcnt] ]] && n_list[$eltcnt]=$eltcnt + [[ $mlist[$eltcnt] = *"m:{a-z}={A-Z}"* ]] && c_list[$eltcnt]=$eltcnt + [[ $mlist[$eltcnt] = *"m:{a-zA-Z}={A-Za-z}"* ]] && C_list[$eltcnt]=$eltcnt + # For partial word stuff, we use backreferences to find out what + # the set of separators was. + if [[ $mlist[$eltcnt] = (#b)*"r:|["([^\]]#)"]=*"#" r:|=*"* ]]; then + p_list[$eltcnt]=$eltcnt + pw_seps[$eltcnt]=${match[1]} + [[ $mlist[$eltcnt] = *"=**"* ]] && pw_dstar[$eltcnt]='*' + fi + # Just look for the left matcher for substring, since the right matcher + # might have been handled as part of a partial-word spec. + [[ $mlist[$eltcnt] = *"l:|=*"* ]] && s_list[$eltcnt]=$eltcnt + done + + while true; do + clear + print "\ + *** compinstall: matcher menu *** + +\`Matchers' compare the completion code with the possible matches in some +special way. Numbers in parentheses show matchers to be tried and the order. +The same number can be assigned to different matchers, meaning apply at the +same time. Omit a sequence number to try normal matching at that point. +A \`+' in the first line indicates the element is added to preceding matchers +instead of replacing them; toggle this with \`t'. You don't need to set +all four, or indeed any matchers --- then the style will not be set. + + ($a_or_r)\ + \`+' indicates add to previous matchers, else replace +n. ($n_list)\ + No matchers; you may want to try this as the first choice. +c. ($c_list)\ + Case-insensitive completion (lowercase matches uppercase) +C. ($C_list)\ + Case-insensitive completion (lower/uppercase match each other) +p. ($p_list)\ + Partial-word completion: expand 'f.b' to 'foo.bar', etc., in one go. + You can choose the separators (here \`.') used each time. +s. ($s_list)\ + Substring completion: complete on substrings, not just initial + strings. Warning: it is recommended this not be used for element 1. + +t. Toggle replacing previous matchers (\` ' at top) or add (\`+') +q. Return without saving. +0. Done setting matchers. +" + + read -k key'?--- Hit selection --- ' + print + + if [[ $key = [nNcCpPsS] ]]; then + while true; do + read -k key2'?Set/unset for element number (1234)? ' + print + [[ $key2 = [1234] ]] && break + print "Only 1, 2, 3 and 4 are handled." + done + fi + + case $key in + [nN]) __ci_toggle_matcher n_list $key2 + if [[ $n_list[$key2] != ' ' ]]; then + fi + ;; + c) __ci_toggle_matcher c_list $key2 + ;; + C) __ci_toggle_matcher C_list $key2 + ;; + [pP]) if __ci_toggle_matcher p_list $key2; then + print "\ +Edit the set of characters which terminate partial words. Typically +these are punctuation characters, such as \`.', \`_' and \`-'. +The expression will automatically be quoted. +" + vared -eh -p 'characters> ' -c 'pw_seps['$key2']' + # Paranoia: we don't know if there's a ']' in that string, + # which will wreck the spec unless it's at the start. Other + # quotes are OK, since they are picked up at the ${(qq)...} + # step. + if [[ $pw_seps[$key2] = *']'* ]]; then + pw_seps[$key2]="]${pw_seps[$key2]//\\\]}" + fi + print -n " +You can allow the partial-word terminators to be matched in the pattern, +too: then for example \`c.u' would expand to \`comp.source.unix', whereas +usually you would need to type an extra intervening dot. Do you wish the +terminators to be matched in this way? (y/n) [n] " + pw_dstar[$key2]= + read -q key && pw_dstar[$key2]='*' + fi + ;; + [tT]) + read -k key2'?Toggle augment/replace for elements number (1234)? ' + if [[ $key2 == [1234] ]]; then + if [[ $a_or_r[$key2] == ' ' ]]; then + a_or_r[$key2]='+' + else + a_or_r[$key2]=' ' + fi + else + print "Only 1, 2, 3 and 4 are handled." + fi + ;; + [sS]) __ci_toggle_matcher s_list $key2 + ;; + [qQ]) return 1 + ;; + esac + + [[ $key = 0 ]] && break + done + + # Keep track of the last element which was non-empty; all the rest + # are junked. + lastnz=0 + + # Now we just reverse the first for-loop, looking for set matchers + # and reconstructing the elements of the matcher array. + for (( eltcnt = 1; eltcnt <= 4; eltcnt++ )); do + elt= + [[ $c_list[$eltcnt] != ' ' ]] && elt="${elt:+$elt }m:{a-z}={A-Z}" + [[ $C_list[$eltcnt] != ' ' ]] && elt="${elt:+$elt }m:{a-zA-Z}={A-Za-z}" + [[ $p_list[$eltcnt] != ' ' ]] && + elt="${elt:+$elt }r:|[${pw_seps[$eltcnt]}]=*${pw_dstar[$eltcnt]}\ + r:|=*${pw_dstar[$eltcnt]}" + if [[ $s_list[$eltcnt] != ' ' ]]; then + if [[ $elt = *"r:|=*"* ]]; then + elt="${elt:+$elt }l:|=*" + else + elt="${elt:+$elt }l:|=* r:|=*" + fi + fi + [[ $a_or_r[$eltcnt] != ' ' ]] && elt="+$elt" + [[ -n $elt || $n_list[$eltcnt] != ' ' ]] && lastnz=$eltcnt + mlist[$eltcnt]=$elt + done + + if (( ! $lastnz )); then + # No matchers set, so just make the style empty: __ci_set_this_style + # will omit it completely. + mlist= + else + # Quote the entire list: this correctly quotes element by element, + # praise be to Sven. + mlist=(${(qq)mlist[1,$lastnz]}) + # Make it a scalar just for safety's sake. + mlist="$mlist" + fi + __ci_set_this_style matcher-list mlist + + return 0 +} + +__ci_do_list_format() { + local key format groupn verbose listp autod haslistp + __ci_get_this_style format format + [[ -n $format ]] && format=${(Q)format} + __ci_get_this_style group-name groupn + __ci_get_this_style verbose verbose + __ci_get_this_style list-prompt listp + [[ -n $listp ]] && haslistp=1 + listp=${(Q)listp} + __ci_get_this_style auto-description autod + [[ -n $autod ]] && autod=${(Q)autod} + + while true; do + clear + print "\ + *** compinstall: order and descriptions in completion lists *** +Type the appropriate number for more information on how this would affect +listings. + +1. Print a message above completion lists describing what is being + completed. + +2. Make different types of completion appear in separate lists. + +3. Make completion verbose, using option descriptions etc. (on by default). + +4. Make single-valued options display the value's description as + part of the option's description. + +q. Return without saving. +0. Done setting options for formatting of completion lists. +" + + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + 1) print "\ +You can set a string which is displayed on a line above the list of matches +for completions. A \`%d' in this string will be replaced by a brief +description of the type of completion. For example, if you set the +string to \`Completing %d', and type ^D to show a list of files, the line +\`Completing files' will appear above that list. Enter an empty line to +turn this feature off. If you enter something which doesn't include \`%d', +then \`%d' will be appended. Quotation will be added automatically. +" + vared -eh -p 'description> ' -c format + if [[ -n $format && $format != *%d* ]]; then + [[ $format = *[[:blank:]] ]] || format="$format " + format="$format%d" + fi + ;; + 2) print "\ +Normally, all possible completions are listed together in a single list, and +if you have set a description with 1) above, the descriptions are listed +together above that. However, you can specify that different types of +completion appear in separate lists; any description appears above its +own list. For example, external commands and shell functions would appear +in separate lists when you are completing a command name. Do you +want to turn this on? +" + while true; do + read -k key'?[y]es, [n]o, [k]eep old setting? ' + print + [[ $key = [yYnNkK] ]] && break + done + case $key in + [yY]) groupn="''" + ;; + [nN]) groupn= + ;; + esac + ;; + 3) print "By default, completion uses a \`verbose' setting. This +affects different completions in different ways. For example, many +well-known commands have short, uninformative option names; in some cases, +completion will indicate what the options do when offering to complete them. +If you prefer shorter listings you can turn this off. What setting to +you want? +" + while true; do + read -k key'?[v]erbose, [n]ot verbose, [k]eep old setting? ' + print + [[ $key = [vVnNkK] ]] && break + done + case $key in + # might as well be explicit, particularly since it's + # the only way to override an existing `false' value. + [vV]) verbose=true + ;; + [nN]) verbose=false + ;; + esac + ;; + 4) print "\ +Many commands have options which take a single argument. In some cases, +completion is not set up to describe the option even though it has a +description for the argument. You can enter a string containing \`%d', +which will be replaced by the description for the option. For +example, if you enter the string \`specify: %d', and an option -ifile +exists which has an argument whose description is \`input file', then the +description \`specify: input file' will appear when the option itself +is listed. As this long explanation suggests, this is only occasionally +useful. Enter an empty line to turn this feature off. If you enter +something which doesn't include \`%d', then \`%d' will be appended. +Quotation will be added automatically. +" + vared -eh -p 'auto-description> ' -c autod + if [[ -n $autod && $autod != *%d* ]]; then + [[ $autod = *[[:blank:]] ]] || autod="$autod " + autod="$autod%d" + fi + ;; + q) return 1 + ;; + esac + done + + [[ -n $format ]] && format=${(qq)format} + __ci_set_this_style format format + __ci_set_this_style group-name groupn + __ci_set_this_style verbose verbose + [[ -n $autod ]] && autod=${(qq)autod} + __ci_set_this_style auto-description autod +} + +__ci_do_insertion() { + local key insertu original # sort + + __ci_get_this_style insert-unambiguous insertu + __ci_get_this_style original original + + while true; do + clear + print "\ + *** compinstall: options for inserting completions *** + +1. In completers that change what you have already typed, insert any + unambiguous prefix rather than go straight to menu completion. + +2. In completers which correct what you have typed, keep what you + originally typed as one of the list of possible completions. + +q. Return with saving. +0. Done setting options for insertion. +" + read -k key'?-- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + 1) print "\ +The completers which do pattern matching and correction often alter the +string which is already on the line, in the first case because it was a +pattern and in the second case because what you typed was wrong. +Since the possible completions can bear little or no resemblance to one +another in those cases, so that typing extra characters to resolve the +completion doesn't make much sense, menu completion is usually turned on +straight away to allow you to pick the completion you want. This style +tells completion that if there is a common, unambiguous prefix in this +case, you would prefer that to be inserted rather than going straight +to menu completion. Do you want this? +" + while true; do + read -k key'?[y]es, [n]o, [k]eep old setting? ' + print + [[ $key = [yYnNkK] ]] && break + done + case $key in + [yY]) insertu=true + ;; + [nN]) insertu=false + ;; + esac + ;; + 2) print "\ +For completers which correct what you have typed, you sometimes want +to keep the original string instead, so if the correction was ambiguous +the original string is always listed as a possible completion. However, +if there was just one completion it is usually accepted. You can +force completion to offer the original string as a possibility even in +this case. Do you want this? +" + while true; do + read -k key'?[y]es, [n]o, [k]eep old setting? ' + print + [[ $key = [yYnNkK] ]] && break + done + case $key in + [yY]) original=true + ;; + [nN]) original=false + ;; + esac + ;; + [qQ]) return 1 + ;; + esac + + done + + __ci_set_this_style insert-unambiguous insertu + __ci_set_this_style original original + # __ci_set_this_style sort sort + + return 0; +} + + +__ci_do_selection() { + local key listc menu select amenu elt listp selectp haslistp hasselectp + integer num + + __ci_get_this_style list-colors listc + __ci_get_this_style menu menu + __ci_get_this_style list-prompt listp + [[ -n $listp ]] && haslistp=1 + listp=${(Q)listp} + __ci_get_this_style select-prompt selectp + [[ -n $selectp ]] && hasselectp=1 + selectp=${(Q)selectp} + + while true; do + clear + print "\ + *** compinstall: options for colouring and selecting in lists *** + +1. Use coloured lists for listing completions. + +2. Use cursor keys to select completions from completion lists. + +3. Allow scrolling of long selection lists and set the prompt. + +q. Return without saving. +0. Done setting options for insertion. +" + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + 1) print "\ +Zsh can produce coloured completion listings where different file types +etc. appear in different colours. If you want to tailor that to your +own needs, you will have to edit ~/.zshrc. Here you have the choice of: + +1. Using the default colours. +2. Using the colours already set up for GNU ls via the \$LS_COLORS + environment variable. Note this must be set before the completion + configuration code is executed. +3. Turn colouring off. +0. Leave the setting the way it is. Choose this if you have a custom + setting and you don't want to lose it. +" + while true; do + read -k key'?Enter 1, 2, 3, 0: ' + print + [[ $key = [1230] ]] && break + done + case $key in + 1) listc="''" + ;; + 2) listc='${(s.:.)LS_COLORS}' + ;; + 3) listc= + ;; + esac + ;; + 2) print "\ +If you use zsh's menu completion and the feature that all short completion +lists appear below the line on which you are editing, you can enable +\`menu selection', which lets you pick a completion with the cursor keys: +the choice is highlighted, and hitting return accepts it. Note that +this only happens when you are already using menu completion. This +feature can be set so that it is only enabled when there are a certain +number of completions. Please enter: + +- 0 or 1, to turn this feature on unconditionally +- a higher number to turn this feature on when there are that many + completions +- an \`l' for \`long' to turn it on for listings which don't fit on the + screen. +- an \`ll' for \`long list' to turn it on for completions which don't fit + on the screen, even for commands which only do listing of completions. + This may be combined with a number which will be used in ordinary selection. +- a negative number to turn this feature off +- an empty line to leave the setting the way it is. +" + # Better to parse and display the current setting. + while true; do + vared -eh -p 'value> ' select + [[ -z $select || $select = ((-|)<->|l|<->#ll<->#) ]] && break; + print "Type a number, l, ll, ll<num>, or an empty line." >&2 + done + amenu=(${=menu}) + elt=${amenu[(i)*select*]} + [[ $elt -gt $#amenu ]] && elt= + case $select in + <->) if [[ -n $elt ]]; then + amenu[$elt]="select=$select" + else + amenu=($amenu "select=$select") + fi + menu="$amenu" + ;; + *ll*) num=${(RS)select##ll} + select="select=long-list" + [[ -n $num ]] && select="$select select=$num" + if [[ -n $elt ]]; then + amenu[$elt]=$select + else + amenu=($amenu $select) + fi + menu="$amenu" + ;; + l#) if [[ -n $elt ]]; then + amenu[$elt]="select=long" + else + amenu=($amenu "select=long") + fi + menu="$amenu" + ;; + -<->) if [[ -n $elt ]]; then + # i never liked the way indexing was done anyway + if [[ $elt -eq 1 ]]; then + amenu=($amenu[$elt+1,-1]) + else + amenu=($amenu[1,$elt-1] $amenu[$elt+1,-1]) + fi + fi + menu="$amenu" + ;; + esac + if [[ $menu = *select* ]]; then + print "\ +You can also set a prompt to use for menu selection when it would scroll +off the screen. Unless this is set, you won't see a prompt, but the feature +is still enabled. + +Edit a prompt below. It can contain \`%l' to show the number of matches +as \`current_number/total_number', \`%p' to show the fraction of +the way down the list, or font-control sequences such as %B, %U, %S and +the corresponding %b, %u, %s; quotes will be added automatically. Delete +the whole line to turn it off. Hit return to keep the current value. +" + [[ -z $hasselectp ]] && + selectp='%SScrolling active: current selection at %p%s' + vared -eh -p 'prompt> ' -c selectp + [[ -z $selectp ]] && hasselectp= + fi + ;; + 3) print "\ +You can make completion lists scroll when they don't fit on the screen. +Note this is different from scrolling in menu selection --- a more basic +pager is used which should work even with fairly stupid terminals. + +To enable this, edit a prompt to show when scrolling is active; an empty +string turns this feature off. It can contain \`%l' to show the number of +matches as \`current_number/total_number', \`%p' to show the fraction of +the way down the list, or font-control sequences such as %B, %U, %S and the +corresponding %b, %u, %s; quotes will be added automatically. Delete the +whole line to turn this behaviour off, in which case the display of +completions which don't fit on the screen is controlled by the LISTMAX +parameter (currently ${LISTMAX:-unset}), which specifies the maximum number +to show without asking. Hit return to keep the current value. +" + [[ -z $haslistp ]] && + listp='%SAt %p: Hit TAB for more, or the character to insert%s' + vared -eh -p 'prompt> ' -c listp + [[ -z $listp ]] && haslistp= + ;; + q) return 1 + ;; + esac + done + + __ci_set_this_style list-colors listc + __ci_set_this_style menu menu + [[ -n $haslistp ]] && listp=${(qq)listp} + __ci_set_this_style list-prompt listp + [[ -n $hasselectp ]] && selectp=${(qq)selectp} + __ci_set_this_style select-prompt selectp + + return 0 +} + + +__ci_do_display() { + local key usec + + __ci_get_this_style use-compctl usec + + while true; do + clear + print "\ + *** compinstall: display and insertion options *** + +1. Change appearance of completion lists: allows descriptions of + completions to appear and sorting of different types of completions. + +2. Change how completions are inserted: includes options for sorting, + and keeping the original or an unambiguous prefix with correction etc. + +3. Configure coloured/highlighted completion lists, selection of items + and scrolling. + +4. Change whether old-style \`compctl' completions will be used. + +q. Return without saving. +0. Done setting display and insertion options. +" + + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + 1) __ci_do_list_format + ;; + 2) __ci_do_insertion + ;; + 3) __ci_do_selection + ;; + 4) print "\ +Completions defined by the new completion system (the one you are +configuring) always take precedence over the old sort defined with compctl. +You can choose whether or not you want to search for a compctl-defined +completion if no new completion was found for a command. The default +behaviour is only to check for compctl-defined completions if the required +library, zsh/compctl, is already loaded. (If not, this implies that +compctl has not been called.) Do you want to test for compctl-defined +completions? +" + while true; do + read -k key'?[y]es, [n]o, if [l]oaded, [k]eep old setting? ' + print + [[ $key = [yYnNlLkK] ]] && break + done + case $key in + [yY]) usec=true + ;; + [nN]) usec=false + ;; + [lL]) usec= + ;; + esac + ;; + q) return 1 + ;; + esac + + done + + __ci_set_this_style use-compctl usec + + return 0 +} + + +# file-sort, special-dirs, ignore-parents, +# squeeze-slashes, +__ci_do_file_styles() { + local key files cursor expand speciald ignorep squeezes select + + __ci_get_this_style file-sort files + __ci_get_this_style ignore-parents ignorep + __ci_get_this_style special-dirs speciald + __ci_get_this_style squeeze-slashes squeezes + + while true; do + clear + print "\ + *** compinstall: options for filename completion *** + +1. Choose how to sort the displayed list of filename matches. + +2. In expressions with .., don't include directories already implied. + +3. Allow completion of . and .. for the bone idle. + +4. When expanding paths, \`foo//bar' is treated as \`foo/bar'. + +q. Return without saving. +0. Done setting options for filename completion. +" + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + (1) print "\ +Filenames listed as possible completions are usually displayed in +alphabetical order. You can alternatively choose: + s File size + l Number of (hard) links + m Modification time + a Access time + i Inode change time + n File name + k Keep the current setting +You can also specify the reverse of any of the above orders (except \`k'): to +do this, type the appropriate letter in upper case. +" + while true; do + read -k key'?--- Hit selection --- ' + print + [[ $key = [sSlLmMaAiInNkK] ]] && break + done + case $key in + ([sS]) files=size;; + ([lL]) files=links;; + ([mM]) files=modification;; + ([aA]) files=access;; + ([iI]) files=inode;; + ([nN]) files=name;; + esac + if [[ $key = [SLAMIN] ]]; then + # slam it into reverse + files="$files reverse" + fi + ;; + (2) print "\ +When you type an expression containing \`..', you may usually not want to +be offered certain directories for completion. + p Don't offer parents: in \`foo/bar/../', don't make \`bar' a completion. + c Don't offer the current directory, e.g. after \`../'. + o Only perform the two tests if there is a real \`..' in the word so far. + d Only perform the two tests when completing directory names. + 0 None of the above; use normal completion. + k Keep the current settings. +You may specify any combination of p, c, o, d including at least one of p +and c, or you may specify either 0 or k. Note that the _ignored completer +functions in the normal way, i.e. you would be able to complete the +directories in question if nothing else matched. +" + while true; do + vared -eh -p 'selection> ' select + [[ ( $select = [pPcCoOdD]# && $select = *[pPcC]* ) + || $select = [0kK] ]] && break + print "Type any combination of p, c, o, d, or type 0 or k" + done + case $select in + (0) ignorep= + ;; + ([pPcCoOdD]#) + ignorep=() + [[ $select = *[pP]* ]] && ignorep=($ignorep parent) + [[ $select = *[cC]* ]] && ignorep=($ignorep pwd) + [[ $select = *[oO]* ]] && ignorep=($ignorep ..) + [[ $select = *[dD]* ]] && ignorep=($ignorep directory) + ;; + esac + ;; + (3) print "\ +Filename completion does not usually offer the directory names \`.' and +\`..' as choices. However, some immensely lazy people can't even be +bothered to type these. Do you wish to be offered \`.' and \`..' as +choices ([y]es, [n]o, [k]eep current setting)? +" + while true; do + read -k key'?--- Hit selection --- ' + [[ $key = [yYnNkK] ]] && break + print "Type y, n or k." + done + case $key in + ([yY]) speciald=true;; + ([nN]) speciald=;; + esac + ;; + (4) print "\ +Filename completion can complete sets of path segments at once, for example +\`/u/X/l/X' to \`/usr/X11R6/lib/X11'. Normally this means that multiple +slashes in filenames are treated as matching multiple directories. For +example, \`foo//bar' could expand to \`foo/datthe/bar'. You can, however, +stick to the usual UNIX convention that multiple slashes are treated as +a single slash. Do you wish to treat multiple slashes the same as just +one ([y]es, [n]o, [k]eep current setting)? +" + while true; do + read -k key'?--- Hit selection --- ' + [[ $key = [yYnNkK] ]] && break + print "Type one of y, n or k." + done + case $key in + ([yY]) squeezes=true;; + ([nN]) squeezes=;; + esac + ;; + (q) return 1 + ;; + esac + + done + + __ci_set_this_style file-sort files + __ci_set_this_style ignore-parents ignorep + __ci_set_this_style special-dirs speciald + __ci_set_this_style squeeze-slashes squeezes + + return 0 +} + + +# TODO: history completion, jobs, prefix-needed 'n' stuff. +__ci_do_misc() { + local key + + while true; do + clear + print "\ + *** compinstall: options for particular types of completion *** + +1. Options for file completion. + +q. Return without saving. +0. Done setting options for particular completions. +" + read -k key'?--- Hit selection --- ' + print + + [[ $key = 0 ]] && break + + case $key in + 1) __ci_do_file_styles + ;; + q) return 1 + ;; + esac + + done + + return 0; +} + + +# TODO: it should probably be possible to set completion options via +# compinstall, even though they've been around for years. + +while true; do + clear + print "\ + *** compinstall: main menu *** +Note that hitting \`q' in menus does not abort the set of changes from +lower level menus. However, quitting at top level will ensure that nothing +at all is actually written out. + +1. Completers: choose completion behaviour for tasks such as + approximation, spell-checking, expansion. + +2. Matching control: set behaviour for case-insensitive matching, + extended (partial-word) matching and substring matching. + +3. Styles for changing the way completions are displayed and inserted. + +4. Styles for particular completions. + +c. Change context (plus more information on contexts). + +q. Return without saving. +0. Save and exit. +" + + __ci_newline \ + "--- Hit choice --- " || return 1 + + # note this is a string test: we require the `0' to have been typed. + [[ $key = 0 ]] && break + + case $key in + 1) __ci_do_completers + ;; + 2) __ci_do_matchers + ;; + 3) __ci_do_display + ;; + 4) __ci_do_misc + ;; + c) __ci_change_context + ;; + esac +done + + +local output + +if (( $#styles )); then + typeset style stylevals context values + for style in ${(ko)styles}; do + stylevals=(${(f)styles[$style]}) + while (( $#stylevals )); do + output="$output +zstyle ${(qq)stylevals[1]} $style $stylevals[2]" + shift 2 stylevals + done + done +fi + +if [[ -z $ifile || -d $ifile ]] || + ! read -q key"?Save new settings to $ifile? "; then + print "Enter file to save in (~ will be expanded), or return to abort:" + ifile= + vared -ch -p 'file> ' ifile + ifile=${~ifile} +fi + +local tmpout=${TMPPREFIX:-/tmp/zsh}compinstall$$ +# +# Assemble the complete set of lines to +# insert. +# +{ print -r "$startline +$output" + if [[ -n $ifile ]]; then + line="zstyle :compinstall filename ${(qq)ifile}" + print -r "$line" + eval "$line" + fi + + [[ -n $fpath_line ]] && print -r "$fpath_line" + + print -r " +autoload -U compinit +compinit${compinit_args:+ $compinit_args}" + + print -r "$endline" +} >$tmpout + +if [[ -n $ifile ]]; then + if [[ $ifile != *(zshrc|zlogin|zshenv) ]]; then + print "\ +If you want this file to be run automatically, you should add + . $ifile +to your .zshrc. compinstall will remember the name of this file for +future use." + __ci_newline || return 1 + fi + # + # Now use sed to update the file. + # + if [[ -f $ifile ]]; then + cp $ifile ${ifile}\~ && + print "Copied old file to ${ifile}~." + else + touch $ifile + fi + if { { grep "$endline" $ifile >/dev/null 2>&1 && + sed -e "/^[ ]*$endline/r $tmpout +/^[ ]*$startline/,/^[ ]*$endline/d" $ifile >${tmpout}2 } || + { cp $ifile ${tmpout}2 && cat $tmpout >>${tmpout}2 } } && + cp ${tmpout}2 $ifile && rm -f ${tmpout}2; then + print "\nSuccessfully added compinstall lines to $ifile." + rm -f $tmpout + else + print "\nFailure adding lines to $ifile. Lines left in \`$tmpout'" + fi + rm -f ${tmpout}2 +elif read -q key'?Print them to stdout instead? '; then + cat $tmpout + rm -f $tmpout +fi + +if read -q key'?Set new styles for immediate use? '; then + eval $output + print "The new settings are now in effect. Note this will not remove old +styles you have deleted until you restart the shell." +fi + +__ci_tidyup +return 0 |