فهرست منبع

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.
Nicolas Goaziou 13 سال پیش
والد
کامیت
c166bfbb1a
2فایلهای تغییر یافته به همراه82 افزوده شده و 68 حذف شده
  1. 24 13
      contrib/lisp/org-export.el
  2. 58 55
      testing/contrib/lisp/test-org-export.el

+ 24 - 13
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)))))

+ 58 - 55
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))))))