Function: minibuffer-completion-help

minibuffer-completion-help is an interactive and byte-compiled function defined in minibuffer.el.gz.

Signature

(minibuffer-completion-help &optional START END)

Documentation

Display a list of possible completions of the current minibuffer contents.

View in manual

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/minibuffer.el.gz
(defun minibuffer-completion-help (&optional start end)
  "Display a list of possible completions of the current minibuffer contents."
  (interactive)
  (message "Making completion list...")
  (let* ((start (or start (minibuffer--completion-prompt-end)))
         (end (or end (point-max)))
         (string (buffer-substring start end))
         (md (completion--field-metadata start))
         (completion-lazy-hilit t)
         (completions (completion-all-completions
                       string
                       minibuffer-completion-table
                       minibuffer-completion-predicate
                       (- (point) start)
                       md)))
    (message nil)
    (if (or (null completions)
            (and (not (consp (cdr completions)))
                 (equal (car completions) string)))
        (progn
          ;; If there are no completions, or if the current input is already
          ;; the sole completion, then hide (previous&stale) completions.
          (minibuffer-hide-completions)
          (remove-hook 'after-change-functions #'completions--after-change t)
          (if completions
              (completion--message "Sole completion")
            (unless completion-fail-discreetly
	      (ding)
	      (completion--message "No match"))))

      (let* ((last (last completions))
             (base-size (or (cdr last) 0))
             (prefix (unless (zerop base-size) (substring string 0 base-size)))
             (minibuffer-completion-base (substring string 0 base-size))
             (ctable minibuffer-completion-table)
             (cpred minibuffer-completion-predicate)
             (cprops completion-extra-properties)
             (field-end
              (save-excursion
                (forward-char
                 (cdr (completion-boundaries (buffer-substring start (point))
                                             ctable
                                             cpred
                                             (buffer-substring (point) end))))
                (point)))
             (field-char (and (< field-end end) (char-after field-end)))
             (base-position (list (+ start base-size) field-end))
             (all-md (completion--metadata (buffer-substring-no-properties
                                            start (point))
                                           base-size md
                                           ctable
                                           cpred))
             (ann-fun (completion-metadata-get all-md 'annotation-function))
             (aff-fun (completion-metadata-get all-md 'affixation-function))
             (sort-fun (completion-metadata-get all-md 'display-sort-function))
             (group-fun (completion-metadata-get all-md 'group-function))
             (mainbuf (current-buffer))
             (current-candidate-and-offset
              (when-let* ((buffer (get-buffer "*Completions*"))
                          (window (get-buffer-window buffer 0)))
                (with-current-buffer buffer
                  (when-let* ((cand (completion-list-candidate-at-point
                                     (window-point window))))
                    (cons (car cand) (- (point) (cadr cand)))))))
             ;; If the *Completions* buffer is shown in a new
             ;; window, mark it as softly-dedicated, so bury-buffer in
             ;; minibuffer-hide-completions will know whether to
             ;; delete the window or not.
             (display-buffer-mark-dedicated 'soft))
        (with-current-buffer-window
          "*Completions*"
          ;; This is a copy of `display-buffer-fallback-action'
          ;; where `display-buffer-use-some-window' is replaced
          ;; with `display-buffer-at-bottom'.
          `((display-buffer--maybe-same-window
             display-buffer-reuse-window
             display-buffer--maybe-pop-up-frame
             ;; Use `display-buffer-below-selected' for inline completions,
             ;; but not in the minibuffer (e.g. in `eval-expression')
             ;; for which `display-buffer-at-bottom' is used.
             ,(if (eq (selected-window) (minibuffer-window))
                  'display-buffer-at-bottom
                'display-buffer-below-selected))
            (window-height . completions--fit-window-to-buffer)
            ,(when temp-buffer-resize-mode
               '(preserve-size . (nil . t)))
            (body-function
             . ,#'(lambda (window)
                    (with-current-buffer mainbuf
                      (when (or completion-auto-deselect completion-eager-update)
                        (add-hook 'after-change-functions #'completions--after-change nil t))
                      ;; Remove the base-size tail because `sort' requires a properly
                      ;; nil-terminated list.
                      (when last (setcdr last nil))

                      ;; Sort first using the `display-sort-function'.
                      ;; FIXME: This function is for the output of
                      ;; all-completions, not
                      ;; completion-all-completions.  Often it's the
                      ;; same, but not always.
                      (setq completions (if sort-fun
                                            (funcall sort-fun completions)
                                          (pcase completions-sort
                                            ('nil completions)
                                            ('alphabetical (minibuffer-sort-alphabetically completions))
                                            ('historical (minibuffer-sort-by-history completions))
                                            (_ (funcall completions-sort completions)))))

                      ;; After sorting, group the candidates using the
                      ;; `group-function'.
                      (when group-fun
                        (setq completions
                              (minibuffer--group-by
                               group-fun
                               (pcase completions-group-sort
                                 ('nil #'identity)
                                 ('alphabetical
                                  (lambda (groups)
                                    (sort groups
                                          (lambda (x y)
                                            (string< (car x) (car y))))))
                                 (_ completions-group-sort))
                               completions)))

                      (cond
                       (aff-fun
                        (setq completions
                              (funcall aff-fun completions)))
                       (ann-fun
                        (setq completions
                              (mapcar (lambda (s)
                                        (let ((ann (funcall ann-fun s)))
                                          (if ann (list s ann) s)))
                                      completions))))

                      (with-current-buffer standard-output
                        (setq-local completion-base-position base-position)
                        (setq-local completion-list-insert-choice-function
                               (lambda (start end choice)
                                 (unless (or (zerop (length prefix))
                                             (equal prefix
                                                    (buffer-substring-no-properties
                                                     (max (point-min)
                                                          (- start (length prefix)))
                                                     start)))
                                   (message "*Completions* out of date"))
                                 (when (> (point) end)
                                   ;; Completion suffix has changed, have to adapt.
                                   (setq end (+ end
                                                (cdr (completion-boundaries
                                                      (concat prefix choice) ctable cpred
                                                      (buffer-substring end (point))))))
                                   ;; Stopped before some field boundary.
                                   (when (> (point) end)
                                     (setq field-char (char-after end))))
                                 (when (and field-char
                                            (= (aref choice (1- (length choice)))
                                               field-char))
                                   (setq end (1+ end)))
                                 ;; Tried to use a marker to track buffer changes
                                 ;; but that clashed with another existing marker.
                                 (decf (nth 1 base-position)
                                          (- end start (length choice)))
                                 ;; FIXME: Use `md' to do quoting&terminator here.
                                 (completion--replace start (min end (point-max)) choice)
                                 (let* ((minibuffer-completion-table ctable)
                                        (minibuffer-completion-predicate cpred)
                                        (completion-extra-properties cprops)
                                        (result (concat prefix choice))
                                        (bounds (completion-boundaries
                                                 result ctable cpred "")))
                                   ;; If the completion introduces a new field, then
                                   ;; completion is not finished.
                                   (completion--done result
                                                     (if (eq (car bounds) (length result))
                                                         'exact 'finished))))))

                      (display-completion-list completions nil group-fun)
                      (when current-candidate-and-offset
                        (with-current-buffer standard-output
                          (when-let* ((match (text-property-search-forward
                                              'completion--string (car current-candidate-and-offset) t)))
                            (goto-char (prop-match-beginning match))
                            ;; Preserve the exact offset for the sake of
                            ;; `choose-completion-deselect-if-after'.
                            (forward-char (cdr current-candidate-and-offset))
                            (set-window-point window (point)))))))))
          nil)))
    nil))