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

Re: completion grouping (yes, again)



On Nov 9,  1:07pm, Sven Wischnowsky wrote:
} Subject: completion grouping (yes, again)
}
} I've hacked a bit more, trying to make things easier to use and
} configure...

This, I like, a lot.

} First, the completion function side:
} 
} `_tags' has been simplified. [...]
} I also added a bit of parameter magic, so that functions using `_tags' 
} don't need to define the `tags' parameter locally.

This is pretty cute, but I wonder if it's going to work correctly with
(say) KSH_ARRAYS set?  There aren't very many "emulate -L zsh" calls in
the Completion tree at the moment ...

} The I added the functions `_requested' which gets names of tags and
} returns zero if at least one of these tags was requested.
} 
} So, to use tags one can now simply do something like:
} 
}   local ret=1
} 
}   _tags job process   # say which types of matches we can add
} 
}   while _tags; do     # get the next set of tags to try
} 
}     _requested job     && _jobs && ret=0
}     _requested process && _pids && ret=0
} 
}     (( ret )) || return 0
}   done
} 
}   return 1

This looks reasonable; I could only wish for a more direct correlation
between the tag name and the completion function that's called to get
the corresponding matches.  However, I can't decide whether to rename
the tags or the functions -- and I can imagine there might be cases in
which the same tag might map to more than one function.
 
} But there is also the new function `_alternative' (please someone who
} actually can speak English tell me a better name)

The only better words that occur to me are ones like "switch" and "case"
that are used in other languages for select-among-alternates behavior.
It'd probably be bad to actually use one of those because of confusion
with similar shell reserved words.  I suppose you could use "_alternate"
just for a little brevity, or maybe something like "_inspect".

} which basically
} implements such a loop. Its arguments are of the form
} `<tag>:<descr>:<action>', which should look familiar. The tags are
} given to `_tags' and then a loop executes the actions of the requested 
} tags.

Looks like there's an obvious optimization here:  Replicate the loop
that's in _requested and put the body of _alternative inside it.  Am I
missing something?

} This also means that there is a small difference to `_arguments' 
} and friends: the `->state' style for actions is not supported (because 
} `_alternative' may have to execute more than one action).

I'm afraid I don't immediately understand the ramifications of this.

} With this functions like `_wait' only have to do:
} 
}   _alternative 'job:: _jobs' 'process:: _pids'
} 
} (Empty descriptions because they are not used -- the actions start
} with spaces and we use the descriptions added by `_jobs' and `_pids'.)

Why do the actions start with space?

} Then I added some more support for styles. [...]
} 
} What I was thinking about is this: if we integrate the config stuff
} into the tags mechanism I see two ways we can go:
} 
} 1) Add `pseudo'-tags, named after the config keys they replace
} 2) Add new tags [...] which also group config keys.
} 
} I quite like the grouping done by 2), but for some config keys this
} looks like overkill.

It seems to me that (2) is a superset of (1).  That is, you could use a
special case (the empty style name?) to represent (1) within (2), and
thus get the best of both worlds without the "overkill".

} Ok, now for the last part: contexts. The problem is that for some
} commands there are different places where the same tags are
} used. E.g. the command `dvips' gets dvi files but any file name after
} the `-o' option. [...]
} 
} I have already change `_tags' and `_alternative' to support the
} `-C <context>' option that allows one to give the name of the context
} we are completing for. If such a context is given (currently no
} functions uses them), `_tags' will compare the patterns from the
} `comptags' assoc with a string of the form `cmd-name/context'. It
} could be changed so that a user definition without a slash would
} affect all contexts.

