emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
@ 2022-09-27 10:46 No Wayman
  2022-09-27 11:06 ` No Wayman
  2022-09-27 20:56 ` No Wayman
  0 siblings, 2 replies; 7+ messages in thread
From: No Wayman @ 2022-09-27 10:46 UTC (permalink / raw)
  To: emacs-orgmode

The attached patch is the first step toward integrating DOCT[1] 
syntax into Org mode.
It adds property options to org-capture-templates which make it 
easier to run template-specific hooks.
The current approach for running such hooks involves adding to the 
desired global hook variable and filtering by the template's keys.
e.g.

#+begin_src emacs-lisp :lexical t
(defun +example-template-hook ()
  (when (eq (org-capture-get :key t) "e")
    (message "hook run")))

(add-hook 'org-capture-mode-hook #'+example-template-hook)

(let ((org-capture-templates '("e" "example" (file "") "")))
  (org-capture nil "e"))
#+end_src

The hook has to be maintained separately from the template 
declaration.
The criteria to determine the selected template is baked into the 
hook function.
This is fragile (change the binding for the template and you must 
update the hook function),
mixes concerns, and makes templates harder to share.

Contrast the above with the following syntax enabled by the 
attached patch: 

#+begin_src emacs-lisp :lexical t
(let ((org-capture-templates
       '(("t" "test" plain (file "/tmp/test.org")
          "test %?"
          :hook ((lambda () (insert "mode-hook\n")))
          :before-finalize ((lambda () (insert 
          "before-finalize\n")))
          ;; Only a message because this happens outside the 
          context
          ;; of the capture buffer.
          :after-finalize ((lambda () (message "after-finalize")))
          :prepare-finalize ((lambda () (insert 
          "prepare-finalize\n")))))))
  (org-capture nil "t"))
#+end_src

These template-specific hook functions run prior to their global 
counterparts.

Ihor, an implementation note: I have not used `run-hooks' with 
these because they have no associated symbol.
The functions are lists stored directly on `org-capture-plist'.

[1]: https://github.com/progfolio/doct


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
  2022-09-27 10:46 [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)] No Wayman
@ 2022-09-27 11:06 ` No Wayman
  2022-09-27 20:37   ` No Wayman
  2022-09-27 20:56 ` No Wayman
  1 sibling, 1 reply; 7+ messages in thread
From: No Wayman @ 2022-09-27 11:06 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 2086 bytes --]


No Wayman <iarchivedmywholelife@gmail.com> writes:

> The attached patch is the first step toward integrating DOCT[1] 
> syntax into Org mode.
> It adds property options to org-capture-templates which make it 
> easier to run template-specific hooks.
> The current approach for running such hooks involves adding to 
> the 
> desired global hook variable and filtering by the template's 
> keys.
> e.g.
>
> #+begin_src emacs-lisp :lexical t
> (defun +example-template-hook ()
>   (when (eq (org-capture-get :key t) "e")
>     (message "hook run")))
>
> (add-hook 'org-capture-mode-hook #'+example-template-hook)
>
> (let ((org-capture-templates '("e" "example" (file "") "")))
>   (org-capture nil "e"))
> #+end_src
>
>
> The hook has to be maintained separately from the template 
> declaration.
> The criteria to determine the selected template is baked into 
> the 
> hook function.
> This is fragile (change the binding for the template and you 
> must 
> update the hook function),
> mixes concerns, and makes templates harder to share.
>
> Contrast the above with the following syntax enabled by the 
> attached patch: 
>
> #+begin_src emacs-lisp :lexical t
> (let ((org-capture-templates
>        '(("t" "test" plain (file "/tmp/test.org")
>           "test %?"
>           :hook ((lambda () (insert "mode-hook\n")))
>           :before-finalize ((lambda () (insert 
>           "before-finalize\n")))
>           ;; Only a message because this happens outside the 
>           context
>           ;; of the capture buffer.
>           :after-finalize ((lambda () (message 
>           "after-finalize")))
>           :prepare-finalize ((lambda () (insert 
>           "prepare-finalize\n")))))))
>   (org-capture nil "t"))
> #+end_src
>
> These template-specific hook functions run prior to their global 
> counterparts.
>
> Ihor, an implementation note: I have not used `run-hooks' with 
> these because they have no associated symbol.
> The functions are lists stored directly on `org-capture-plist'.
>
> [1]: https://github.com/progfolio/doct

And, of course, the patch...


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-capture-Add-template-hook-properties.patch --]
[-- Type: text/x-patch, Size: 4049 bytes --]

From 790e8c517ba933025e50302e9c990ccf9265b55c Mon Sep 17 00:00:00 2001
From: Nicholas Vollmer <iarchivedmywholelife@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 | 21 +++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index ab8a295e5..ed2322949 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 list of functions run before `org-capture-mode-hook'
+    when the template is selected.
+
+ - ~:prepare-finalize~ ::
+
+    A list of functions run before `org-capture-prepare-finalize-hook'
+    when the template is selected.
+
+ - ~:before-finalize~ ::
+
+    A list of functions run before `org-capture-before-finalize-hook'
+    when the template is selected.
+
+ - ~:after-finalize~ ::
+
+    A 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..af1502ede 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 list of functions run before
+                     `org-capture-mode-hook' when the template is selected.
+
+ :prepare-finalize   A list of functions run before
+                     `org-capture-prepare-finalize-hook'
+                     when the template is selected.
+
+ :before-finalize    A list of functions run before
+                     `org-capture-before-finalize-hook'
+                     when the template is selected.
+
+ :after-finalize     A 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
@@ -751,6 +766,7 @@ captured item after finalizing."
 	       (buffer-base-buffer (current-buffer)))
     (error "This does not seem to be a capture buffer for Org mode"))
 
+  (mapc #'funcall (org-capture-get :prepare-finalize t))
   (run-hooks 'org-capture-prepare-finalize-hook)
 
   ;; Update `org-capture-plist' with the buffer-local value.  Since
