Subject: bug#33595: 26; Have `try-completion' or `completion--done' run abnormal hook if sole completion

From: Drew Adams <[email-masked]>
Date: Sun, 2 Dec 2018 20:07:07 -0800 (PST)

Enhancement request: When `try-completion' returns `t' there is a
"unique match which is exact".  Please add an abnormal hook at this
point, which accepts that sole completion as argument.

This feature would make it easier for callers of `completing-read',
`read-file-name', etc. to do something at that point with that sole
match, while the user can still change her minibuffer input.  For
example, the caller could display additional information about that sole
match.

This could alternatively be done in `completion--done', before it calls
`exit-fun', but it would also need to be done in the case where there is
no exit function.  `try-completion' is the logical place to do this, I
think, but it is coded in C.  I'm not sure which Lisp place would be
best as an alternative, if it's not `completion--done'.

A hook is handier for this than, say, defining an exit function that
tests for `finished' and binding `completion-extra-properties' to a list
that contains `:exit-function' with that function as value.  A hook lets
you add any number of such "sole completion" functions, and their use is
not tied to just one call of a completion function.

Here's a quick implementation using `completion--done'.  It may be all
that's required - not sure about the use of `unknown' as
`completion--done' arg FINISHED.  It just adds these two lines:

  (when (eq finished 'finished)
    (run-hook-with-args 'completion-sole-match-functions string))

(defun completion--done (string &optional finished message)
  (let* ((exit-fun (plist-get completion-extra-properties :exit-function))
         (pre-msg (and exit-fun (current-message))))
    (cl-assert (memq finished '(exact sole finished unknown)))
    (when (eq finished 'finished)
      (run-hook-with-args 'completion-sole-match-functions string))
    (when exit-fun
      (when (eq finished 'unknown)
        (setq finished
              (if (eq (try-completion string
                                      minibuffer-completion-table
                                      minibuffer-completion-predicate)
                      t)
                  'finished 'exact)))
      (funcall exit-fun string finished))
    (when (and message
               ;; Don't output any message if the exit-fun already did so.
               (equal pre-msg (and exit-fun (current-message))))
      (completion--message message))))

(defvar completion-sole-match-functions ()
  "Functions to be run when completion results in only one match.
Each function must accept that completion as its first arg.")

In GNU Emacs 26.1 (build 1, x86_64-w64-mingw32)
 of 2018-05-30
Repository revision: 07f8f9bc5a51f5aa94eb099f3e15fbe0c20ea1ea
Windowing system distributor `Microsoft Corp.', version 10.0.16299
Configured using:
 `configure --without-dbus --host=x86_64-w64-mingw32
 --without-compress-install 'CFLAGS=-O2 -static -g3''