branch: externals/org
commit 03148c5d1fcbbc47d57d7301ab2b8d0925e2e235
Author: Ihor Radchenko <[email protected]>
Commit: Ihor Radchenko <[email protected]>
ox-org: Fix handling export snippets
* lisp/org-element.el (org-element-interpret-data): Fix interpreting
anonymous nodes.
* lisp/ox-org.el (org-org-identity): Do not reproduce secondary
strings verbatim. Pass them through export.
(org-org-headline): Pass headline title through export.
(org-org-export-snippet): New transcoder.
* testing/lisp/test-ox-org.el: New test file.
---
lisp/org-element.el | 2 +-
lisp/ox-org.el | 31 ++++++++++++++++++++++++-------
testing/lisp/test-ox-org.el | 44 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/lisp/org-element.el b/lisp/org-element.el
index 5f64cc1c1d..7078ce1f89 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -5540,7 +5540,7 @@ DATA is a parse tree, an element, an object or a
secondary string
to interpret. Return Org syntax as a string."
(letrec ((fun
(lambda (data parent)
- (let* ((type (org-element-type data))
+ (let* ((type (org-element-type data 'allow-anonymous))
;; Find interpreter for current object or
;; element. If it doesn't exist (e.g. this is
;; a pseudo object or element), return contents,
diff --git a/lisp/ox-org.el b/lisp/ox-org.el
index e2c434fd6c..34a73f8f51 100644
--- a/lisp/ox-org.el
+++ b/lisp/ox-org.el
@@ -79,6 +79,7 @@ described in the Info node `(org)Advanced features'."
(entity . org-org-identity)
(example-block . org-org-identity)
(export-block . org-org-export-block)
+ (export-snippet . org-org-export-snippet)
(fixed-width . org-org-identity)
(footnote-definition . ignore)
(footnote-reference . org-org-identity)
@@ -158,13 +159,23 @@ CONTENTS and INFO are ignored."
(and (equal (org-element-property :type export-block) "ORG")
(org-element-property :value export-block)))
-(defun org-org-identity (blob contents _info)
+(defun org-org-identity (blob contents info)
"Transcode BLOB element or object back into Org syntax.
-CONTENTS is its contents, as a string or nil. INFO is ignored."
- (let ((case-fold-search t))
- (replace-regexp-in-string
- "^[ \t]*#\\+attr_[-_a-z0-9]+:\\(?: .*\\)?\n" ""
- (org-export-expand blob contents t))))
+CONTENTS is its contents, as a string or nil. INFO is the information plist."
+ (let ((new-blob (org-element-copy blob)))
+ ;; Recursively export secondary objects.
+ (org-element-map new-blob t
+ (lambda (data)
+ (unless (eq data new-blob)
+ (let ((exported-data (copy-sequence (org-export-data data info))))
+ (unless (string-empty-p exported-data)
+ (org-element-insert-before exported-data data))
+ (org-element-extract-element data))))
+ info nil nil 'with-affiliated)
+ (let ((case-fold-search t))
+ (replace-regexp-in-string
+ "^[ \t]*#\\+attr_[-_a-z0-9]+:\\(?: .*\\)?\n" ""
+ (org-export-expand new-blob contents t)))))
(defun org-org-headline (headline contents info)
"Transcode HEADLINE element back into Org syntax.
@@ -178,7 +189,7 @@ CONTENTS is its contents, as a string or nil. INFO is
ignored."
(org-element-put-property headline :priority nil))
(org-element-put-property headline :level
(org-export-get-relative-level headline info))
- (org-element-headline-interpreter headline contents)))
+ (org-org-identity headline contents info)))
(defun org-org-keyword (keyword _contents _info)
"Transcode KEYWORD element back into Org syntax.
@@ -195,6 +206,12 @@ INFO is a plist containing current export state."
(or (org-export-custom-protocol-maybe link contents 'org info)
(org-element-link-interpreter link contents)))
+(defun org-org-export-snippet (export-snippet _contents _info)
+ "Transcode a EXPORT-SNIPPET object from Org to Org.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (when (eq (org-export-snippet-backend export-snippet) 'org)
+ (org-element-property :value export-snippet)))
+
(defun org-org-template (contents info)
"Return Org document template with document keywords.
CONTENTS is the transcoded contents string. INFO is a plist used
diff --git a/testing/lisp/test-ox-org.el b/testing/lisp/test-ox-org.el
new file mode 100644
index 0000000000..a56a1a2afb
--- /dev/null
+++ b/testing/lisp/test-ox-org.el
@@ -0,0 +1,44 @@
+;;; test-ox-md.el --- Tests for ox-org.el -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2026 Ihor Radchenko
+
+;; Author: Ihor Radchenko <[email protected]>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ox-org)
+
+(ert-deftest ox-org/honor-export-snippets ()
+ "Test exporting export snippets."
+ (org-test-with-temp-text "
+** @@comment:nope@@ title
+#+caption: @@comment:nope@@ Caption
+- @@comment:nope@@ tag ::
+- @@org:yes@@ tag ::
+"
+ (let ((export-buffer "*Test Org Export*")
+ (org-export-show-temporary-export-buffer nil))
+ (org-export-to-buffer 'org export-buffer)
+ (with-current-buffer export-buffer
+ (goto-char (point-min))
+ (should (search-forward "* title"))
+ (should (search-forward "#+caption: Caption"))
+ (should (search-forward "- tag :: "))
+ (should (search-forward "- yes tag :: "))))))
+
+(provide 'test-ox-org)
+
+;; test-ox-org.el ends here