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:
parent
12c94310a2
commit
c166bfbb1a
|
@ -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)))))
|
||||
|
|
|
@ -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))))))
|
||||
|
|
Loading…
Reference in New Issue