On second thought, I'd prefer the keywords to allow a single function or a list of functions. This prevents breakage with current DOCT syntax and is cleaner IMO. e.g.

#+begin_srce emacs-lisp :lexical t
(let ((org-capture-templates
      '(("t" "test" plain (file "/tmp/test.org") "test %?"
         :hook (lambda () (insert "PASS"))))))
 (org-capture nil "t"))
#+end_src

See attached patch.

>From 780194a5af6a8a6c7fbb602e834dcbec78016070 Mon Sep 17 00:00:00 2001
From: Nicholas Vollmer <iarchivedmywholel...@gmail.com>
Date: Tue, 27 Sep 2022 05:44:33 -0400
Subject: [PATCH] org-capture: Add template hook properties

* lisp/org-capture.el (org-capture-templates): Document template hook properties.
(org-capture-finalize): execute :prepare/:before/:after-finalize functions.
(org-capture-place-template): execute :hook functions.

* doc/org-manual.org Document template hook properties.
---
 doc/org-manual.org  | 20 ++++++++++++++++++++
 lisp/org-capture.el | 29 +++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index ab8a295e5..c1321f6cd 100644
--- a/doc/org-manual.org
+++ b/doc/org-manual.org
@@ -7838,6 +7838,26 @@ Now lets look at the elements of a template definition.  Each entry in
   - ~:refile-targets :: Temporarily set ~org-refile-targets~ to the
     value of this property.
 
+  - ~:hook~ ::
+
+    A function or list of functions run before `org-capture-mode-hook'
+    when the template is selected.
+
+ - ~:prepare-finalize~ ::
+
+    A function or list of functions run before `org-capture-prepare-finalize-hook'
+    when the template is selected.
+
+ - ~:before-finalize~ ::
+
+    A function or list of functions run before `org-capture-before-finalize-hook'
+    when the template is selected.
+
+ - ~:after-finalize~ ::
+
+    A function or list of functions run before `org-capture-after-finalize-hook'
+    when the template is selected.
+
 **** Template expansion
 :PROPERTIES:
 :DESCRIPTION: Filling in information about time and context.
diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index 428d0ac0e..e5528a849 100644
--- a/lisp/org-capture.el
+++ b/lisp/org-capture.el
@@ -297,6 +297,21 @@ properties are:
 
  :no-save            Do not save the target file after finishing the capture.
 
+ :hook               A function or list of functions run before
+                     `org-capture-mode-hook' when the template is selected.
+
+ :prepare-finalize   A function or list of functions run before
+                     `org-capture-prepare-finalize-hook'
+                     when the template is selected.
+
+ :before-finalize    A function or list of functions run before
+                     `org-capture-before-finalize-hook'
+                     when the template is selected.
+
+ :after-finalize     A function or list of functions run before
+                     `org-capture-after-finalize-hook'
+                     when the template is selected.
+
 The template defines the text to be inserted.  Often this is an
 Org mode entry (so the first line should start with a star) that
 will be filed as a child of the target headline.  It can also be
@@ -740,6 +755,14 @@ of the day at point (if any) or the current HH:MM time."
 	(format "* Template function %S not found" f)))
      (_ "* Invalid capture template"))))
 
+(defun org-capture--run-template-functions (keyword &optional local)
+  "Run template's KEYWORD functions.
+If LOCAL is non-nil use the buffer-local value of `org-capture-plist'."
+  (let ((value (org-capture-get keyword local)))
+    (if (functionp value)
+        (funcall value)
+      (mapc #'funcall value))))
+
 (defun org-capture-finalize (&optional stay-with-capture)
   "Finalize the capture process.
 With prefix argument STAY-WITH-CAPTURE, jump to the location of the
@@ -751,6 +774,7 @@ captured item after finalizing."
 	       (buffer-base-buffer (current-buffer)))
     (error "This does not seem to be a capture buffer for Org mode"))
 
+  (org-capture--run-template-functions :prepare-finalize t)
   (run-hooks 'org-capture-prepare-finalize-hook)
 
   ;; Update `org-capture-plist' with the buffer-local value.  Since
@@ -823,6 +847,7 @@ captured item after finalizing."
       ;; the indirect buffer has been killed.
       (org-capture-store-last-position)
 
+      (org-capture--run-template-functions :before-finalize t)
       ;; Run the hook
       (run-hooks 'org-capture-before-finalize-hook))
 
@@ -871,6 +896,9 @@ captured item after finalizing."
       ;; Restore the window configuration before capture
       (set-window-configuration return-wconf))
 
+    ;; Do not use the local arg to `org-capture-get' here.
+    ;; The buffer-local value has been stored on `org-capture-plist'.
+    (org-capture--run-template-functions :after-finalize)
     (run-hooks 'org-capture-after-finalize-hook)
     ;; Special cases
     (cond
@@ -1147,6 +1175,7 @@ may have been stored before."
     (`item (org-capture-place-item))
     (`checkitem (org-capture-place-item)))
   (setq-local org-capture-current-plist org-capture-plist)
+  (org-capture--run-template-functions :hook t)
   (org-capture-mode 1))
 
 (defun org-capture-place-entry ()
-- 
2.37.3

Reply via email to