Subject: bug#65348: INITIAL-INPUT in completing-read repeats same entry twice consecutively

From: Drew Adams <[email-masked]>
Date: Mon, 21 Aug 2023 00:23:08 +0000

> > In case you're thinking, for your "obvious" use
> > cases, of a case where you have few completion
> > candidates, such as just "alpha", "beta", "gamma",
> > then let's not forget that you can already cycle
> > among those now, as completion candidates, without
> > having them added to the future history.  That's
> > available since Stefan added candidate cycling,
> > AFAIK.
> 
> Your answers are too short.  Please elaborate
> what do you mean by "candidate cycling" and
> what keys do you press to cycle candidates?

Sorry.  First, I'm no expert on the cycling provided
by vanilla Emacs.  I believe Stefan introduced it.
He can probably tell you more, and better.

There are two different completion metadata entries,
`display-sort-function' and `cycle-sort-function'.
See (elisp) `Programmed Completion':

https://www.gnu.org/software/emacs/manual/html_node/elisp/Programmed-Completion.html

(I don't see why anyone would ever want those two to
have different values, but I don't think my ignorance
about that is very relevant here.)

Dunno whether there is some key that, by _default_,
invokes one or the other of those functions.

I use them in a two of my libraries, `sortie.el'
and `keysee.el', to use vanilla Emacs cycling
for cycling and display, together.

With sortie.el, when you hit a key (`C-,' by
default) the candidates in *Completions* are
re-sorted, and so are the candidates you cycle
through (same sort order).  So when you cycle to
a candidate, that's also the current candidate
in *Completions*.

To turn on cycling you need to give
`completion-cycle-threshold' a non-nil value.
Then you can cycle among candidates using `TAB'.

keysee.el uses key descriptions as candidates.
sortie.el uses sort orders (functions) as
candidates.  keysee.el uses sortie.el to let you
change how its candidate key descriptions are
sorted.

In the Commentary of sortie there's a simple
example of using the features it provides.
Here's most of that example:

