branch: externals/cape commit f5364cd1455fae83885092a32ab74e90a177c419 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
Add cape-wrap-debug and cape-capf-debug --- CHANGELOG.org | 4 ++++ README.org | 12 ++++++++---- cape.el | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.org b/CHANGELOG.org index 26a1636e02..8eb108dab6 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -2,6 +2,10 @@ #+author: Daniel Mendler #+language: en +* Development + +- Add =cape-wrap-debug= and =cape-capf-debug= to add debug messages to a Capf. + * Version 0.17 (2023-08-14) - Bugfixes. diff --git a/README.org b/README.org index f70a0f6cf2..5a0b2836d4 100644 --- a/README.org +++ b/README.org @@ -252,6 +252,7 @@ the Capf transformers with =defalias= to a function symbol. - ~cape-interactive-capf~, ~cape-interactive~: Create a Capf which can be called interactively. - ~cape-wrap-accept-all~, ~cape-capf-accept-all~: Create a Capf which accepts every input as valid. +- ~cape-wrap-debug~, ~cape-capf-debug~: Create a Capf which prints debugging messages. - ~cape-wrap-silent~, ~cape-capf-silent~: Wrap a chatty Capf and silence it. - ~cape-wrap-purify~, ~cape-capf-purify~: Purify a broken Capf and ensure that it does not modify the buffer. - ~cape-wrap-nonexclusive~, ~cape-capf-nonexclusive:~ Mark Capf as non-exclusive. @@ -279,11 +280,14 @@ personal configuration. (setq-local completion-at-point-functions (list (cape-capf-prefix-length #'cape-dabbrev 2))) -;; Example 3: Named Capf +;; Example 3: Create a Capf with debugging messages +(setq-local completion-at-point-functions (list (cape-capf-debug #'cape-dict))) + +;; Example 4: Named Capf (defalias 'cape-dabbrev-min-2 (cape-capf-prefix-length #'cape-dabbrev 2)) (setq-local completion-at-point-functions (list #'cape-dabbrev-min-2)) -;; Example 4: Define a defensive Dabbrev Capf, which accepts all inputs. If you +;; Example 5: Define a defensive Dabbrev Capf, which accepts all inputs. If you ;; use Corfu and `corfu-auto=t', the first candidate won't be auto selected if ;; `corfu-preselect=valid', such that it cannot be accidentally committed when ;; pressing RET. @@ -291,12 +295,12 @@ personal configuration. (cape-wrap-accept-all #'cape-dabbrev)) (add-to-list 'completion-at-point-functions #'my-cape-dabbrev-accept-all) -;; Example 5: Define interactive Capf which can be bound to a key. Here we wrap +;; Example 6: Define interactive Capf which can be bound to a key. Here we wrap ;; the `elisp-completion-at-point' such that we can complete Elisp code ;; explicitly in arbitrary buffers. (keymap-global-set "C-c p e" (cape-interactive-capf #'elisp-completion-at-point)) -;; Example 6: Ignore :keywords in Elisp completion. +;; Example 7: Ignore :keywords in Elisp completion. (defun ignore-elisp-keywords (sym) (not (keywordp sym))) (setq-local completion-at-point-functions diff --git a/cape.el b/cape.el index fe45aa2abd..0ae93c0190 100644 --- a/cape.el +++ b/cape.el @@ -203,6 +203,45 @@ BODY is the wrapping expression." (let ((default-directory dir) (non-essential t)))))) +(defun cape--debug-print (obj &optional full) + "Print OBJ as string, truncate lists if FULL is nil." + (cond + ((symbolp obj) (symbol-name obj)) + ((functionp obj) "#<function>") + ((and (consp obj) (ignore-errors (length obj))) + (concat + "(" + (string-join (mapcar #'cape--debug-print (if full obj (take 5 obj))) " ") + (if (and (not full) (length> obj 5)) " ...)" ")"))) + (t (let ((print-level 2)) + (prin1-to-string obj))))) + +(defun cape--debug-table (table name) + "Create completion TABLE with debug messages. +NAME is the name of the Capf." + ;; TODO reuse `cape--wrapped-table' + (lambda (str pred action) + (let ((result (complete-with-action action table str pred))) + (if (and (eq action 'completion--unquote) (functionp (cadr result))) + (cl-callf cape--debug-table (cadr result) name) + (message + "%s(action=%S prefix=%S ignore-case=%S%s%s) => %s" + name + (pcase action + ('nil 'try) + ('t 'all) + ('lambda 'test) + (_ action)) + str completion-ignore-case + (if completion-regexp-list + (format " regexp=%s" (cape--debug-print completion-regexp-list t)) + "") + (if pred + (format " predicate=%s" (cape--debug-print pred)) + "") + (cape--debug-print result))) + result))) + (cl-defun cape--table-with-properties (table &key category (sort t) &allow-other-keys) "Create completion TABLE with properties. CATEGORY is the optional completion category. @@ -852,6 +891,26 @@ changed. The function `cape-company-to-capf' is experimental." (interactive (list t)) (if interactive (cape-interactive capf) (funcall capf)))) +;;;###autoload +(defun cape-wrap-debug (capf) + "Call CAPF and return a completion table which prints trace messages." + (let ((name (if (symbolp capf) (symbol-name capf) "capf"))) + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + (let* ((count 0) + (cands (all-completions "" table + (lambda (&rest _) (< (cl-incf count) 5))))) + (message + "%s() => beg=%s end=%s candidates=(%s%s)%s" + name beg end + (string-join (mapcar #'prin1-to-string cands) " ") + (and (> count 5) " ...") + (if plist (format " plist=%s" (cape--debug-print plist t)) ""))) + `(,beg ,end ,(cape--debug-table table name) . ,plist)) + (result + (message "%s() => %s (No completion)" + name (cape--debug-print result)))))) + ;;;###autoload (defun cape-wrap-buster (capf &optional valid) "Call CAPF and return a completion table with cache busting. @@ -1014,6 +1073,8 @@ This function can be used as an advice around an existing Capf." (cape--capf-wrapper buster) ;;;###autoload (autoload 'cape-capf-case-fold "cape") (cape--capf-wrapper case-fold) +;;;###autoload (autoload 'cape-capf-debug "cape") +(cape--capf-wrapper debug) ;;;###autoload (autoload 'cape-capf-inside-comment "cape") (cape--capf-wrapper inside-comment) ;;;###autoload (autoload 'cape-capf-inside-string "cape")