Function: external-completion-table

external-completion-table is a byte-compiled function defined in external-completion.el.gz.

Signature

(external-completion-table CATEGORY LOOKUP &optional METADATA TRY-COMPLETION-FUNCTION)

Documentation

Make completion table using the external completion style.

The external style is particularly useful when the caller interfaces with an external tool that provides completions. This may be a shell utility, an inferior process, an http server, etc. Given a pattern string, the external tool matches it to an arbitrarily large set of candidates. Since the full set doesn't need to be transferred to Emacs's address space, this often results in much faster overall experience, at the expense of the convenience of offered by other completion styles.

CATEGORY is a symbol uniquely naming the external tool. This function links CATEGORY to the style external, by modifying completion-category-defaults, overriding any styles normally set in completion-styles.

LOOKUP is a function taking a string PATTERN and a number POINT. The function should contact the tool and return a list of strings representing the completions for PATTERN given that POINT is the location of point within it. LOOKUP decides if PATTERN is interpreted as a substring, a regular expression, or any other type of matching method. The strings returned may be propertized with completions-common-part to illustrate the specific method used. LOOKUP may ignore POINT if it doesn't meaningfully alter the results.

LOOKUP is a synchronous blocking function. Since it contacts an external tool, it's possible that it takes significant time to return results. To maintain Emacs's responsiveness, LOOKUP should detect pending user input using while-no-input or sit-for (which see). In those cases, LOOKUP should attempt to cancel the request (if possible) and immediately return any non-list.

METADATA is an alist of additional properties such as cycle-sort-function to associate with CATEGORY. This means that the caller may still retain control the sorting of the candidates while the tool controls the matching.

Optional TRY-COMPLETION-FUNCTION helps some frontends partially or fully expand PATTERN before finishing the completion operation. If supplied, it is a function taking a (PATTERN POINT ALL-COMPLETIONS), where PATTERN and POINT are as described above and ALL-COMPLETIONS are gathered by LOOKUP for these arguments (this function ensures LOOKUP isn't called more than needed). If you know the matching method that the external tool using, TRY-COMPLETION-FUNCTION may return a cons cell (EXPANDED-PATTERN . NEW-POINT). For example, if the tool is completing by prefix, one could call try-completion to find the largest common prefix in ALL-COMPLETIONS and then return that as EXPANDED-PATTERN.

Probably introduced at or before Emacs version 29.1.

Source Code

;; Defined in /usr/src/emacs/lisp/external-completion.el.gz
(defun external-completion-table (category lookup
                                           &optional metadata
                                           try-completion-function)
  "Make completion table using the `external' completion style.

The `external' style is particularly useful when the caller
interfaces with an external tool that provides completions.  This
may be a shell utility, an inferior process, an http server, etc.
Given a pattern string, the external tool matches it to an
arbitrarily large set of candidates.  Since the full set doesn't
need to be transferred to Emacs's address space, this often
results in much faster overall experience, at the expense of the
convenience of offered by other completion styles.

CATEGORY is a symbol uniquely naming the external tool.  This
function links CATEGORY to the style `external', by modifying
`completion-category-defaults', overriding any styles normally
set in `completion-styles'.

LOOKUP is a function taking a string PATTERN and a number
POINT.  The function should contact the tool and return a list of
strings representing the completions for PATTERN given that POINT
is the location of point within it.  LOOKUP decides if PATTERN is
interpreted as a substring, a regular expression, or any other
type of matching method.  The strings returned may be propertized
with `completions-common-part' to illustrate the specific method
used.  LOOKUP may ignore POINT if it doesn't meaningfully alter
the results.

LOOKUP is a synchronous blocking function.  Since it contacts an
external tool, it's possible that it takes significant time to
return results.  To maintain Emacs's responsiveness, LOOKUP
should detect pending user input using `while-no-input' or
`sit-for' (which see).  In those cases, LOOKUP should attempt to
cancel the request (if possible) and immediately return any
non-list.

METADATA is an alist of additional properties such as
`cycle-sort-function' to associate with CATEGORY.  This means
that the caller may still retain control the sorting of the
candidates while the tool controls the matching.

Optional TRY-COMPLETION-FUNCTION helps some frontends partially
or fully expand PATTERN before finishing the completion
operation.  If supplied, it is a function taking a (PATTERN POINT
ALL-COMPLETIONS), where PATTERN and POINT are as described above
and ALL-COMPLETIONS are gathered by LOOKUP for these
arguments (this function ensures LOOKUP isn't called more than
needed).  If you know the matching method that the external tool
using, TRY-COMPLETION-FUNCTION may return a cons
cell (EXPANDED-PATTERN . NEW-POINT).  For example, if the tool is
completing by prefix, one could call `try-completion' to find the
largest common prefix in ALL-COMPLETIONS and then return that as
EXPANDED-PATTERN."
  (let ((probe (alist-get category completion-category-defaults)))
    (if probe
        (cl-assert (equal '(external) (alist-get 'styles probe))
                   nil "Category `%s' must only use `external' style" category)
        (push `(,category (styles external))
              completion-category-defaults)))
  (let ((cache (make-hash-table :test #'equal)))
    (cl-flet ((lookup-internal (string point)
                (let* ((key (cons string point))
                       (probe (gethash key cache 'external--notfound)))
                  (if (eq probe 'external--notfound)
                      (puthash key (funcall lookup string point) cache)
                    probe))))
      (lambda (string pred action)
        (pcase action
          (`metadata
           `(metadata (category . ,category) . ,metadata))
          ;; Note: the `--tryc' `--allc' suffixes are made awkward on
          ;; purpose, so it's easy to pick them apart from the jungle
          ;; of combinations of "try" and "all" and "completion" that
          ;; inhabit Emacs's completion logic.
          (`(external-completion--tryc . ,point)
           ;; FIXME: Obey `pred'?  Pass it to `try-completion-function'?
           `(external-completion--tryc
             . ,(if try-completion-function
                    (funcall try-completion-function
                             string
                             point
                             (lookup-internal string point))
                  (cons string point))))
          (`(external-completion--allc . ,point)
           (let ((all (lookup-internal string point)))
             `(external-completion--allc
               . ,(if pred (cl-remove-if-not pred all) all))))
          (`(boundaries . ,_) nil)
          (_method
           (let ((all (lookup-internal string (length string))))
             ;; This branch might be taken:
             ;;
             ;; * when users work around
             ;;   `completion-category-defaults' (via
             ;;   `completion-category-overrides') and access this
             ;;   table with another completion style.  We assume
             ;;   these users know what they are doing, but it might
             ;;   not work very well, as this whatever is in `all'
             ;;   very often doesn't equate the full set of candidates
             ;;   (many tools cap to sth like 100-1000 results).
             ;;
             ;; * when `_method' is nil or `lambda' which some
             ;;   frontends will invoke.  Here, `all' should be
             ;;   sufficient information for `complete-with-action' to
             ;;   do the job correctly.
             (complete-with-action action all string pred))))))))