forked from mirrors/org-mode
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:
parent
72f10cffce
commit
b07bd32081
57
lisp/ox.el
57
lisp/ox.el
|
@ -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.
|
||||||
|
|
|
@ -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."
|
||||||
|
|
Loading…
Reference in a new issue