From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22524 invoked from network); 22 Feb 1999 11:15:27 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 22 Feb 1999 11:15:27 -0000 Received: (qmail 5138 invoked by alias); 22 Feb 1999 10:54:36 -0000 Mailing-List: contact zsh-workers-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 5469 Received: (qmail 5126 invoked from network); 22 Feb 1999 10:54:31 -0000 Date: Mon, 22 Feb 1999 11:53:42 +0100 (MET) Message-Id: <199902221053.LAA21209@beta.informatik.hu-berlin.de> From: Sven Wischnowsky To: zsh-workers@sunsite.auc.dk Subject: New example function for completion Below is a fix for a thinko in the `init' function and a new example function. It was Peter who made me think about this, dunno if he was thinking about something like this, though. The function `_comp_parts' is invoked with arrays (names of arrays or `(foo bar)' strings) and separator strings as arguments, as in `_comp_parts friends @ hosts'. It will then try to complete the word-parts seperated by the separator strings independently from the arrays. Only being able to use arrays is not very powerful, but I don't see a solution to independently complete word-parts from `complist'-flags for now (only the obvious one-after-another-solution well known from `compctl' and the current completion widget examples). Now, could someone come up with an example that uses this function? ;-) Bye Sven --- of/Completion/init Mon Feb 22 10:49:46 1999 +++ Functions/Completion/init Mon Feb 22 11:12:30 1999 @@ -170,7 +170,7 @@ if [[ -f "$COMPDUMP" ]]; then read -rA _i_line < "$COMPDUMP" - if [[ _i_autodump -eq 1 || $_i_line[2] -eq $#_i_files ]]; then + if [[ _i_autodump -eq 1 && $_i_line[2] -eq $#_i_files ]]; then builtin . "$COMPDUMP" _i_done=yes fi --- Functions/Completion/_comp_parts Mon Feb 22 11:18:08 1999 +++ Functions/Completion/_comp_parts Mon Feb 22 11:17:34 1999 @@ -0,0 +1,123 @@ +#autoload + +# This function can be used to separately complete parts of strings +# where each part may be one of a set of matches and different parts +# have different sets. +# Arguments are alternatingly arrays and separator strings. Arrays may +# be given by name or literally as words separated by white space in +# parentheses, e.g.: +# +# _comp_parts '(foo bar)' @ hosts +# +# This will make this function complete the strings in the array +# `friends'. If the string on the line contains a `@', the substring +# after it will be completed from the array `hosts'. Of course more +# arrays may be given, each preceded by another separator string. +# This function does part of the matching itself, doing it as if a +# matching specification like `-M "m :{a-z}={A-Z} r:|[.,-_]=* r:|=*"' +# were used, so you might want to modify this function. + +local str arr sep test testarr tmparr prefix suffixes matchers autosuffix + +# I have a global matching specification with multiple sets and want +# all this tried only once, you may want to change this line. + +[[ MATCHER -gt 1 ]] && return + +# Get the string from the line. + +str="$PREFIX$SUFFIX" +prefix="" + +# Walk through the arguments to find the longest unambiguous prefix. + +while [[ $# -gt 1 ]]; do + # Get the next array and separator. + arr="$1" + sep="$2" + + if [[ "$arr[1]" == '(' ]]; then + tmparr=( ${=arr[2,-2]} ) + arr=tmparr + fi + # Is the separator on the line? + [[ "$str" != *${sep}* ]] && break + + # Build a pattern matching the possible matches and get all these + # matches in an array. + test="${str%%${sep}*}" + test="(#l)$test:gs/./*./:gs/,/*,/:gs/-/*-/:gs/_/*_/:gs/**/*/" + testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) + + # If there are no matches we give up. If there is more than one + # match, this is the part we will complete. + (( $#testarr )) || return + [[ $#testarr -gt 1 ]] && break + + # Only one match, add it to the prefix and skip over it in `str', + # continuing with the next array and separator. + prefix="${prefix}${testarr[1]}${sep}" + str="${str#*${sep}}" + shift 2 +done + +# Get the array to work upon. +arr="$1" +if [[ "$arr[1]" == '(' ]]; then + tmparr=( ${=arr[2,-2]} ) + arr=tmparr +fi +if [[ $# -le 1 || "$str" != *${2}* ]]; then + # No more separators, build the matches. + test="(#l)$str:gs/./*./:gs/,/*,/:gs/-/*-/:gs/_/*_/:gs/**/*/" + testarr=( "${(@M)${(@P)arr}:#${~test}*}" ) +fi + +# Now we build the suffixes to give to the completion code. +shift +matchers=() +suffixes=("") +autosuffix=() + +while [[ $# -gt 0 && "$str" == *${1}* ]]; do + # Remove anything up to the the suffix. + str="${str#*${1}}" + + # Again, we get the string from the line up to the next separator + # and build a pattern from it. + if [[ $# -gt 2 ]]; then + test="${str%%${3}*}" + else + test="$str" + fi + test="(#l)$test:gs/./*./:gs/,/*,/:gs/-/*-/:gs/_/*_/:gs/**/*/" + + # We incrementally add suffixes by appending to them the seperators + # and the strings from the next array that match the pattern we built. + + arr="$2" + if [[ "$arr[1]" == '(' ]]; then + tmparr=( ${=arr[2,-2]} ) + arr=tmparr + fi + suffixes=("${^suffixes[@]}${1}${(@M)^${(@P)arr}:#${~test}*}") + + # We want the completion code to generate the most specific suffix + # for us, so we collect matching specifications that allow partial + # word matching before the separators on the fly. + matchers=("$matchers[@]" "r:|${1}=*") + shift 2 +done + +# If we were given at least one more separator we make the completion +# code offer it by appending it as a autoremovable suffix. +(( $# )) && autosuffix=(-qS "$1") + +# If we have collected matching specifications, we build an array +# from it that can be used as arguments to `compadd'. +[[ $#matchers -gt 0 ]] && matchers=(-M "$matchers") + +# Add the matches for each of the suffixes. +for i in "$suffixes[@]"; do + compadd "$matchers[@]" "$autosuffix[@]" -p "$prefix" -s "$i" - "$testarr[@]" +done -- Sven Wischnowsky wischnow@informatik.hu-berlin.de