From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id CMHXIrC5PmPRJwEAbAwnHQ (envelope-from ) for ; Thu, 06 Oct 2022 13:19:12 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id qI33IrC5PmNWhQAA9RJhRA (envelope-from ) for ; Thu, 06 Oct 2022 13:19:12 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 2BE2B291B6 for ; Thu, 6 Oct 2022 13:19:12 +0200 (CEST) Received: from localhost ([::1]:52338 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ogOuF-0003tK-Es for larch@yhetil.org; Thu, 06 Oct 2022 07:19:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:42792) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ogOX2-0000yH-I9 for emacs-orgmode@gnu.org; Thu, 06 Oct 2022 06:55:12 -0400 Received: from mail-qk1-x72c.google.com ([2607:f8b0:4864:20::72c]:34307) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ogOX0-0001tp-JA for emacs-orgmode@gnu.org; Thu, 06 Oct 2022 06:55:12 -0400 Received: by mail-qk1-x72c.google.com with SMTP id g2so750202qkk.1 for ; Thu, 06 Oct 2022 03:55:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:message-id:in-reply-to:date:subject:cc:to:from :user-agent:references:from:to:cc:subject:date:message-id:reply-to; bh=rA47kJ3igUQeWnLZa1k57rpUx9OCHWsGYmgrkuV68Mk=; b=lcAOrYpiZ7TTGlQd6pjYDcanhHMlRlpgOydtVIwwRrE/H2QepinQoQ64Q1SPl/qTaq 6DlbJBFWD64xfdU7+h8mhB4kbwxEkmVoBq+ovnatzD7UcTL1D6PIHKGbGxaX5H0GWCeu xobn5DZk2ATGO9JgzHd89Htb6tbcOvYQ2lZ8USVDMvRXdvP2VzfCunOMjJKJSOdMj9Ig 5KroNJ8xod8FmETy2dRxegYfepNZzxXAiA2G5Alu/sfLtHtMOQ3KqGuALmzm/TBmprLd 9vZQZ8vNRELrmyR354fNYx77KqrxpPCj7FUQBcU49yppn3eAIHbBkK/W84tGGV6GhgLu DyYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:message-id:in-reply-to:date:subject:cc:to:from :user-agent:references:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=rA47kJ3igUQeWnLZa1k57rpUx9OCHWsGYmgrkuV68Mk=; b=7QenVO7LyT31MQGdsFg/my2Eata7ClQd2ZDXSylLmjTtDU0ZSl+9T2n33Rh0rb53ra zA5iPgMHOr6CxV91hkNyK4ovHmizajUi8c4GOONhrVeVgGvrGpfwI+RKTTR6wxjbU2wn VzyuDb0LrLmsaiqDNHupd76IPgHw+HwGk1A44dA6B3Lvw0pMZHV1RRKy+ipKjKNy+0pF r1YrIrYnSbMvw0+pnDWm405Z2BY5ICBFmPvaEjhLoGDLn8ku11D9teM3jzXvwcouoP17 EmRHieyikr/tbnZBtXgg9SmAdJZFTvLIdZ/UNvdxCFql2gk8tt/24Nvy/cILW6J9Sgvo lqhQ== X-Gm-Message-State: ACrzQf0p5sMZQHXtrodPDy4n+baLhG/6wOw1NsoJumfEfQTD9mHJSdOG yaB+9R7wP5Gkg8gjJQxeGhza35x9sYg= X-Google-Smtp-Source: AMsMyM7cCvlJ1fQBFlDeqDax+J19tBwaHfCF1De8srYSYk5yCp9dBVE6sBH4G/irW5OkFNua8gyKjQ== X-Received: by 2002:a05:620a:2903:b0:6cf:920f:435c with SMTP id m3-20020a05620a290300b006cf920f435cmr2575552qkp.741.1665053706723; Thu, 06 Oct 2022 03:55:06 -0700 (PDT) Received: from nbook ([2601:82:c200:166d:7a0:14e6:e26:75bd]) by smtp.gmail.com with ESMTPSA id bn30-20020a05620a2ade00b006e2d087fd63sm4001446qkb.63.2022.10.06.03.55.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Oct 2022 03:55:05 -0700 (PDT) References: <87mtalozym.fsf@gmail.com> <87czbg352p.fsf@gmail.com> <87bkqp7jgg.fsf@localhost> User-agent: mu4e 1.9.0; emacs 29.0.50 From: No Wayman To: Ihor Radchenko Cc: emacs-orgmode@gnu.org Subject: Re: [PATCH] DOCT integration: template specific hooks [9.5.5 (9.5.5-g003cc7 @ /home/n/.emacs.d/elpaca/builds/org/)] Date: Thu, 06 Oct 2022 06:47:48 -0400 In-reply-to: <87bkqp7jgg.fsf@localhost> Message-ID: <87sfk1gqyi.fsf@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=2607:f8b0:4864:20::72c; envelope-from=iarchivedmywholelife@gmail.com; helo=mail-qk1-x72c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Migadu-Flow: FLOW_IN X-Migadu-Country: US ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1665055152; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=rA47kJ3igUQeWnLZa1k57rpUx9OCHWsGYmgrkuV68Mk=; b=Nc733LWyDiAUvrEEZ5o06B+isbTeH9zrihCxyBVisWpA9k4zyL2G6Xhu3lRJSyxaYgIJvL 9D+xr2LXiYnYMG4A2GP5qDGgOLc7p5ktnw3uhoSwZ1bJxt9rgs5Jbego6bUKVXleQfXXUV DMWrYQD+GZ9u4V6FGOjBts+1RNHO7SUHjBHgctpIdVAhsyhNoyQSMPJG9h3rBg0aHfXY/7 TSJV6r63VlIDvY+XT0cKztwHiwqfpsLhqHc8XQr+LJZ7o2zz+WjgHZb1NNYCZaYDgzyvU0 G6YBU+LgSXpwWjUQl9o9rNhMAvEer5IfLvjVl4ScbutJ60lSydk1JA+7U365iw== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1665055152; a=rsa-sha256; cv=none; b=VZVzZL3FB7MQeIFbc/ewGt+UbKjJo6+IQomxeJy7umJA3riZccxzLVGhFJ+UeWVAyAISX8 OK5lJ4pV7nQcXho4cuSDcdQ72w9a6RnbwbCo4qtS0Iz2latLNm9E9tyTkIvWT7qWJpNQYb cv8TkEJHgCiJYFy5ZIwz/hdOdfHg/OL3ELcKCFtwfw0FVOVrOmEflig3fGWr0s44IpqMPg 2wXwA2hPFrS9b9lCxiqczBy19IulPDcJjRxFLMN5DPdYaDLiooeSkfrGwZzSN3HGrWqLpa UCQwuFNy/eDD3a9ev+grz2EwVGe8dYHIfd4zyZsftKPeDHy71pGMkGgyltrlyg== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=lcAOrYpi; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -2.37 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=lcAOrYpi; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Queue-Id: 2BE2B291B6 X-Spam-Score: -2.37 X-Migadu-Scanner: scn1.migadu.com X-TUID: s/4LD9j79+XV --=-=-= Content-Type: text/plain; format=flowed 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. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-org-capture-Add-template-hook-properties.patch Content-Description: revised >From 90f0c68e1149512b51230fd44ad728b38e5f088e Mon Sep 17 00:00:00 2001 From: Nicholas Vollmer 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: showlevels= 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 --=-=-=--