I think that suggested change would be a good idea, because:

} One problem is to decide when we should use such contexts: always? Or
} only if a command uses the same tag(s) in more than one place? The
} first one looks cleaner but that would mean that completion function
} writers would always have to give such a context name. This is
} particularly ugly because 1) we would have to change all completion
} functions and 2) we would have to change functions like `_arguments'
} so that their arguments also contain these context names.

I think the right answer is to use the contexts always, combined with
the change described above.

If the default behavior were to treat a command-name without a slash as
affecting all contexts, then the existing completion functions could be
left as is without significantly changing their behavior, could they not?
And if it were appropriate to specialize them more, contexts could be
selectively added.

} [W]e could change `_arguments' so that [it builds] context names
} if users don't define them. For `_arguments' this could, for example,
} use names like `-o' and `arg-1' (for options getting multiple
} arguments this would have to be `-foo-1'). Or maybe we use `arg/1',
} making it look like a (sub-)sub-context. But, of course, the problem
} with this is that in many cases the names would be ugly (`infile' is
} certainly more user-friendly than `arg/1').

Before I address that, answer me this:

How does the system know `infile' means "the first non-option argument"?
Or that `outfile' means "the word after `-o ' or `--output='"?  What's
the step I haven't seen that maps these user-friendly context names to
the corresponding (and potentially different for each command) "shape" of
the command line?  I don't believe we can simply infer it.

Unless that mapping can be established in a simple/understandable way, I
think we're just as well off using mechanically-constructed context names
like those suggested above.

} As I said above, I have implemented two suggestions. The functions
} are `conf1' and `conf2' in `compinit'.

This is great stuff, Sven.  I don't have any real opinion at this point
about which is better.  I would suggest a couple of changes:

} `conf1' is tag-centered, its arguments implement what I would call a
} mini-language:
} 
}   conf1 <def> ...
} 
}   <def>     = tag <spec> ... |
}               tag 'is' style
}   <spec>    = [ <context> ] <prio>
}   <context> = 'in' pattern |
}               'else'

I'd suggest

  <context> = 'when' pattern |
              'else'

I might even go so far as to suggest 'if' rather than 'when' -- you
obviously aren't avoiding use of reserved words.

Incidentally, can there be multiple 'in' (suggested 'when') clauses, or
only one?

}   <prio>    = '=' 'never' |
}               '=' number [ <style> ... ]
}   <style>   = 'with' style
} 
} where `style' may be `foo=bar' (i.e. a style with a value).

} The `is'-form would be used for replacing config keys as in:
} 
}   conf1 completer is '_complete:_correct'

OK ...

}   conf2 <def> ...
}   <def>      = 'for' pat 'do' <spec> |
}                'else' 'do' <spec> |
} 	       'always' do <spec>
                        ^^
                       'do' ?

Once again I'd suggest 'when' rather than 'for'.  There's a looping
connotation to 'for' and I don't think any loop is implied here.

Also, I suggest 'use' or 'try' or maybe even 'expect' rather than 'do';
see below.

}   <spec>     = <or-list> |
}                'no' <no-list> |
}                'no' <no-list> 'but' <or-list>
}   <no-list>  = tag | tag 'and' <no-list>
}   <or-list>  = <and-list> |
}                <and-list> 'or' <or-list>
}   <and-list> = <tag> |
}                <tag> 'and' <and-list>
}   <tag>      = tag [ <styles> ]
}   <styles>   = 'with' style | <styles> 'and' 'with' style
} 
} Example:
} 
}   conf2 \
}     for '*dvi*' do \
}       glob and path or \
}       file \
}     else do \
}       glob or \
}       path or \
}       file \
}     for '*p[bgpn]m*' do \
}       argument and option with describe and with hide \
}     else do \
}       argument or \
}       value with describe or \
}       option with describe \
}     for 'kill' do \
}       no job but \
}       process \
}     else do \
}       process and job
} 
} This says that for `*dvi*' commands first both the glob pattern and
} directories should be generated and if that fails all files. For all
} other commands (the `else') first the glob pattern is tried (if any),
} if that fails, directories and if that fails, all files.

I had to think hard about what's going on there.  The bit that it took
a while for me to get is that the 'do' clause doesn't actually "do"
anything!  The completion function still has to call "_requested glob"
or something like that before globbing is attempted.

Hence my suggestion that some other word than 'do' be used here.

Nevertheless:  Good work!

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com



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