Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
New example function for completion
- X-seq: zsh-workers 5469
- From: Sven Wischnowsky <wischnow@xxxxxxxxxxxxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxxxxxx
- Subject: New example function for completion
- Date: Mon, 22 Feb 1999 11:53:42 +0100 (MET)
- Mailing-list: contact zsh-workers-help@xxxxxxxxxxxxxx; run by ezmlm
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@xxxxxxxxxxxxxxxxxxxxxxx
Messages sorted by:
Reverse Date,
Date,
Thread,
Author