@@ -823,6 +839,7 @@ captured item after finalizing."
       ;; the indirect buffer has been killed.
       (org-capture-store-last-position)
 
+      (mapc #'funcall (org-capture-get :before-finalize t))
       ;; Run the hook
       (run-hooks 'org-capture-before-finalize-hook))
 
@@ -871,6 +888,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 has been stored on `org-capture-plist'.
+    (mapc #'funcall (org-capture-get :after-finalize))
     (run-hooks 'org-capture-after-finalize-hook)
     ;; Special cases
     (cond
@@ -1147,6 +1167,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)
+  (mapc #'funcall (org-capture-get :hook t))
   (org-capture-mode 1))
 
 (defun org-capture-place-entry ()
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
  2022-09-27 11:06 ` No Wayman
@ 2022-09-27 20:37   ` No Wayman
  0 siblings, 0 replies; 7+ messages in thread
From: No Wayman @ 2022-09-27 20:37 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 57 bytes --]


Attached is a revision which fixes a typo in a comment.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: fix-typo --]
[-- Type: text/x-patch, Size: 4055 bytes --]

From af1d14439d6ada284b5f9b8f17a3da2a172808f1 Mon Sep 17 00:00:00 2001
From: Nicholas Vollmer <iarchivedmywholelife@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 | 21 +++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index ab8a295e5..ed2322949 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 list of functions run before `org-capture-mode-hook'
+    when the template is selected.
+
+ - ~:prepare-finalize~ ::
+
+    A list of functions run before `org-capture-prepare-finalize-hook'
+    when the template is selected.
+
+ - ~:before-finalize~ ::
+
+    A list of functions run before `org-capture-before-finalize-hook'
+    when the template is selected.
+
+ - ~:after-finalize~ ::
+
+    A 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..2004c91fa 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 list of functions run before
+                     `org-capture-mode-hook' when the template is selected.
+
+ :prepare-finalize   A list of functions run before
+                     `org-capture-prepare-finalize-hook'
+                     when the template is selected.
+
+ :before-finalize    A list of functions run before
+                     `org-capture-before-finalize-hook'
+                     when the template is selected.
+
+ :after-finalize     A 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
@@ -751,6 +766,7 @@ captured item after finalizing."
 	       (buffer-base-buffer (current-buffer)))
     (error "This does not seem to be a capture buffer for Org mode"))
 
+  (mapc #'funcall (org-capture-get :prepare-finalize t))
   (run-hooks 'org-capture-prepare-finalize-hook)
 
   ;; Update `org-capture-plist' with the buffer-local value.  Since
@@ -823,6 +839,7 @@ captured item after finalizing."
       ;; the indirect buffer has been killed.
       (org-capture-store-last-position)
 
+      (mapc #'funcall (org-capture-get :before-finalize t))
       ;; Run the hook
       (run-hooks 'org-capture-before-finalize-hook))
 
@@ -871,6 +888,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'.
+    (mapc #'funcall (org-capture-get :after-finalize))
     (run-hooks 'org-capture-after-finalize-hook)
     ;; Special cases
     (cond
@@ -1147,6 +1167,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)
+  (mapc #'funcall (org-capture-get :hook t))
   (org-capture-mode 1))
 
 (defun org-capture-place-entry ()
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
  2022-09-27 10:46 [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)] No Wayman
  2022-09-27 11:06 ` No Wayman
@ 2022-09-27 20:56 ` No Wayman
  2022-10-06  2:51   ` Ihor Radchenko
  1 sibling, 1 reply; 7+ messages in thread
From: No Wayman @ 2022-09-27 20:56 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 400 bytes --]


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.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: single-or-list-of-fns --]
[-- Type: text/x-patch, Size: 4823 bytes --]

From 780194a5af6a8a6c7fbb602e834dcbec78016070 Mon Sep 17 00:00:00 2001
From: Nicholas Vollmer <iarchivedmywholelife@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


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
  2022-09-27 20:56 ` No Wayman
@ 2022-10-06  2:51   ` Ihor Radchenko
  2022-10-06 10:47     ` No Wayman
  0 siblings, 1 reply; 7+ messages in thread
From: Ihor Radchenko @ 2022-10-06  2:51 UTC (permalink / raw)
  To: No Wayman; +Cc: emacs-orgmode



No Wayman <iarchivedmywholelife@gmail.com> writes:

> The attached patch is the first step toward integrating DOCT[1] 
> syntax into Org mode.

Thanks! This is most welcome.

> It adds property options to org-capture-templates which make it 
> easier to run template-specific hooks.
> ...
> Contrast the above with the following syntax enabled by the 
> attached patch: 
> 
> #+begin_src emacs-lisp :lexical t
> (let ((org-capture-templates
>        '(("t" "test" plain (file "/tmp/test.org")
> 	  "test %?"
> 	  :hook ((lambda () (insert "mode-hook\n")))
> 	  :before-finalize ((lambda () (insert 
> 	  "before-finalize\n")))
> 	  ;; Only a message because this happens outside the 
> 	  context
> 	  ;; of the capture buffer.
> 	  :after-finalize ((lambda () (message "after-finalize")))
> 	  :prepare-finalize ((lambda () (insert 
> 	  "prepare-finalize\n")))))))
>   (org-capture nil "t"))
> #+end_src
> 
> These template-specific hook functions run prior to their global 
> counterparts.

LGTM.
 
> Ihor, an implementation note: I have not used `run-hooks' with 
> these because they have no associated symbol.
> The functions are lists stored directly on `org-capture-plist'.

Then, please add an appropriate comment in the code.

> See attached patch.
>
> From 780194a5af6a8a6c7fbb602e834dcbec78016070 Mon Sep 17 00:00:00 2001
> From: Nicholas Vollmer <iarchivedmywholelife@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.
Nitpick: Execute

> (org-capture-place-template): execute :hook functions.

> * doc/org-manual.org Document template hook properties.

You also need to add an appropriate ORG-NEWS entry.

> +  - ~:hook~ ::
> +
> +    A function or list of functions run before `org-capture-mode-hook'
> +    when the template is selected.

You did not mention the number of arguments passed to the functions.

> + - ~: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.

In the above, please use the quoting consistently. This is an Org file,
so do not use `symbol'. Instead, use ~symbol', as documented in
doc/Documentation_Standards.org

>   :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.

Again, the number of arguments passed to the hooks should be documented.

>  
> +(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'."

It is unclear what "KEYWORD functions" refers to.

> +  (let ((value (org-capture-get keyword local)))
> +    (if (functionp value)
> +        (funcall value)
> +      (mapc #'funcall value))))

The reasoning why not `run-hooks' might be commented here.

>  
> +    ;; Do not use the local arg to `org-capture-get' here.
> +    ;; The buffer-local value has been stored on `org-capture-plist'.

Did you mean "... local arg to `org-capture--run-template-function'"?

> +    (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))

Here and above, it would be a bit more clear to use something like
'local instead of t argument.

Also, please add some tests into testing/lisp/test-org-capture.el.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
  2022-10-06  2:51   ` Ihor Radchenko
@ 2022-10-06 10:47     ` No Wayman
  2022-10-07  5:42       ` Ihor Radchenko
  0 siblings, 1 reply; 7+ messages in thread
From: No Wayman @ 2022-10-06 10:47 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 219 bytes --]



I've addressed your comments in the attached patch.
I based it off the most recent patch in the thread.
The main difference is that the hook properties accept a single 
nullary function or list of nullary functions.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: revised --]
[-- Type: text/x-patch, Size: 8737 bytes --]

From 90f0c68e1149512b51230fd44ad728b38e5f088e Mon Sep 17 00:00:00 2001
From: Nicholas Vollmer <iarchivedmywholelife@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.

* etc/ORG-NEWS: Add news entry for template hook properties.

* testing/lisp/test-org-capture.el: Add tests for template hook properties.
---
 doc/org-manual.org               | 20 +++++++++++++++
 etc/ORG-NEWS                     |  6 +++++
 lisp/org-capture.el              | 32 ++++++++++++++++++++++++
 testing/lisp/test-org-capture.el | 43 ++++++++++++++++++++++++++++++++
 4 files changed, 101 insertions(+)

diff --git a/doc/org-manual.org b/doc/org-manual.org
index ab8a295e5..6a857529c 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 nullary function or list of nullary functions run before ~org-capture-mode-hook~
+    when the template is selected.
+
+ - ~:prepare-finalize~ ::
+
+    A nullary function or list of nullary functions run before ~org-capture-prepare-finalize-hook~
+    when the template is selected.
+
+ - ~:before-finalize~ ::
+
+    A nullary function or list of nullary functions run before ~org-capture-before-finalize-hook~
+    when the template is selected.
+
+ - ~:after-finalize~ ::
+
+    A nullary function or list of nullary 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/etc/ORG-NEWS b/etc/ORG-NEWS
index cab64317f..1a482c3c7 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -657,6 +657,12 @@ When exiting capture mode via ~org-capture-refile~, the variable
 ~org-refile-targets~ will be temporarily bound to the value of this
 template option.
 
+*** Add Capture template hook properties
+
+Capture templates can now attach template specific hooks via the following properties:
+~:hook~, ~:prepare-finalize~, ~:before-finalize~, ~:after-finalize~.
+These nullary functions run prior to their global counterparts for the selected template.
+
 *** New startup options =#+startup: show<n>levels=
 
 These startup options complement the existing =overview=, =content=,
diff --git a/lisp/org-capture.el b/lisp/org-capture.el
index 428d0ac0e..4b6b51b39 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 nullary function or list of nullary functions run before
+                     `org-capture-mode-hook' when the template is selected.
+
+ :prepare-finalize   A nullary function or list of nullary functions run before
+                     `org-capture-prepare-finalize-hook'
+                     when the template is selected.
+
+ :before-finalize    A nullary function or list of nullary functions run before
+                     `org-capture-before-finalize-hook'
+                     when the template is selected.
+
+ :after-finalize     A nullary function or list of nullary 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,17 @@ 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 funcitons associated with KEYWORD on template's plist.
+For valid values of KEYWORD see `org-capture-templates'.
+If LOCAL is non-nil use the buffer-local value of `org-capture-plist'."
+  ;; Used in place of `run-hooks' because these functions have no associated symbol.
+  ;; They are stored directly on `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 +777,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 'local)
   (run-hooks 'org-capture-prepare-finalize-hook)
 
   ;; Update `org-capture-plist' with the buffer-local value.  Since
@@ -823,6 +850,7 @@ captured item after finalizing."
       ;; the indirect buffer has been killed.
       (org-capture-store-last-position)
 
+      (org-capture--run-template-functions :before-finalize 'local)
       ;; Run the hook
       (run-hooks 'org-capture-before-finalize-hook))
 
@@ -871,6 +899,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--run-template-functions' 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 +1178,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 'local)
   (org-capture-mode 1))
 
 (defun org-capture-place-entry ()
diff --git a/testing/lisp/test-org-capture.el b/testing/lisp/test-org-capture.el
index 47c7ed129..44702c3ce 100644
--- a/testing/lisp/test-org-capture.el
+++ b/testing/lisp/test-org-capture.el
@@ -754,5 +754,48 @@
 	      (org-capture nil "t")
 	      (buffer-string))))))
 
+(ert-deftest test-org-capture/template-specific-hooks ()
+  "Test template-specific hook execution."
+  ;; Runs each template hook prior to corresponding global hook
+  (should
+   (equal "hook\nglobal-hook\nprepare\nglobal-prepare
+before\nglobal-before\nafter\nglobal-after"
+          (org-test-with-temp-text-in-file ""
+            (let* ((file (buffer-file-name))
+                   (org-capture-mode-hook
+                    '((lambda () (insert "global-hook\n"))))
+                   (org-capture-prepare-finalize-hook
+                    '((lambda () (insert "global-prepare\n"))))
+                   (org-capture-before-finalize-hook
+                    '((lambda () (insert "global-before\n"))))
+                   (org-capture-after-finalize-hook
+                    '((lambda () (with-current-buffer
+                                     (org-capture-get :buffer)
+                                   (goto-char (point-max))
+                                   (insert "global-after")))))
+                   (org-capture-templates
+                    `(("t" "Test" plain (file ,file) ""
+                       :hook (lambda () (insert "hook\n"))
+                       :prepare-finalize (lambda () (insert "prepare\n"))
+                       :before-finalize (lambda () (insert "before\n"))
+                       :after-finalize (lambda () (with-current-buffer
+                                                      (org-capture-get :buffer)
+                                                    (goto-char (point-max))
+                                                    (insert "after\n")))
+                       :immediate-finish t))))
+              (org-capture nil "t")
+              (buffer-string)))))
+  ;; Accepts a list of nullary functions
+  (should
+   (equal "one\ntwo"
+          (org-test-with-temp-text-in-file ""
+            (let* ((file (buffer-file-name))
+                   (org-capture-templates
+                    `(("t" "Test" plain (file ,file) ""
+                       :hook ((lambda () (insert "one\n"))
+                              (lambda () (insert "two")))))))
+              (org-capture nil "t")
+              (buffer-string))))))
+
 (provide 'test-org-capture)
 ;;; test-org-capture.el ends here
-- 
2.37.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)]
  2022-10-06 10:47     ` No Wayman
@ 2022-10-07  5:42       ` Ihor Radchenko
  0 siblings, 0 replies; 7+ messages in thread
From: Ihor Radchenko @ 2022-10-07  5:42 UTC (permalink / raw)
  To: No Wayman; +Cc: emacs-orgmode

No Wayman <iarchivedmywholelife@gmail.com> writes:

> I've addressed your comments in the attached patch.
> I based it off the most recent patch in the thread.
> The main difference is that the hook properties accept a single 
> nullary function or list of nullary functions.

Applied onto main with minor amendments (filling and missing ":" in the
commit message).

https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=7f3a6cf6e72fe9968c6ef32211c754b7fe0172b6

Thanks for your contribution!

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2022-10-07  5:44 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-27 10:46 [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)] No Wayman
2022-09-27 11:06 ` No Wayman
2022-09-27 20:37   ` No Wayman
2022-09-27 20:56 ` No Wayman
2022-10-06  2:51   ` Ihor Radchenko
2022-10-06 10:47     ` No Wayman
2022-10-07  5:42       ` Ihor Radchenko

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).