Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Functions for multiple commands

I thought of several ways to restructure these completion functions for
multiple commands/contexts. Below are those I liked best.

In the following, I'll call such functions `digests'. Never mind.
`collections' might be a better name.

Each command/context has its own function. The autoloaded function
only defines those functions (and may contain other initialisation
code, like defining cache-arrays or whatever).

For such files, we use a new tag, say `#digest'. The tag lines contain
the mappings from command/context to sub-functions, e.g. as in:

  #digest cmd1:sub-func1 cmd2:sub-func2 ...

Then there are three possibilities:

The code that handles `#digest' tags immediately calls them, during
compinit. That allows other functions to call the sub-functions directly
and $_comp only needs to contain the name of the sub-function, i.e.
users can just do:

  compdef sub-func cmd ...

And as long as they are easy to see in the file (or documented)...

But of course having to call the functions during initialisation is ugly.

One way to avoid that: the function that handles `#digest' only saves the
mappings from the autoloaded function to the sub-functions in an
associative array, say $_digest. Keys are the autoloaded functions, values
are formed like ' sub-func1 sub-func2 ...'.

In this case we have to change the code that invokes completion functions.
We could of course add a helper function for that, which gets the name
of the command/context as argument:

  foo() {
    local func digest
    digest="${(k)_digest[(R)* $func *]}"
    if [[ -n "$digest" ]]; then
      unfunction "$digest"
      unset "_digest[$digest]"

I'm not exactly sure how big a problem it is that this means that sub-
functions are not directly callable.

That could be avoided with a bit of magic, namely: the function handling
`#digest' creates dummy-functions for the sub-functions, like this:

  # name of sub-function is in $sub, name of digest function is in $digest
  (( $+functions[$sub] )) ||
      if (( \$+functions[$digest] )); then
        unfunction $digest

Without mapped .zwc files, this might be faster (and certainly more memory-
saving than 1a)). But still...

And in any case, digest-file writers would have to use:

  (( $+functions[_foo] )) || _foo() { ... }

so that sub-functions found earlier (in user-defined autoloaded files)
override those found later.

Using only one autoloaded function, no sub-functions. The function then
uses a big `case', the `service' to use is given as the first argument and
the `#digest' line contains the mappings from commands/contexts to
`services'. The function handling `#digest' saves those mappings in an
associative array, say $_digest. Again, we need special code to call
the function:

  if (( $+_digest[$func] )); then
    "$_digest[$func]" "$func"

Instead of `#digest', we could also use `#compdef' and allow a special
syntax to mean that for a certain command/context the autoloaded function
should be called with a `service'-argument.

And of course, we could also combine this with 1c) and define dummy
functions for the `services' that just call the autoloaded function with
the argument. Together with 2a) we could also add a second syntax to
define `services' for which functions should be created (next to those
for which no functions are created).

Currently, I'm not sure which I like best. Comments? Opinions? Other


Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx

Messages sorted by: Reverse Date, Date, Thread, Author