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

From: Drew Adams <[email-masked]>
Date: Mon, 3 Dec 2018 10:52:55 -0800 (PST)

The attached patch implements this enhancement.

Simple example use cases:

(defun my-find-file-other-window (filename &optional wildcards)
  "`find-file-other-window', but show file info if only one completion matches."
  (interactive
   (unwind-protect
       (progn
         (add-hook 'completion-sole-match-functions 'describe-file)
         (find-file-read-args "Find file in other window: "
                              (confirm-nonexistent-file-or-buffer)))
     (remove-hook 'completion-sole-match-functions 'describe-file)))
  (find-file-other-window filename wildcards))

(defun my-describe-function (function)
  "`describe-function', but show output if only one completion matches."
  (interactive
   (unwind-protect
       (progn
         (add-hook 'completion-sole-match-functions
                   (lambda (fn) (describe-function (intern fn))))
         (let* ((fn (function-called-at-point))
                (enable-recursive-minibuffers t)
                (val (completing-read
                      (if fn
                          (format "Describe function (default %s): " fn)
                        "Describe function: ")
                      #'help--symbol-completion-table
                      (lambda (f)
                        (or (fboundp f) (get f 'function-documentation)))
                      t nil nil
                      (and fn (symbol-name fn)))))
           (unless (equal val "")
             (setq fn (intern val)))
           (unless (and fn (symbolp fn))
             (user-error "You didn't specify a function symbol"))
           (unless (or (fboundp fn) (get fn 'function-documentation))
             (user-error "Symbol's function definition is void: %s" fn))
           (list fn))))
   (remove-hook 'completion-sole-match-functions
                (lambda (fn) (describe-function (intern fn)))))
  (describe-function function))

----

Or, using macro `with-hook-added' (see bug #33601):

(defun my-find-file-other-window (filename &optional wildcards)
  "`find-file-other-window', but show file info if only one completion matches."
  (interactive
   (with-hook-added completion-sole-match-functions
     describe-file
     (find-file-read-args "Find file in other window: "
                          (confirm-nonexistent-file-or-buffer))))
  (find-file-other-window filename wildcards))

(defun my-describe-function (function)
  "`describe-function', but show output if only one completion matches."
  (interactive
   (with-hook-added completion-sole-match-functions
     (lambda (fn) (describe-function (intern fn)))
     (let* ((fn (function-called-at-point))
            (enable-recursive-minibuffers t)
            (val (completing-read
                  (if fn
                      (format "Describe function (default %s): " fn)
                    "Describe function: ")
                  #'help--symbol-completion-table
                  (lambda (f)
                    (or (fboundp f) (get f 'function-documentation)))
                  t nil nil
                  (and fn (symbol-name fn)))))
       (unless (equal val "")
         (setq fn (intern val)))
       (unless (and fn (symbolp fn))
         (user-error "You didn't specify a function symbol"))
       (unless (or (fboundp fn) (get fn 'function-documentation))
         (user-error "Symbol's function definition is void: %s" fn))
       (list fn))))
  (describe-function function))