branch: externals/cape
commit d5a17477033b2cd624b26daa74ac312579c23865
Author: Daniel Mendler <[email protected]>
Commit: Daniel Mendler <[email protected]>

    Add cape-capf-trigger
---
 CHANGELOG.org |  3 +++
 README.org    | 23 ++++++++++++++++-------
 cape.el       | 30 +++++++++++++++++++++++++++++-
 3 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.org b/CHANGELOG.org
index 830e3d83a3..bae707d283 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -7,6 +7,9 @@
 - Mark ~cape-capf-purify~ and ~cape-wrap-purify~ as obsolete.
 - ~cape-capf-sort~: Make ~SORT~ function argument optional. If the ~SORT~ 
argument is
   nil or not given, the completion UI sorting will take over.
+- ~cape-capf-trigger~, ~cape-wrap-trigger~: New Capf transformer for trigger
+  characters. The Capf will only complete if the trigger character occurs 
before
+  point.
 
 * Version 2.2 (2025-10-13)
 
diff --git a/README.org b/README.org
index 3652e3041c..d02571a72c 100644
--- a/README.org
+++ b/README.org
@@ -259,24 +259,33 @@ the Capf transformers with =defalias= to a function 
symbol.
 - ~cape-capf-silent~, ~cape-wrap-silent~: Silence Capf messages and errors.
 - ~cape-capf-sort~, ~cape-wrap-sort~: Add sort function to a Capf.
 - ~cape-capf-super~, ~cape-wrap-super~: Merge multiple Capfs into a Super-Capf.
+- ~cape-capf-trigger~, ~cape-wrap-trigger~: Create a Capf with a trigger 
character or string.
 
 In the following we show a few example configurations, which have come up on 
the
 [[https://github.com/minad/cape/issues][Cape]] or 
[[https://github.com/minad/corfu/issues][Corfu issue tracker]] or the 
[[https://github.com/minad/corfu/wiki][Corfu wiki.]] I use some of these tweaks 
in my
 personal configuration.
 
 #+begin_src emacs-lisp
-;; Example 1: Configure a Capf with a specific auto completion prefix length
+;; Example 1: Configure a merged Capf with a trigger prefix
+(setq-local completion-at-point-functions
+            (list (cape-capf-trigger
+                   (cape-capf-super #'cape-abbrev
+                                    #'cape-dabbrev
+                                    #'tempel-complete)
+                   ?/)))
+
+;; Example 2: Configure a Capf with a specific auto completion prefix length
 (setq-local completion-at-point-functions
             (list (cape-capf-prefix-length #'cape-dabbrev 2)))
 
-;; Example 2: Create a Capf with debugging messages
+;; Example 3: Create a Capf with debugging messages
 (setq-local completion-at-point-functions (list (cape-capf-debug #'cape-dict)))
 
-;; Example 3: Named Capf
+;; 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.
@@ -284,19 +293,19 @@ personal configuration.
   (cape-wrap-accept-all #'cape-dabbrev))
 (add-hook '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-capf-interactive 
#'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
             (list (cape-capf-predicate #'elisp-completion-at-point
                                        #'ignore-elisp-keywords)))
 
-;; Example 7: Catch errors with `cape-wrap-silent'.
+;; Example 8: Catch errors with `cape-wrap-silent'.
 (advice-add 'dabbrev-capf :around #'cape-wrap-silent)
 (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) ;; Was 
necessary on Emacs 28
 #+end_src
diff --git a/cape.el b/cape.el
index 3c7e502912..49dc0f4433 100644
--- a/cape.el
+++ b/cape.el
@@ -1216,6 +1216,33 @@ This function can be used as an advice around an 
existing Capf."
     (`(,beg ,end ,table . ,plist)
      `(,beg ,end ,(cape--accept-all-table table) . ,plist))))
 
+;;;###autoload
+(defun cape-wrap-trigger (capf trigger)
+  "Ensure that TRIGGER string or character occurs before point and then call 
CAPF.
+Example:
+  (setq completion-at-point-functions
+      (list (cape-capf-trigger \\='cape-abbrev ?/)))"
+  (setq trigger (if (stringp trigger) trigger (char-to-string trigger)))
+  (when-let ((tbeg (save-excursion (search-backward trigger (pos-bol) 
'noerror)))
+             (tend (+ tbeg (length trigger)))
+             ((save-excursion (not (re-search-backward "\\s-" tbeg 
'noerror)))))
+    (pcase (funcall capf)
+      (`(,beg ,end ,table . ,plist)
+       (when (<= tbeg beg tend)
+         (if (markerp beg)
+             (move-marker beg tend)
+           (setq beg tend))
+         (setq tbeg (copy-marker tbeg)
+               tend (copy-marker tend))
+         `( ,beg ,end ,table
+            :company-prefix-length t
+            :exit-function
+            ,(lambda (str status)
+               (delete-region tbeg tend)
+               (when-let ((exit (plist-get plist :exit-function)))
+                 (funcall exit str status)))
+            . ,plist))))))
+
 ;;;###autoload (autoload 'cape-capf-purify "cape")
 ;;;###autoload
 (defun cape-wrap-purify (capf)
@@ -1242,7 +1269,7 @@ This function can be used as an advice around an existing 
Capf."
                        #'cape-wrap-passthrough #'cape-wrap-predicate
                        #'cape-wrap-prefix-length #'cape-wrap-properties
                        'cape-wrap-purify #'cape-wrap-silent
-                       #'cape-wrap-sort #'cape-wrap-super))
+                       #'cape-wrap-sort #'cape-wrap-super #'cape-wrap-trigger))
   (let ((name (string-remove-prefix "cape-wrap-" (symbol-name wrapper))))
     (defalias (intern (format "cape-capf-%s" name))
       (lambda (capf &rest args) (lambda () (apply wrapper capf args)))
@@ -1266,6 +1293,7 @@ See `%s' for documentation." name wrapper wrapper))))
 ;;;###autoload (autoload 'cape-capf-properties "cape")
 ;;;###autoload (autoload 'cape-capf-silent "cape")
 ;;;###autoload (autoload 'cape-capf-super "cape")
+;;;###autoload (autoload 'cape-capf-trigger "cape")
 
 (defvar-keymap cape-prefix-map
   :doc "Keymap used as completion entry point.

Reply via email to