emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Kaushal Modi <kaushal.modi@gmail.com>
To: Nicolas Goaziou <mail@nicolasgoaziou.fr>,
	Bastien Guerry <bzg@gnu.org>, Paul Rankin <hello@paulwrankin.com>
Cc: emacs-org list <emacs-orgmode@gnu.org>
Subject: Re: Backward incompatible outline-invisible-p change in emacs master for Org (Was: 6 failing tests on master branch)
Date: Wed, 14 Jun 2017 16:03:17 +0000	[thread overview]
Message-ID: <CAFyQvY1mDrzZwYCffZoqKRyZ7Z36G18Lrdrq+oRcQw+H76eLcg@mail.gmail.com> (raw)
In-Reply-To: <CAFyQvY2fGdezRKdF5QZ78X89B2Ma-xp3oJQJsDqsgf5Xx7f13w@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 644 bytes --]

On Wed, Jun 14, 2017 at 10:56 AM Kaushal Modi <kaushal.modi@gmail.com>
wrote:

> One solution would be to have a new function "org-invisible-p" that
> restores the old definition of outline-invisible-p. Interestingly I find
> that an "org-invisible-p" did exist back then, but it was replaced with
> outline-invisible-p in 2011 (
> http://orgmode.org/cgit.cgi/org-mode.git/commit/?id=84d7165d74a5061413168af435d61453be217933
> ). Looks like that might need reverting.
>

Here's a patch for the above proposed solution.

With that applied, 'make test' now passes cleanly on emacs master. Running
'make single' also looks good.
-- 

Kaushal Modi

