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
;; property is the keyword with "EXPORT_" appended to it.
(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
;; options, with priority given to the latter.
(options (append (and backend (org-export-get-all-options backend))
org-export-options-alist)))
;; Make sure point is at a heading.
(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)
(let ((property (car option))
(keyword (nth 1 option)))
(when (and keyword (not (member keyword seen)))
(let* ((subtree-prop (concat "EXPORT_" keyword))
(value (org-entry-get (point) subtree-prop)))
(push keyword seen)
(when (and value (not (plist-member plist property)))
(setq plist
(plist-put
plist
property
(case (nth 4 option)
(parse
(org-element-parse-secondary-string
value (org-element-restriction 'keyword)))
(split (org-split-string value))
(t value)))))))))))))
;; Handle other keywords. Then return PLIST.
(dolist (option options plist)
(let ((property (car option))
(keyword (nth 1 option)))
(when keyword
(let ((value
(or (cdr (assoc keyword cache))
(let ((v (org-entry-get (point)
(concat "EXPORT_" keyword))))
(push (cons keyword v) cache) v))))
(when value
(setq plist
(plist-put plist
property
(case (nth 4 option)
(parse
(org-element-parse-secondary-string
value (org-element-restriction 'keyword)))
(split (org-split-string value))
(t value))))))))))))
(defun org-export--get-inbuffer-options (&optional backend)
"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 ()
"Test setting options from headline's properties."
;; EXPORT_TITLE.
(org-test-with-temp-text "#+TITLE: Title
* Headline
(should
(equal '("Subtree Title")
(org-test-with-temp-text "#+TITLE: Title
* Headline<point>
:PROPERTIES:
:EXPORT_TITLE: Subtree Title
:END:
Paragraph"
(forward-line)
(should (equal (plist-get (org-export-get-environment nil t) :title)
'("Subtree Title"))))
:title
'("subtree-title")
(plist-get (org-export-get-environment nil t) :title))))
;; EXPORT_OPTIONS.
(org-test-with-temp-text "#+OPTIONS: H:1
* Headline
(should
(= 2
(org-test-with-temp-text "#+OPTIONS: H:1
* Headline<point>
:PROPERTIES:
:EXPORT_OPTIONS: H:2
:END:
Paragraph"
(forward-line)
(should
(= 2 (plist-get (org-export-get-environment nil t) :headline-levels))))
(plist-get (org-export-get-environment nil t) :headline-levels))))
;; EXPORT_DATE.
(org-test-with-temp-text "#+DATE: today
* Headline
(should
(equal '("29-03-2012")
(org-test-with-temp-text "#+DATE: today
* Headline<point>
:PROPERTIES:
:EXPORT_DATE: 29-03-2012
:END:
Paragraph"
(forward-line)
(should (equal (plist-get (org-export-get-environment nil t) :date)
'("29-03-2012"))))
(plist-get (org-export-get-environment nil t) :date))))
;; Properties with `split' behaviour are stored as a list of
;; strings.
(should
(equal '("a" "b")
(org-test-with-temp-text "#+EXCLUDE_TAGS: noexport
* Headline
* Headline<point>
:PROPERTIES:
:EXPORT_EXCLUDE_TAGS: a b
:END:
Paragraph"
(progn
(forward-line)
(plist-get (org-export-get-environment nil t) :exclude-tags)))))
(plist-get (org-export-get-environment nil t) :exclude-tags))))
;; Handle :PROPERTY+: syntax.
(should
(equal '("a" "b")
(org-test-with-temp-text "#+EXCLUDE_TAGS: noexport
* Headline
* Headline<point>
:PROPERTIES:
:EXPORT_EXCLUDE_TAGS: a
:EXPORT_EXCLUDE_TAGS+: b
:END:
Paragraph"
(progn
(forward-line)
(plist-get (org-export-get-environment nil t) :exclude-tags)))))
(plist-get (org-export-get-environment nil t) :exclude-tags))))
;; Export properties are case-insensitive.
(org-test-with-temp-text "* Headline
(should
(equal '("29-03-2012")
(org-test-with-temp-text "* Headline
:PROPERTIES:
:EXPORT_Date: 29-03-2012
:END:
Paragraph"
(should (equal (plist-get (org-export-get-environment nil t) :date)
'("29-03-2012"))))
(plist-get (org-export-get-environment nil t) :date))))
;; Still grab correct options when section above is empty.
(should
(equal '("H1")
(org-test-with-temp-text "* H1\n** H11\n** H12"
(progn (forward-line 2)
(plist-get (org-export-get-environment nil t) :title))))))
(org-test-with-temp-text "* H1\n** H11\n** H12<point>"
(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 ()
"Test title setting."