From c166bfbb1ad475f86dd53363b46e61c14370b6b7 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 26 Feb 2012 10:55:44 +0100 Subject: [PATCH] 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. --- contrib/lisp/org-export.el | 37 +++++++---- testing/contrib/lisp/test-org-export.el | 113 ++++++++++++++++---------------- 2 files changed, 82 insertions(+), 68 deletions(-) diff --git a/contrib/lisp/org-export.el b/contrib/lisp/org-export.el index e8cc1193f..b8097584e 100644 --- a/contrib/lisp/org-export.el +++ b/contrib/lisp/org-export.el @@ -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))))) diff --git a/testing/contrib/lisp/test-org-export.el b/testing/contrib/lisp/test-org-export.el index adf4f2a9c..c9923d4bb 100644 --- a/testing/contrib/lisp/test-org-export.el +++ b/testing/contrib/lisp/test-org-export.el @@ -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)))))) -- 2.11.4.GIT