Subject: Re: bug#16555: 24.3.50; Company and CAPF: dealing with completion values containing extra text

From: Stefan Monnier <[email-masked]>
Date: Tue, 28 Jan 2014 08:24:27 -0500

> But should we document that the only way to retain the information about
> different annotations corresponding to equal strings is to use text
> properties?

We could add a note somewhere, I guess.  So far, "different completions
for equal strings" is a very rare situation.

> And if text properties is the only way, maybe dispense with the annotation
> function and just document the desired property on the strings?

None of the annotation functions so far use text-properties, because the
completion candidate strings are all different anyway.  I'd rather not
force them to construct the annotation ahead of time "just in case it
might get displayed".

ELISP> (js2-time (mapcar
>>> (lambda (s)
>>> (if (> (length s) 2)
>>> (propertize s 's (substring s (/ (length s) 2)))
>>> s))
>>> (all-completions "" obarray 'fboundp)))

The comparison is not really fair.  Try comparing

   (mapcar (lambda (s)
             (if (> (length s) 2)
                 (substring s 0 (/ (length s) 2))
               s))
           (all-completions "" obarray 'fboundp)))
to
   (mapcar (lambda (s)
             (if (> (length s) 2)
                 (let ((bound (/ (length s) 2))
                       (comp (substring s 0 bound)))
                   (propertize comp 'annotation (substring s bound)))
               s))
           (all-completions "" obarray 'fboundp)))

which can be optimized to

   (mapcar (lambda (s)
             (if (> (length s) 2)
                 (let ((bound (/ (length s) 2))
                       (comp (substring s 0 bound)))
                   (put-text-property 0 bound 'annotation s comp)
                   comp)
               s))
           (all-completions "" obarray 'fboundp)))

Where the (substring s bound) is delayed to the annotation-function.

> Well, I'm not sure: at least in this case, as you can see, fetching the
> candidates is an order or magnitude faster than separating their
> annotations.

That's also because you artificially moved a lot of processing to the
all-completions step whereas some of that processing really belongs to
the annotation step.

>> That description was from the point of view of "TAB-style completion".
>> In the case of company-complete-selection', we know that even if there
>> could be further continuations, the user's action indicates he doesn't
>> want those, so it really should be `finished'.
>> IOW the problem is one of how to better document the meaning of `finished'.
> But wouldn't it clash with the current completion-at-point interface?

I don't see why.  The `finished' case is exactly for things like "insert
a terminator, record the user's choice somewhere, or some other thing
which only makes sense when you somehow know this part of the completion
is over".

> I don't think we can define a CAPF function without regard to how it
> work there.

Can't see why not.

>>> The reverse is also true: being able not to insert the arguments list
>>> for a sole candidate can also be useful, and in Company user can do that at
>>> least by repeatedly using TAB (company-complete-common) instead of
>>> company-complete-selection'.
>> Then I guess that company-complete-common wouldn't want to pass
>> `finished' to the exit-function.
> It won't call the exit-function at all, currently, so when going though
> company-capf, exit-function would only be called with `finished'.
> That's another discrepancy, I guess.

completion-at-point doesn't always call exit-function either.
Maybe Company could be improved to call the exit-function from
company-complete-common in the same way as completion-at-point, but
that's just a "quality of implementation" issue, it shouldn't affect
the API, AFAICT.

        Stefan