[-- Attachment #1.2: Type: text/html, Size: 1243 bytes --]

[-- Attachment #2: 0001-Fix-breakage-due-to-outline-invisible-p-defn-change-.patch --]
[-- Type: application/octet-stream, Size: 18505 bytes --]

From 0548946c6fc45355813fc2219f94205c4f103d96 Mon Sep 17 00:00:00 2001
From: Kaushal Modi <kaushal.modi@gmail.com>
Date: Wed, 14 Jun 2017 11:20:05 -0400
Subject: [PATCH] Fix breakage due to outline-invisible-p defn change in emacs
 26+

* lisp/org.el (org-invisible-p): New function.  Restore the behavior
of outline-invisible-p prior to the following commint on emacs master
<http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=9cc59ffbbb2f20fbbf1c72d2e0c9dc47c7906a99>.

* lisp/org.el (org-cycle-internal-local)
(org-clean-visibility-after-subtree-move, org-goto)
(org-get-location, org-move-subtree-down, org-copy-subtree)
(org-paste-subtree, org-next-link, org-mark-ring-goto)
(org-todo, org-deadline, org-schedule, org-set-tags)
(org-truely-invisible-p, org-invisible-p2)
(org-forward-heading-same-level, org-forward-paragraph)
(org-backward-paragraph, org-down-element)
(org-bookmark-jump-unhide, org-mark-jump-unhide):
* lisp/org-list.el (org-insert-item):
* lisp/org-crypt.el (org-encrypt-entry, org-decrypt-entry):
* lisp/org-clock.el (org-clock-load):
* lisp/org-archive.el (org-archive-subtree)
(org-archive-to-archive-sibling, org-toggle-archive-tag)
(org-archive-set-tag):
* contrib/lisp/org-drill.el (org-drill-hide-subheadings-if): Use
org-invisible-p instead of outline-invisible-p.

Reference:
<http://lists.gnu.org/archive/html/emacs-orgmode/2017-06/msg00230.html>
---
 contrib/lisp/org-drill.el |  4 +--
 lisp/org-archive.el       | 32 ++++++++++++-----------
 lisp/org-clock.el         |  2 +-
 lisp/org-crypt.el         |  4 +--
 lisp/org-list.el          |  4 +--
 lisp/org.el               | 65 ++++++++++++++++++++++++++---------------------
 6 files changed, 60 insertions(+), 51 deletions(-)

diff --git a/contrib/lisp/org-drill.el b/contrib/lisp/org-drill.el
index a78b8068ce..fb578ab863 100644
--- a/contrib/lisp/org-drill.el
+++ b/contrib/lisp/org-drill.el
@@ -1455,7 +1455,7 @@ How well did you do? %s"
 ;;     (save-excursion
 ;;       (org-map-entries
 ;;        (lambda ()
-;;          (when (and (not (outline-invisible-p))
+;;          (when (and (not (org-invisible-p))
 ;;                     (> (org-current-level) drill-entry-level))
 ;;            (setq drill-heading (org-get-heading t))
 ;;            (unless (and (= (org-current-level) (1+ drill-entry-level))
@@ -1480,7 +1480,7 @@ the current topic."
     (save-excursion
       (org-map-entries
        (lambda ()
-         (when (and (not (outline-invisible-p))
+         (when (and (not (org-invisible-p))
                     (> (org-current-level) drill-entry-level))
            (when (or (/= (org-current-level) (1+ drill-entry-level))
                         (funcall test))
diff --git a/lisp/org-archive.el b/lisp/org-archive.el
index c76abdb765..adb922e758 100644
--- a/lisp/org-archive.el
+++ b/lisp/org-archive.el
@@ -204,17 +204,19 @@ if LOCATION is not given, the value of `org-archive-location' is used."
 ;;;###autoload
 (defun org-archive-subtree (&optional find-done)
   "Move the current subtree to the archive.
-The archive can be a certain top-level heading in the current file, or in
-a different file.  The tree will be moved to that location, the subtree
-heading be marked DONE, and the current time will be added.
-
-When called with a single prefix argument FIND-DONE, find whole trees without any
-open TODO items and archive them (after getting confirmation from the user).
-When called with a double prefix argument, find whole trees with timestamps before
-today and archive them (after getting confirmation from the user).
-If the cursor is not at a headline when these commands are called, try all level
-1 trees.  If the cursor is on a headline, only try the direct children of
-this heading."
+The archive can be a certain top-level heading in the current
+file, or in a different file.  The tree will be moved to that
+location, the subtree heading be marked DONE, and the current
+time will be added.
+
+When called with a single prefix argument FIND-DONE, find whole
+trees without any open TODO items and archive them (after getting
+confirmation from the user).  When called with a double prefix
+argument, find whole trees with timestamps before today and
+archive them (after getting confirmation from the user).  If the
+cursor is not at a headline when these commands are called, try
+all level 1 trees.  If the cursor is on a headline, only try the
+direct children of this heading."
   (interactive "P")
   (if (and (org-region-active-p) org-loop-over-headlines-in-active-region)
       (let ((cl (if (eq org-loop-over-headlines-in-active-region 'start-level)
@@ -224,7 +226,7 @@ this heading."
 	 `(progn (setq org-map-continue-from (progn (org-back-to-heading) (point)))
 		 (org-archive-subtree ,find-done))
 	 org-loop-over-headlines-in-active-region
-	 cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
+	 cl (if (org-invisible-p) (org-end-of-subtree nil t))))
     (cond
      ((equal find-done '(4))  (org-archive-all-done))
      ((equal find-done '(16)) (org-archive-all-old))
@@ -422,7 +424,7 @@ Archiving time is retained in the ARCHIVE_TIME node property."
 		 (when (org-at-heading-p)
 		   (org-archive-to-archive-sibling)))
 	 org-loop-over-headlines-in-active-region
-	 cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
+	 cl (if (org-invisible-p) (org-end-of-subtree nil t))))
     (save-restriction
       (widen)
       (let (b e pos leader level)
@@ -570,7 +572,7 @@ the children that do not contain any open TODO items."
 	(org-map-entries
 	 `(org-toggle-archive-tag ,find-done)
 	 org-loop-over-headlines-in-active-region
-	 cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
+	 cl (if (org-invisible-p) (org-end-of-subtree nil t))))
     (if find-done
 	(org-archive-all-done 'tag)
       (let (set)
@@ -591,7 +593,7 @@ the children that do not contain any open TODO items."
 	(org-map-entries
 	 'org-archive-set-tag
 	 org-loop-over-headlines-in-active-region
-	 cl (if (outline-invisible-p) (org-end-of-subtree nil t))))
+	 cl (if (org-invisible-p) (org-end-of-subtree nil t))))
     (org-toggle-tag org-archive-tag 'on)))
 
 ;;;###autoload
diff --git a/lisp/org-clock.el b/lisp/org-clock.el
index e1a83ea8d6..d6dada7f0a 100644
--- a/lisp/org-clock.el
+++ b/lisp/org-clock.el
@@ -2962,7 +2962,7 @@ The details of what will be saved are regulated by the variable
 	     (let ((org-clock-in-resume 'auto-restart)
 		   (org-clock-auto-clock-resolution nil))
 	       (org-clock-in)
-	       (when (outline-invisible-p) (org-show-context))))))
+	       (when (org-invisible-p) (org-show-context))))))
 	(_ nil)))))
 
 ;; Suggested bindings
diff --git a/lisp/org-crypt.el b/lisp/org-crypt.el
index 4439c947c0..3c431e4fdd 100644
--- a/lisp/org-crypt.el
+++ b/lisp/org-crypt.el
@@ -176,7 +176,7 @@ See `org-crypt-disable-auto-save'."
    (let ((start-heading (point)))
      (org-end-of-meta-data)
      (unless (looking-at-p "-----BEGIN PGP MESSAGE-----")
-       (let ((folded (outline-invisible-p))
+       (let ((folded (org-invisible-p))
 	     (crypt-key (org-crypt-key-for-heading))
 	     (beg (point)))
 	 (goto-char start-heading)
@@ -204,7 +204,7 @@ See `org-crypt-disable-auto-save'."
 	   (heading-was-invisible-p
 	    (save-excursion
 	      (outline-end-of-heading)
-	      (outline-invisible-p))))
+	      (org-invisible-p))))
        (org-end-of-meta-data)
        (when (looking-at "-----BEGIN PGP MESSAGE-----")
 	 (org-crypt-check-auto-save)
diff --git a/lisp/org-list.el b/lisp/org-list.el
index a84452d30b..471ad59cf1 100644
--- a/lisp/org-list.el
+++ b/lisp/org-list.el
@@ -154,8 +154,8 @@
 (declare-function org-timer-item "org-timer" (&optional arg))
 (declare-function org-trim "org" (s &optional keep-lead))
 (declare-function org-uniquify "org" (list))
+(declare-function org-invisible-p "org" (&optional pos))
 (declare-function outline-flag-region "outline" (from to flag))
-(declare-function outline-invisible-p "outline" (&optional pos))
 (declare-function outline-next-heading "outline" ())
 (declare-function outline-previous-heading "outline" ())
 
@@ -2257,7 +2257,7 @@ item is invisible."
     (unless (or (not itemp)
 		(save-excursion
 		  (goto-char itemp)
-		  (outline-invisible-p)))
+		  (org-invisible-p)))
       (if (save-excursion
 	    (goto-char itemp)
 	    (org-at-item-timer-p))
diff --git a/lisp/org.el b/lisp/org.el
index e2e56f2284..722717f4ec 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -6880,6 +6880,11 @@ Use `\\[org-edit-special]' to edit table.el tables"))
 (defvar org-called-with-limited-levels nil
   "Non-nil when `org-with-limited-levels' is currently active.")
 
+(defun org-invisible-p (&optional pos)
+  "Non-nil if the character after POS is invisible.
+If POS is nil, use `point' instead."
+  (get-char-property (or pos (point)) 'invisible))
+
 (defun org-cycle-internal-local ()
   "Do the local cycling action."
   (let ((goal-column 0) eoh eol eos has-children children-skipped struct)
@@ -6923,7 +6928,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
       (save-excursion
 	(goto-char eos)
 	(outline-next-heading)
-	(when (outline-invisible-p) (org-flag-heading nil))))
+	(when (org-invisible-p) (org-flag-heading nil))))
      ((and (or (>= eol eos)
 	       (not (string-match "\\S-" (buffer-substring eol eos))))
 	   (or has-children
@@ -6957,7 +6962,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
       (save-excursion
 	(goto-char eos)
 	(outline-next-heading)
-	(when (outline-invisible-p) (org-flag-heading nil)))
+	(when (org-invisible-p) (org-flag-heading nil)))
       (setq org-cycle-subtree-status 'children)
       (unless (org-before-first-heading-p)
 	(run-hook-with-args 'org-cycle-hook 'children)))
@@ -7131,9 +7136,9 @@ This function is the default value of the hook `org-cycle-hook'."
 	  ;; Properly fold already folded siblings
 	  (goto-char (point-min))
 	  (while (re-search-forward re nil t)
-	    (when (and (not (outline-invisible-p))
+	    (when (and (not (org-invisible-p))
 		       (save-excursion
-			 (goto-char (point-at-eol)) (outline-invisible-p)))
+			 (goto-char (point-at-eol)) (org-invisible-p)))
 	      (outline-hide-entry))))
 	(org-cycle-show-empty-lines 'overview)
 	(org-cycle-hide-drawers 'overview)))))
@@ -7486,7 +7491,7 @@ With a prefix argument, use the alternative interface: e.g., if
 	(progn
 	  (org-mark-ring-push org-goto-start-pos)
 	  (goto-char selected-point)
-	  (when (or (outline-invisible-p) (org-invisible-p2))
+	  (when (or (org-invisible-p) (org-invisible-p2))
 	    (org-show-context 'org-goto)))
       (message "Quit"))))
 
@@ -7527,7 +7532,7 @@ or nil."
 	 (if (and (boundp 'org-goto-start-pos)
 		  (integer-or-marker-p org-goto-start-pos))
 	     (progn (goto-char org-goto-start-pos)
-		    (when (outline-invisible-p)
+		    (when (org-invisible-p)
 		      (org-show-set-visibility 'lineage)))
 	   (goto-char (point-min)))
 	 (let (org-special-ctrl-a/e) (org-beginning-of-line))
@@ -8384,7 +8389,7 @@ case."
       (setq beg (point)))
     (save-match-data
       (save-excursion (outline-end-of-heading)
-		      (setq folded (outline-invisible-p)))
+		      (setq folded (org-invisible-p)))
       (progn (org-end-of-subtree nil t)
 	     (unless (eobp) (backward-char))))
     (outline-next-heading)
@@ -8480,7 +8485,7 @@ useful if the caller implements cut-and-paste as copy-then-paste-then-cut."
       (if nosubtrees
 	  (outline-next-heading)
 	(save-excursion (outline-end-of-heading)
-			(setq folded (outline-invisible-p)))
+			(setq folded (org-invisible-p)))
 	(ignore-errors (org-forward-heading-same-level (1- n) t))
 	(org-end-of-subtree t t)))
     ;; Include the end of an inlinetask
@@ -8533,7 +8538,7 @@ When REMOVE is non-nil, remove the subtree from the clipboard."
 		(substitute-command-keys
 		 "The kill is not a (set of) tree(s) - please use \\[yank] to yank anyway")))
   (org-with-limited-levels
-   (let* ((visp (not (outline-invisible-p)))
+   (let* ((visp (not (org-invisible-p)))
 	  (txt tree)
 	  (^re_ "\\(\\*+\\)[  \t]*")
 	  (old-level (if (string-match org-outline-regexp-bol txt)
@@ -8590,7 +8595,7 @@ When REMOVE is non-nil, remove the subtree from the clipboard."
      (goto-char beg)
      (skip-chars-forward " \t\n\r")
      (setq beg (point))
-     (when (and (outline-invisible-p) visp)
+     (when (and (org-invisible-p) visp)
        (save-excursion (outline-show-heading)))
      ;; Shift if necessary
      (unless (= shift 0)
@@ -10438,7 +10443,7 @@ If the link is in hidden text, expose it."
     (if (funcall srch-fun org-any-link-re nil t)
 	(progn
 	  (goto-char (match-beginning 0))
-	  (when (outline-invisible-p) (org-show-context)))
+	  (when (org-invisible-p) (org-show-context)))
       (goto-char pos)
       (setq org-link-search-failed t)
       (message "No further link found"))))
@@ -11141,7 +11146,7 @@ or to another Org file, automatically push the old position onto the ring."
     (setq m (car p))
     (pop-to-buffer-same-window (marker-buffer m))
     (goto-char m)
-    (when (or (outline-invisible-p) (org-invisible-p2)) (org-show-context 'mark-goto))))
+    (when (or (org-invisible-p) (org-invisible-p2)) (org-show-context 'mark-goto))))
 
 (defun org-add-angle-brackets (s)
   (unless (equal (substring s 0 1) "<") (setq s (concat "<" s)))
@@ -12392,7 +12397,7 @@ When called through ELisp, arg is also interpreted in the following way:
 	(org-map-entries
 	 `(org-todo ,arg)
 	 org-loop-over-headlines-in-active-region
-	 cl (when (outline-invisible-p) (org-end-of-subtree nil t))))
+	 cl (when (org-invisible-p) (org-end-of-subtree nil t))))
     (when (equal arg '(16)) (setq arg 'nextset))
     (when (equal arg -1) (org-cancel-repeater) (setq arg nil))
     (let ((org-blocker-hook org-blocker-hook)
@@ -13320,7 +13325,7 @@ can either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
        (if (eq org-loop-over-headlines-in-active-region 'start-level)
 	   'region-start-level
 	 'region)
-       (lambda () (when (outline-invisible-p) (org-end-of-subtree nil t))))
+       (lambda () (when (org-invisible-p) (org-end-of-subtree nil t))))
     (org--deadline-or-schedule arg 'deadline time)))
 
 (defun org-schedule (arg &optional time)
@@ -13337,7 +13342,7 @@ either be an Org date like \"2011-07-24\" or a delta like \"+2d\"."
        (if (eq org-loop-over-headlines-in-active-region 'start-level)
 	   'region-start-level
 	 'region)
-       (lambda () (when (outline-invisible-p) (org-end-of-subtree nil t))))
+       (lambda () (when (org-invisible-p) (org-end-of-subtree nil t))))
     (org--deadline-or-schedule arg 'scheduled time)))
 
 (defun org-get-scheduled-time (pom &optional inherit)
@@ -14884,7 +14889,7 @@ When JUST-ALIGN is non-nil, only align tags."
          #'org-set-tags
          org-loop-over-headlines-in-active-region
          cl
-	 '(when (outline-invisible-p) (org-end-of-subtree nil t))))
+	 '(when (org-invisible-p) (org-end-of-subtree nil t))))
     (let ((org-setting-tags t))
       (if arg
           (save-excursion
@@ -23847,16 +23852,18 @@ interactive command with similar behavior."
   "Check if point is at a character currently not visible.
 This version does not only check the character property, but also
 `visible-mode'."
-  ;; Early versions of noutline don't have `outline-invisible-p'.
   (unless (bound-and-true-p visible-mode)
-    (outline-invisible-p)))
+    (org-invisible-p)))
 
 (defun org-invisible-p2 ()
-  "Check if point is at a character currently not visible."
+  "Check if point is at a character currently not visible.
+
+If the point is at EOL (and not at the beginning of a buffer too),
+move it back by one char before doing this check."
   (save-excursion
-    (when (and (eolp) (not (bobp))) (backward-char 1))
-    ;; Early versions of noutline don't have `outline-invisible-p'.
-    (outline-invisible-p)))
+    (when (and (eolp) (not (bobp)))
+      (backward-char 1))
+    (org-invisible-p)))
 
 (defun org-back-to-heading (&optional invisible-ok)
   "Call `outline-back-to-heading', but provide a better error message."
@@ -24126,7 +24133,7 @@ non-nil it will also look at invisible ones."
 	    (cond ((< l level) (setq count 0))
 		  ((and (= l level)
 			(or invisible-ok
-			    (not (outline-invisible-p
+			    (not (org-invisible-p
 				  (line-beginning-position)))))
 		   (cl-decf count)
 		   (when (= l level) (setq result (point)))))))
@@ -24262,7 +24269,7 @@ item, etc.  It also provides some special moves for convenience:
           ;; With no contents, just skip element.
           ((not contents-begin) (goto-char end))
           ;; If contents are invisible, skip the element altogether.
-          ((outline-invisible-p (line-end-position))
+          ((org-invisible-p (line-end-position))
            (cl-case type
              (headline
               (org-with-limited-levels (outline-next-visible-heading 1)))
@@ -24349,7 +24356,7 @@ convenience:
       (org-backward-paragraph))
      (t (goto-char (or post-affiliated begin))))
     ;; Ensure we never leave point invisible.
-    (when (outline-invisible-p (point)) (beginning-of-visual-line))))
+    (when (org-invisible-p (point)) (beginning-of-visual-line))))
 
 (defun org-forward-element ()
   "Move forward by one element.
@@ -24426,7 +24433,7 @@ Move to the previous element at the same level, when possible."
       (forward-char))
      ((memq (org-element-type element) org-element-greater-elements)
       ;; If contents are hidden, first disclose them.
-      (when (outline-invisible-p (line-end-position)) (org-cycle))
+      (when (org-invisible-p (line-end-position)) (org-cycle))
       (goto-char (or (org-element-property :contents-begin element)
 		     (user-error "No content for this element"))))
      (t (user-error "No inner element")))))
@@ -24907,15 +24914,15 @@ ELEMENT is the element at point."
 (defun org-bookmark-jump-unhide ()
   "Unhide the current position, to show the bookmark location."
   (and (derived-mode-p 'org-mode)
-       (or (outline-invisible-p)
+       (or (org-invisible-p)
 	   (save-excursion (goto-char (max (point-min) (1- (point))))
-			   (outline-invisible-p)))
+			   (org-invisible-p)))
        (org-show-context 'bookmark-jump)))
 
 (defun org-mark-jump-unhide ()
   "Make the point visible with `org-show-context' after jumping to the mark."
   (when (and (derived-mode-p 'org-mode)
-	     (outline-invisible-p))
+	     (org-invisible-p))
     (org-show-context 'mark-goto)))
 
 (eval-after-load "simple"
-- 
2.13.0


  reply	other threads:[~2017-06-14 16:03 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-08 20:33 6 failing tests on master branch Kaushal Modi
2017-06-08 21:10 ` Nicolas Goaziou
2017-06-09 14:26   ` Kaushal Modi
2017-06-09 15:14     ` Kaushal Modi
2017-06-09 16:02       ` Michael Albinus
2017-06-09 16:10         ` Kaushal Modi
2017-06-09 16:27           ` Nicolas Goaziou
2017-06-09 19:55             ` Kaushal Modi
2017-06-09 20:05               ` Nicolas Goaziou
2017-06-09 20:21                 ` Kaushal Modi
2017-06-14 14:56   ` Backward incompatible outline-invisible-p change in emacs master for Org (Was: 6 failing tests on master branch) Kaushal Modi
2017-06-14 16:03     ` Kaushal Modi [this message]
2017-06-14 17:02     ` Backward incompatible outline-invisible-p change in emacs master for Org Bastien Guerry
2017-06-14 17:18       ` Kaushal Modi
2017-06-14 20:28         ` Paul Rankin
2017-06-15  6:19           ` Bastien Guerry
2017-06-15 12:16             ` Kaushal Modi
2017-06-15 12:40               ` Bastien Guerry
2017-06-15 13:08                 ` Kaushal Modi

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=CAFyQvY1mDrzZwYCffZoqKRyZ7Z36G18Lrdrq+oRcQw+H76eLcg@mail.gmail.com \
    --to=kaushal.modi@gmail.com \
    --cc=bzg@gnu.org \
    --cc=emacs-orgmode@gnu.org \
    --cc=hello@paulwrankin.com \
    --cc=mail@nicolasgoaziou.fr \
    /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).