Subject: Re: compadd -Q -U completes $(( without inserting upon it
From: Bart Schaefer <[email-masked]>
To: Zsh hackers list <[email-masked]>
Date: Sat, 16 Jan 2016 14:55:05 -0800
List-Id: Zsh Workers List <zsh-workers.zsh.org>

On Jan 16,  6:25pm, Sebastian Gniazdowski wrote:
}
} This looks like zsh source has embedded tweaks to make math
} ($compstate[context] is "math" in second case) completing work more
} reasonably. Is there a way to overcome this?

Internally, when you invoke a completion widget, the ZLE buffer gets
analyzed and divided into three sections:
 1) The words array, which is the context where completion happens.
 2) Anything before the words array, which completion is not allowed
    to modify.
 3) Anything after the words array, similarly immutable.

In "ordinary" command completion, (2) and (3) are empty.

When you complete after a token such as $( or $(( that begins a context,
those tokens are part of the immutable section that precedes the array
of words.  You can assign to the words array to change how completion
interprets the set of possible matches, but anything you subsequently do
has to fit into the part of $BUFFER corresponding to the original $words.

You can make the mutable part smaller and expand the immutable parts by
calling "compset -q", but nobody considered before that the reverse
might also be interesting.  The internals of "compset" are a bit of a
nightmare, programmed by a brilliant Polish student who was fond of
abbreviated variable names and rarely wrote comments.  (The comments
there are others trying mostly unsuccessfully to untangle his logic.)

I've already outlined for you two ways to overcome this:

A) Capture the set of matches using "compadd -O", then remove the bits
that overlap with the immutable parts of the buffer before "compadd"
again of what remains.  (It's possible I've given you bad advice
regarding the need for the -U option; try it without that as well.)

B) Don't invoke completion directly; instead, invoke a normal editing
widget to modify the buffer so the tokens do not begin a context, then
call the completion widget, and finally clean up the buffer again when
the completion widget returns.

The tricky bit of (A) is keeping track of which part of the matches is
really "immutable" and which part is not.  The unfortunate bit of (B)
is that it can't work at all as a completer function (zstyle element).

There's also option (C) write your own completion system from scratch.
When the current compsys was invented, the (z) and (Z) parameter flags
didn't exist, so it was felt that it would be easier to allow the
exiting completion internals to be callable to do most of that work.  
We also didn't have keymaps at that point, nor "zle -M" / "zle -R".
A lot of what the completion system used to be the only way to do, can
probably now be done in the shell language.