ox: Handle subtree properties referring to multiple options

* lisp/ox.el (org-export--get-subtree-options): When multiple options
  refer to the same keyword, and, as a consequence, to the same export
  property, make sure all of them get updated.
* testing/lisp/test-ox.el (test-org-export/get-subtree-options): Add
  test.

Reported-by: Myles English <mylesenglish@gmail.com>
<http://permalink.gmane.org/gmane.emacs.orgmode/98583>
This commit is contained in:
Nicolas Goaziou 2015-06-23 22:09:43 +02:00
parent 72f10cffce
commit b07bd32081
2 changed files with 70 additions and 73 deletions

View File

@ -1364,52 +1364,45 @@ for export. Return options as a plist."
;; same property in communication channel. The name for the ;; same property in communication channel. The name for the
;; property is the keyword with "EXPORT_" appended to it. ;; property is the keyword with "EXPORT_" appended to it.
(org-with-wide-buffer (org-with-wide-buffer
(let (plist ;; Make sure point is at a heading.
(if (org-at-heading-p) (org-up-heading-safe) (org-back-to-heading t))
(let ((plist
;; EXPORT_OPTIONS are parsed in a non-standard way. Take
;; care of them right from the start.
(let ((o (org-entry-get (point) "EXPORT_OPTIONS")))
(and o (org-export--parse-option-keyword o backend))))
;; Take care of EXPORT_TITLE. If it isn't defined, use
;; headline's title (with no todo keyword, priority cookie or
;; tag) as its fallback value.
(cache (list
(cons "TITLE"
(or (org-entry-get (point) "EXPORT_TITLE")
(progn (looking-at org-complex-heading-regexp)
(org-match-string-no-properties 4))))))
;; Look for both general keywords and back-end specific ;; Look for both general keywords and back-end specific
;; options, with priority given to the latter. ;; options, with priority given to the latter.
(options (append (and backend (org-export-get-all-options backend)) (options (append (and backend (org-export-get-all-options backend))
org-export-options-alist))) org-export-options-alist)))
;; Make sure point is at a heading. ;; Handle other keywords. Then return PLIST.
(if (org-at-heading-p) (org-up-heading-safe) (org-back-to-heading t))
;; Take care of EXPORT_TITLE. If it isn't defined, use
;; headline's title (with no todo keyword, priority cookie or
;; tag) as its fallback value.
(let ((title (or (org-entry-get (point) "EXPORT_TITLE")
(progn (looking-at org-complex-heading-regexp)
(org-match-string-no-properties 4)))))
(setq plist
(plist-put
plist :title
(if (eq (nth 4 (assq :title options)) 'parse)
(org-element-parse-secondary-string
title (org-element-restriction 'keyword))
title))))
;; EXPORT_OPTIONS are parsed in a non-standard way.
(let ((o (org-entry-get (point) "EXPORT_OPTIONS")))
(when o
(setq plist
(nconc plist (org-export--parse-option-keyword o backend)))))
;; Handle other keywords. TITLE keyword is excluded as it has
;; been handled already. Then return PLIST.
(let ((seen '("TITLE")))
(dolist (option options plist) (dolist (option options plist)
(let ((property (car option)) (let ((property (car option))
(keyword (nth 1 option))) (keyword (nth 1 option)))
(when (and keyword (not (member keyword seen))) (when keyword
(let* ((subtree-prop (concat "EXPORT_" keyword)) (let ((value
(value (org-entry-get (point) subtree-prop))) (or (cdr (assoc keyword cache))
(push keyword seen) (let ((v (org-entry-get (point)
(when (and value (not (plist-member plist property))) (concat "EXPORT_" keyword))))
(push (cons keyword v) cache) v))))
(when value
(setq plist (setq plist
(plist-put (plist-put plist
plist
property property
(case (nth 4 option) (case (nth 4 option)
(parse (parse
(org-element-parse-secondary-string (org-element-parse-secondary-string
value (org-element-restriction 'keyword))) value (org-element-restriction 'keyword)))
(split (org-split-string value)) (split (org-split-string value))
(t value))))))))))))) (t value))))))))))))
(defun org-export--get-inbuffer-options (&optional backend) (defun org-export--get-inbuffer-options (&optional backend)
"Return current buffer export options, as a plist. "Return current buffer export options, as a plist.

View File

@ -225,77 +225,81 @@ variable, and communication channel under `info'."
(ert-deftest test-org-export/get-subtree-options () (ert-deftest test-org-export/get-subtree-options ()
"Test setting options from headline's properties." "Test setting options from headline's properties."
;; EXPORT_TITLE. ;; EXPORT_TITLE.
(should
(equal '("Subtree Title")
(org-test-with-temp-text "#+TITLE: Title (org-test-with-temp-text "#+TITLE: Title
* Headline * Headline<point>
:PROPERTIES: :PROPERTIES:
:EXPORT_TITLE: Subtree Title :EXPORT_TITLE: Subtree Title
:END: :END:
Paragraph" Paragraph"
(forward-line) (plist-get (org-export-get-environment nil t) :title))))
(should (equal (plist-get (org-export-get-environment nil t) :title)
'("Subtree Title"))))
:title
'("subtree-title")
;; EXPORT_OPTIONS. ;; EXPORT_OPTIONS.
(should
(= 2
(org-test-with-temp-text "#+OPTIONS: H:1 (org-test-with-temp-text "#+OPTIONS: H:1
* Headline * Headline<point>
:PROPERTIES: :PROPERTIES:
:EXPORT_OPTIONS: H:2 :EXPORT_OPTIONS: H:2
:END: :END:
Paragraph" Paragraph"
(forward-line) (plist-get (org-export-get-environment nil t) :headline-levels))))
(should
(= 2 (plist-get (org-export-get-environment nil t) :headline-levels))))
;; EXPORT_DATE. ;; EXPORT_DATE.
(should
(equal '("29-03-2012")
(org-test-with-temp-text "#+DATE: today (org-test-with-temp-text "#+DATE: today
* Headline * Headline<point>
:PROPERTIES: :PROPERTIES:
:EXPORT_DATE: 29-03-2012 :EXPORT_DATE: 29-03-2012
:END: :END:
Paragraph" Paragraph"
(forward-line) (plist-get (org-export-get-environment nil t) :date))))
(should (equal (plist-get (org-export-get-environment nil t) :date)
'("29-03-2012"))))
;; Properties with `split' behaviour are stored as a list of ;; Properties with `split' behaviour are stored as a list of
;; strings. ;; strings.
(should (should
(equal '("a" "b") (equal '("a" "b")
(org-test-with-temp-text "#+EXCLUDE_TAGS: noexport (org-test-with-temp-text "#+EXCLUDE_TAGS: noexport
* Headline * Headline<point>
:PROPERTIES: :PROPERTIES:
:EXPORT_EXCLUDE_TAGS: a b :EXPORT_EXCLUDE_TAGS: a b
:END: :END:
Paragraph" Paragraph"
(progn (plist-get (org-export-get-environment nil t) :exclude-tags))))
(forward-line)
(plist-get (org-export-get-environment nil t) :exclude-tags)))))
;; Handle :PROPERTY+: syntax. ;; Handle :PROPERTY+: syntax.
(should (should
(equal '("a" "b") (equal '("a" "b")
(org-test-with-temp-text "#+EXCLUDE_TAGS: noexport (org-test-with-temp-text "#+EXCLUDE_TAGS: noexport
* Headline * Headline<point>
:PROPERTIES: :PROPERTIES:
:EXPORT_EXCLUDE_TAGS: a :EXPORT_EXCLUDE_TAGS: a
:EXPORT_EXCLUDE_TAGS+: b :EXPORT_EXCLUDE_TAGS+: b
:END: :END:
Paragraph" Paragraph"
(progn (plist-get (org-export-get-environment nil t) :exclude-tags))))
(forward-line)
(plist-get (org-export-get-environment nil t) :exclude-tags)))))
;; Export properties are case-insensitive. ;; Export properties are case-insensitive.
(should
(equal '("29-03-2012")
(org-test-with-temp-text "* Headline (org-test-with-temp-text "* Headline
:PROPERTIES: :PROPERTIES:
:EXPORT_Date: 29-03-2012 :EXPORT_Date: 29-03-2012
:END: :END:
Paragraph" Paragraph"
(should (equal (plist-get (org-export-get-environment nil t) :date) (plist-get (org-export-get-environment nil t) :date))))
'("29-03-2012"))))
;; Still grab correct options when section above is empty. ;; Still grab correct options when section above is empty.
(should (should
(equal '("H1") (equal '("H1")
(org-test-with-temp-text "* H1\n** H11\n** H12" (org-test-with-temp-text "* H1\n** H11\n** H12<point>"
(progn (forward-line 2) (plist-get (org-export-get-environment nil t) :title))))
(plist-get (org-export-get-environment nil t) :title)))))) ;; More than one property can refer to the same node property.
(should
(equal '("1" "1")
(org-test-with-temp-text
"* H\n:PROPERTIES:\n:EXPORT_A: 1\n:END:\n<point>"
(let* ((backend (org-export-create-backend
:options '((:k1 "A")
(:k2 "A"))))
(options (org-export-get-environment backend t)))
(list (plist-get options :k1) (plist-get options :k2)))))))
(ert-deftest test-org-export/set-title () (ert-deftest test-org-export/set-title ()
"Test title setting." "Test title setting."