emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/backend-completion 9eae95a8231: Add caching and yet more doc to


From: João Távora
Subject: scratch/backend-completion 9eae95a8231: Add caching and yet more doc to external-completion.el
Date: Sun, 4 Dec 2022 06:02:38 -0500 (EST)

branch: scratch/backend-completion
commit 9eae95a8231159627d4fc6e4699f263b963ba391
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>

    Add caching and yet more doc to external-completion.el
    
    * lisp/external-completion.el (cl-lib): Require cl-lib.
    (external-completion-table): Rework for caching.
---
 lisp/external-completion.el | 85 +++++++++++++++++++++++++++++++--------------
 1 file changed, 59 insertions(+), 26 deletions(-)

diff --git a/lisp/external-completion.el b/lisp/external-completion.el
index 17e26a4f4d8..4f5595e74bc 100644
--- a/lisp/external-completion.el
+++ b/lisp/external-completion.el
@@ -42,6 +42,8 @@
 ;; `external-completion-table' should be used.  See its docstring.
 
 ;;; Code:
+(require 'cl-lib)
+
 (add-to-list 'completion-styles-alist
              '(external
                external-completion--try-completion
@@ -86,35 +88,66 @@ to associate with CATEGORY.  This means that the caller may 
still
 retain control the sorting of the candidates while the tool
 controls the matching.
 
-Despite the original authors's best efforts,
-TRY-COMPLETION-FUNCTION is still a poorly understood
-implementation detail.  If you understand what it's for, you
-should definitely update this docstring, really!  Anyway, it's a
-function taking a (STRING POINT) as arguments.  The default is to
-use the function `cons' which returns the arguments as a cons
-cell."
+TRY-COMPLETION-FUNCTION is if you want to get fancy.  It's a
+function taking a (PATTERN POINT ALL-COMPLETIONS), where PATTERN
+and POINT are as described above and ALL-COMPLETIONS are all
+candidates previously gathered by LOOKUP (don't worry, we do some
+caching so it doesn't get called more than needed).  If you know
+how the external tool is interpreting PATTERN,
+TRY-COMPLETION-FUNCTION may return a cons cell (NEW-PATTERN
+. NEW-POINT) to partially (or fully) complete the user's
+completion input.  For example, if the tool is completing by
+prefix, you could use `try-completion' to find the largest prefix
+in ALL-COMPLETIONS and then return that as NEW-PATTERN.  If the
+tool is using something else, like \"flex\", it's probably
+useless.  Anyway, the default is to return simply a (PATTERN
+. POINT) unaltered."
   (unless (assq category completion-category-defaults)
     (push `(,category (styles external))
           completion-category-defaults))
-  (lambda (string pred action)
-    (pcase action
-      (`metadata
-       `(metadata (category . ,category) . ,metadata))
-      (`(external-completion--tryc . ,point)
-       ;; FIXME: Obey `pred'?  Pass it to `try-completion-function'?
-       `(external-completion--tryc
-         . ,(funcall (or try-completion-function #'cons) string point)))
-      (`(external-completion--allc . ,point)
-       (let ((all (funcall lookup string point)))
-         `(external-completion--allc . ,(if pred (seq-filter pred all) all))))
-      (`(boundaries . ,_) nil)
-      (_
-       ;; FIXME: Stefan had an extra call to `lookup' and
-       ;; `complete-with-action' again here.  `action' is usually
-       ;; `lambda' or `nil' in those cases.  Since calling `lookup'
-       ;; again is potentially slow and no useful result seems to come
-       ;; from it, I took it out.
-       ))))
+  (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))
+          (`(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 is here for two reasons:
+             ;;
+             ;; * for when users try to work around
+             ;;   `completion-category-defaults' and access this table a
+             ;;   non-`external' completion style.  It won't work very
+             ;;   well, as this `all' here very often doesn't equate
+             ;;   "the full set" (many tools cap to sth like 100-1000
+             ;;   results).  FIXME: I think it would be better to just
+             ;;   error here.
+             ;;
+             ;; * for when `_method' above can also be `nil' or `lambda'
+             ;;   which has some semantics and use I don't fully
+             ;;   understand.  It doesn't seem to do anything very
+             ;;   useful in my tests, but since we have caching it
+             ;;   doesn't seem to hurt much either.
+             (complete-with-action action all string pred))))))))
 
 ;; Note: the "tryc", "allc" suffixes are made akward on purpose, so
 ;; it's easy to pick them apart from the jungle of combinations of



reply via email to

[Prev in Thread] Current Thread [Next in Thread]