org-export: fix bug with nested footnotes in invisible definitions

* contrib/lisp/org-export.el (org-export-collect-footnote-definitions):
  Also collect footnotes in footnote definitions
(org-export-get-footnote-number): Remove unused check.
* testing/contrib/lisp/test-org-export.el: Add test.
This commit is contained in:
Nicolas Goaziou 2012-02-26 10:55:44 +01:00
parent 12c94310a2
commit c166bfbb1a
2 changed files with 82 additions and 68 deletions

View File

@ -2457,16 +2457,28 @@ appear as Org data \(transcoded with `org-export-data'\) or as
a secondary string for inlined footnotes \(transcoded with
`org-export-secondary-string'\). Unreferenced definitions are
ignored."
(let (refs)
;; Collect seen references in REFS.
(org-element-map
data 'footnote-reference
(lambda (footnote)
(when (org-export-footnote-first-reference-p footnote info)
(list (org-export-get-footnote-number footnote info)
(org-element-property :label footnote)
(org-export-get-footnote-definition footnote info))))
info)))
(let (num-alist
(collect-fn
(function
(lambda (data)
;; Collect footnote number, label and definition in DATA.
(org-element-map
data 'footnote-reference
(lambda (fn)
(when (org-export-footnote-first-reference-p fn info)
(let ((def (org-export-get-footnote-definition fn info)))
(push
(list (org-export-get-footnote-number fn info)
(org-element-property :label fn)
def)
num-alist)
;; Also search in definition for nested footnotes.
(when (eq (org-element-property :type fn) 'standard)
(funcall collect-fn def)))))
info)
;; Return final value.
(reverse num-alist)))))
(funcall collect-fn (plist-get info :parse-tree))))
(defun org-export-footnote-first-reference-p (footnote-reference info)
"Non-nil when a footnote reference is the first one for its label.
@ -2543,9 +2555,8 @@ INFO is the plist used as a communication channel."
;; Once again, return nil to stay in the loop.
((not (member fn-lbl seen-refs))
(push fn-lbl seen-refs)
(when (eq (org-element-type fn) 'standard)
(funcall search-ref
(org-export-get-footnote-definition fn info)))
(funcall search-ref
(org-export-get-footnote-definition fn info))
nil))))
info 'first-match)))))
(catch 'exit (funcall search-ref (plist-get info :parse-tree)))))

View File

@ -32,15 +32,15 @@ body to execute. The defined back-end simply returns parsed data
as Org syntax."
(declare (debug (form body)) (indent 1))
`(flet ,(let (transcoders)
(dolist (type (append org-element-all-elements
org-element-all-objects)
transcoders)
(push `(,(intern (format "org-%s-%s" backend type))
(obj contents info)
(,(intern (format "org-element-%s-interpreter" type))
obj contents))
transcoders)))
,@body))
(dolist (type (append org-element-all-elements
org-element-all-objects)
transcoders)
(push `(,(intern (format "org-%s-%s" backend type))
(obj contents info)
(,(intern (format "org-element-%s-interpreter" type))
obj contents))
transcoders)))
,@body))
(ert-deftest test-org-export/parse-option-keyword ()
"Test reading all standard #+OPTIONS: items."
@ -320,49 +320,52 @@ body\n")))
"Test footnotes specifications."
(let ((org-footnote-section nil))
;; 1. Read every type of footnote.
(org-test-with-temp-text "
Text[fn:1] [1] [fn:label:C] [fn::D]
[fn:1] A
[1] B"
(let* ((tree (org-element-parse-buffer))
(info (org-combine-plists
(org-export-initial-options) '(:with-footnotes t))))
(setq info (org-combine-plists
info (org-export-collect-tree-properties tree info 'test)))
(should
(equal
'((1 . "A") (2 . "B") (3 . "C") (4 . "D"))
(org-element-map
tree 'footnote-reference
(lambda (ref)
(cons (org-export-get-footnote-number ref info)
(if (eq (org-element-property :type ref) 'inline)
(car (org-export-get-footnote-definition ref info))
(car (org-element-contents
(car (org-element-contents
(org-export-get-footnote-definition ref info))))))))
info)))))
;; 2. Test nested footnotes.
(org-test-with-temp-text "
Text[fn:1:A[fn:2]] [fn:3].
[fn:2] B [fn:3] [fn::D].
[fn:3] C."
(let* ((tree (org-element-parse-buffer))
(info (org-combine-plists
(org-export-initial-options) '(:with-footnotes t))))
(setq info (org-combine-plists
info (org-export-collect-tree-properties tree info 'test)))
(should
(equal
'((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
(org-element-map
tree 'footnote-reference
(lambda (ref)
(when (org-export-footnote-first-reference-p ref info)
(cons (org-export-get-footnote-number ref info)
(org-element-property :label ref))))
info)))))))
(org-test-with-temp-text
"Text[fn:1] [1] [fn:label:C] [fn::D]\n\n[fn:1] A\n\n[1] B"
(let* ((tree (org-element-parse-buffer))
(info (org-combine-plists
(org-export-initial-options) '(:with-footnotes t))))
(setq info (org-combine-plists
info (org-export-collect-tree-properties tree info 'test)))
(should
(equal
'((1 . "A") (2 . "B") (3 . "C") (4 . "D"))
(org-element-map
tree 'footnote-reference
(lambda (ref)
(let ((def (org-export-get-footnote-definition ref info)))
(cons (org-export-get-footnote-number ref info)
(if (eq (org-element-property :type ref) 'inline) (car def)
(car (org-element-contents
(car (org-element-contents def))))))))
info)))))
;; 2. Test nested footnotes order.
(org-test-with-temp-text
"Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
(let* ((tree (org-element-parse-buffer))
(info (org-combine-plists
(org-export-initial-options) '(:with-footnotes t))))
(setq info (org-combine-plists
info (org-export-collect-tree-properties tree info 'test)))
(should
(equal
'((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
(org-element-map
tree 'footnote-reference
(lambda (ref)
(when (org-export-footnote-first-reference-p ref info)
(cons (org-export-get-footnote-number ref info)
(org-element-property :label ref))))
info)))))
;; 3. Test nested footnote in invisible definitions.
(org-test-with-temp-text "Text[1]\n\n[1] B [2]\n\n[2] C."
;; Hide definitions.
(narrow-to-region (point) (point-at-eol))
(let* ((tree (org-element-parse-buffer))
(info (org-combine-plists
(org-export-initial-options) '(:with-footnotes t))))
(setq info (org-combine-plists
info (org-export-collect-tree-properties tree info 'test)))
;; Both footnotes should be seen.
(should
(= (length (org-export-collect-footnote-definitions tree info)) 2))))))