emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: "John Wiegley" <johnw@gnu.org>
To: emacs-orgmode@gnu.org
Subject: Allowing :PROPERTIES: drawer to appear at the end of entries
Date: Tue, 25 Apr 2023 15:53:08 -0700	[thread overview]
Message-ID: <m25y9jd163.fsf@newartisans.com> (raw)

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

I have about 21,000 headlines throughout my Org files, most of those tasks.
Nearly all of them have PROPERTIES drawers, and since those drawers appear at
the end of the entries, I've grown quite used to that arrangement. Anyway, it
didn't take much effort to adapt Org 9.x to allow for such positioning. This
patch is what I've been using, and it permits me to have the drawer either at
the beginning or the end.

What I haven't tested/modified yet is the code that drops items from the
cache, since that seems to also search for the properties re, yet I'm not sure
under what conditions that code is run...


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: properties-at-end.patch --]
[-- Type: text/x-patch, Size: 5432 bytes --]

--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -1018,6 +1018,20 @@ CONTENTS is the contents of the footnote-definition."
 
 ;;;; Headline
 
+(defcustom org-allow-properties-at-end t
+  "Allow the PROPERTIES drawer to appear at the end of an entry.
+Normally, for reasons of efficiency, the PROPERTIES drawer is
+expected to appear only at the beginning of an entry, after any
+scheduling lines. This avoids having to scan through a large
+entry in order to find its properties.
+
+When this option is non-nil, the PROPERIES drawer may also appear
+at the end of an entry. Note that this may adversely affect the
+speed of many operations, such as building the agenda."
+  :group 'org-todo
+  :type 'boolean
+  :package-version '(Org . "9.6.2"))
+
 (defun org-element--get-node-properties (&optional at-point-p?)
   "Return node properties for headline or property drawer at point.
 Upcase property names.  It avoids confusion between properties
@@ -1030,7 +1044,13 @@ parse properties for property drawer at point."
     (unless at-point-p?
       (forward-line)
       (when (looking-at-p org-element-planning-line-re) (forward-line)))
-    (when (looking-at org-property-drawer-re)
+    (when (if org-allow-properties-at-end
+              (and (re-search-forward org-property-drawer-re
+                                      (save-excursion
+                                        (outline-next-heading)
+                                        (point)) t)
+                   (goto-char (match-beginning 0)))
+            (looking-at org-property-drawer-re))
       (forward-line)
       (let ((end (match-end 0)) properties)
 	(while (< (line-end-position) end)
@@ -1158,8 +1178,14 @@ Assume point is at beginning of the headline."
                                             0)
                                           (point)))))
            (robust-end (and robust-begin
-                            (when (> (- contents-end 2) robust-begin)
-                              (- contents-end 2)))))
+                            (if (> (- contents-end 2) robust-begin)
+                                (min
+                                 (- contents-end 2)
+                                 (if (and org-allow-properties-at-end
+                                          (re-search-forward org-property-drawer-re
+                                                             contents-end t))
+                                     (- (match-beginning 0) 2)
+                                   (point-max)))))))
       (unless robust-end (setq robust-begin nil))
       (let ((headline
 	     (list 'headline
@@ -4246,13 +4272,14 @@ element it has to parse."
 	          (looking-at org-element-planning-line-re))
 	     (org-element-planning-parser limit))
             ;; Property drawer.
-            ((and (pcase mode
+            ((and (or org-allow-properties-at-end
+                      (pcase mode
 	                (`planning (eq ?* (char-after (line-beginning-position 0))))
 	                ((or `property-drawer `top-comment)
 		         (save-excursion
 		           (beginning-of-line 0)
 		           (not (looking-at "[[:blank:]]*$"))))
-	            (_ nil))
+	                (_ nil)))
 	          (looking-at org-property-drawer-re))
 	     (org-element-property-drawer-parser limit))
             ;; When not at bol, point is at the beginning of an item or
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -12342,19 +12342,29 @@ the document if before the first headline.  If it is not given,
 it will be found.  If the drawer does not exist, create it if
 FORCE is non-nil, or return nil."
   (org-with-wide-buffer
-   (let ((beg (cond (beg (goto-char beg))
+   (let* ((beg (cond (beg (goto-char beg))
 		     ((or (not (featurep 'org-inlinetask))
 			  (org-inlinetask-in-task-p))
 		      (org-back-to-heading-or-point-min t) (point))
 		     (t (org-with-limited-levels
 			 (org-back-to-heading-or-point-min t))
-		       (point)))))
+		        (point))))
+          (end (save-excursion
+                 (outline-next-heading)
+                 (point))))
      ;; Move point to its position according to its positional rules.
      (cond ((org-before-first-heading-p)
 	    (while (and (org-at-comment-p) (bolp)) (forward-line)))
 	   (t (forward-line)
 	      (when (looking-at-p org-planning-line-re) (forward-line))))
-     (cond ((looking-at org-property-drawer-re)
+     (cond ((and (< (point) end)
+                 (if org-allow-properties-at-end
+                     (and (re-search-forward org-property-drawer-re
+                                             (save-excursion
+                                               (outline-next-heading)
+                                               (point)) t)
+                          (goto-char (match-beginning 0)))
+                   (looking-at org-property-drawer-re)))
             (forward-line)
             (cons (point) (progn (goto-char (match-end 0))
 			         (line-beginning-position))))
@@ -20600,7 +20610,8 @@ properties, clocking lines and logbook drawers."
   ;; Skip planning information.
   (when (looking-at-p org-planning-line-re) (forward-line))
   ;; Skip property drawer.
-  (when (looking-at org-property-drawer-re)
+  (when (and (not org-allow-properties-at-end)
+             (looking-at org-property-drawer-re))
     (goto-char (match-end 0))
     (forward-line))
   ;; When FULL is not nil, skip more.

[-- Attachment #3: Type: text/plain, Size: 150 bytes --]


--
John Wiegley                  GPG fingerprint = 4710 CF98 AF9B 327B B80F
http://newartisans.com                          60E1 46C4 BD1A 7AC1 4BA2

             reply	other threads:[~2023-04-25 22:54 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-25 22:53 John Wiegley [this message]
2023-04-26  6:50 ` Allowing :PROPERTIES: drawer to appear at the end of entries Ihor Radchenko
2023-04-26  8:25   ` John Wiegley
2023-04-26  8:44     ` John Wiegley
2023-04-26  8:56     ` Ihor Radchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m25y9jd163.fsf@newartisans.com \
    --to=johnw@gnu.org \
    --cc=emacs-orgmode@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).