(defun my-completion-with-sort-cycling ()
  "Read and echo choice using completion with sort-order cycling."
  (interactive)
  (minibuffer-with-setup-hook #'sorti-bind-cycle-key
    (let ((sorti-current-order          'order1)
          (sorti-sort-function-chooser  'my-sort-fn-chooser)
          (sorti-sort-orders-alist      '((order1 . "alphabetical")
                                          (order2 . "by length")))
          (sorti-sort-orders-ring       (let ((rng  (make-ring 4)))
                                          (ring-insert rng 'order1)
                                          (ring-insert rng 'order2)
                                          rng)))
      (message "RESULT: %S"
               (completing-read "fff: "
                                (my-collection-fn
                                 '("aa" "bb" "ab" "aaff" "c")))))))

(defun my-collection-fn (candidates)
  "Collection function that provides metadata for sorting.
Sorting is per the current value of `my-sort-fn-chooser'."
  (lambda (string pred action)
    (if (eq action 'metadata)
        (let ((order  (my-sort-fn-chooser)))
          `(metadata ,@(and order
                            `((display-sort-function . ,order)
                              (cycle-sort-function   . ,order)))))
      (complete-with-action action candidates string pred))))

(defun my-sort-fn-chooser ()
  "Return sort function for current value of `sorti-current-order'."
  (if (eq 'order2 sorti-current-order)
      'my-sort-by-length
    'my-sort-alphabetically))

So for example, with both sortie.el and keysee.el
loaded, if you turn on mode `kc-mode' then

* `S-TAB' shows currently available key bindings.
* `C-,' re-sorts them in a few different ways
  (for both *Completions* display and cycling).
  You cycle among the available sort orders, to
  choose one, with `completing-read'.
* `TAB' cycles among the key bindings, to choose
  one, with `completing-read'.
___

As I say, I don't know how others make use of the
vanilla cycling feature.  Maybe Emacs provides a
key for such cycling by default, but I doubt it.

I think you have to define the cycling yourself,
by defining a function (such as `my-collection-fn'
above) that dynamically sorts the candidates to
produce a COLLECTION that's sorted as desired.

But is it really needed - by default, i.e., in
general - to be able to cycle among all candidates
in COLLECTION?  Certainly some libraries, such as
Icicles, offer that, but it's not as if it's so
essential that vanilla Emacs should provide it by
default, I think.  It makes sense to give coders
ways to provide candidate cycling when they want
it for `completing-read'.

My main point was that IF any such cycling of
COLLECTION entries is provided, it need not, and
should NOT, be part of the history (future or not).
Leave the history cycling to minibuffer input
HISTORY and to DEFAULTS.  If you want cycling of
all candidates in COLLECTION then provide that as
a different kind of cycling (different key).

> Then maybe this cycling could be used instead of 'M-n'.

No, not in my opinion; not at all.

`M-n' should be only for cycling forward in the
history, just as `M-p' should be for cycling
backward.  Users should know that that's what's
being cycled, and that those things are NOT, in
general, candidates from COLLECTION.  (Think lax
completion.)

The "feature" of unequivocally adding COLLECTION
to the history mixes things that don't belong
together.  It doesn't help users, IMO; and it can
confuse them, by mixing carrots with car parts.

My call is to first-and-foremost give control to
(1) users interactively and (2) coders who call
`completing-read'.

We already have a way for any coder to add all of
COLLECTION to the "future history": use it as, or
include it in, the value of argument DEFAULTS.
_End of story._

That gives coders 100% control over such addition.
It's not blindly imposed on them.  And it's easy
to obtain when/if they want it.  Easy peasy.  They
already have COLLECTION - just pass it also as arg
DEFAULTS (or part of DEFAULTS).

Arg DEFAULTS should, _alone_, determine/define the
"future history".  You can do anything you want
with it, including get the current behavior that
gets imposed unilaterally.  But you need not live
with that imposition.

Do I want to argue this in emacs-devel?  Not really.
I really don't have time for such things these days.

But do I wish something were done to remove this
imposition and give control back to coders & users?
Absolutely.  If this makes sense to you, go for it.

And I think it's simple to do: (1) Stop filling
future history with COLLECTION, or at least provide
a simple means to stop that.  (2) Point out to users
that IF they want to for some reason (the "many" use
cases Eli hinted at), they can simply include all of
COLLECTION as, or in, the future history, by just
passing it as (or as part of) the list arg DEFAULTS.

What's more, they can sort it first, any way they
like.  And they can filter it, if they don't want to
include _all_ of COLLECTION.  The current "feature"
is brutal - it's a one-size-fits-none, IMO.  It was
never needed (DEFAULT suffices), and it can't be
turned off.

#2 is maybe not obvious, even though it has been
available since Day One.  If it were really so
useful in "many" situations then I think we would
have seen "many" users pass COLLECTION also as
DEFAULTS (e.g. before Emacs 23).  I seriously doubt
we'v seen many - maybe not even any.

Yet someone thought it was a great idea to impose
that behavior always, on everyone - every call to
`completing-read' that uses an explicit COLLECTION.
Dunno who did that, and as Eli says, apparently it
was done in Emacs 23.  I guess many of us just
never noticed it.

BTW, what about a COLLECTION that's not explicit,
that's realized bit by bit with a function?  That
doesn't work anyway for this "feature", I guess.
You need to manifest an explicit COLLECTION, in
order to add it to any history (history needs to
be manifest for the call to `completing-read').

(I guess if you know the candidate domain you can
use `all-completions' with a function COLLECTION
to get an explicit version, if you really need to
add it to the future history.)

HTH.  And BTW, thanks, Juri, for enhancing DEFAULT
to be able to be a list (long ago).
___

https://www.emacswiki.org/emacs/download/sortie.el

https://www.emacswiki.org/emacs/download/keysee.el