فهرست منبع

org-export: Avoid duplicates in `org-export-collect-footnote-definitions'

* contrib/lisp/org-element.el (org-element-map): New optional argument
  to avoid recursion into certain recursive types.
* contrib/lisp/org-export.el (org-export-footnote-first-reference-p,
  org-export-get-footnote-number,
  org-export-collect-footnote-definitions): Use new argument from
  `org-element-map'.
* testing/lisp/test-org-export.el: Add test.

The new argument allows to force entering footnotes definitions at
a certain time (when their first reference is found) but not a second
time when they are encountered in the parse tree.

Thanks to Jambunathan for reporting this.
Nicolas Goaziou 13 سال پیش
والد
کامیت
bf609d8844
3فایلهای تغییر یافته به همراه44 افزوده شده و 19 حذف شده
  1. 16 9
      contrib/lisp/org-element.el
  2. 14 9
      contrib/lisp/org-export.el
  3. 14 1
      testing/lisp/test-org-export.el

+ 16 - 9
contrib/lisp/org-element.el

@@ -2935,7 +2935,7 @@ the current buffer."
     (insert string)
     (org-element-parse-objects (point-min) (point-max) nil restriction)))
 
-(defun org-element-map (data types fun &optional info first-match)
+(defun org-element-map (data types fun &optional info first-match no-recursion)
   "Map a function on selected elements or objects.
 
 DATA is the parsed tree, as returned by, i.e,
@@ -2951,9 +2951,15 @@ not exportable according to that property list will be skipped.
 When optional argument FIRST-MATCH is non-nil, stop at the first
 match for which FUN doesn't return nil, and return that value.
 
-Nil values returned from FUN are ignored in the result."
-  ;; Ensure TYPES is a list, even of one element.
+Optional argument NO-RECURSION is a symbol or a list of symbols
+representing elements or objects types.  `org-element-map' won't
+enter any recursive element or object whose type belongs to that
+list.  Though, FUN can still be applied on them.
+
+Nil values returned from FUN do not appear in the results."
+  ;; Ensure TYPES and NO-RECURSION are a list, even of one element.
   (unless (listp types) (setq types (list types)))
+  (unless (listp no-recursion) (setq no-recursion (list no-recursion)))
   ;; Recursion depth is determined by --CATEGORY.
   (let* ((--category
 	  (cond
@@ -3008,12 +3014,13 @@ Nil values returned from FUN are ignored in the result."
 			    --blob))))
 		    ;; Now determine if a recursion into --BLOB is
 		    ;; possible.  If so, do it.
-		    (when (or (memq --type org-element-recursive-objects)
-			      (and (memq --type org-element-all-elements)
-				   (not (eq --category 'elements)))
-			      (and (memq --type org-element-greater-elements)
-				   (not (eq --category 'greater-elements))))
-		      (funcall --walk-tree --blob)))))
+		    (unless (memq --type no-recursion)
+		      (when (or (and (memq --type org-element-greater-elements)
+				     (not (eq --category 'greater-elements)))
+				(and (memq --type org-element-all-elements)
+				     (not (eq --category 'elements)))
+				(memq --type org-element-recursive-objects))
+			(funcall --walk-tree --blob))))))
 	      (org-element-contents --data))))))
     (catch 'first-match
       (funcall --walk-tree data)

+ 14 - 9
contrib/lisp/org-export.el

@@ -2459,9 +2459,9 @@ DATA is the parse tree from which definitions are collected.
 INFO is the plist used as a communication channel.
 
 Definitions are sorted by order of references.  They either
-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
+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 (num-alist
 	(collect-fn
@@ -2481,10 +2481,11 @@ ignored."
 		   ;; 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))))
+	     ;; Don't enter footnote definitions since it will happen
+	     ;; when their first reference is found.
+	     info nil 'footnote-definition)))))
+    (funcall collect-fn (plist-get info :parse-tree))
+    (reverse num-alist)))
 
 (defun org-export-footnote-first-reference-p (footnote-reference info)
   "Non-nil when a footnote reference is the first one for its label.
@@ -2512,7 +2513,9 @@ INFO is the plist used as a communication channel."
 		    ((eq (org-element-property :type fn) 'standard)
 		     (funcall search-refs
 			      (org-export-get-footnote-definition fn info)))))
-		 info 'first-match)))))
+		 ;; Don't enter footnote definitions since it will
+		 ;; happen when their first reference is found.
+		 info 'first-match 'footnote-definition)))))
 	(equal (catch 'exit (funcall search-refs (plist-get info :parse-tree)))
 	       footnote-reference)))))
 
@@ -2564,7 +2567,9 @@ INFO is the plist used as a communication channel."
 		   (funcall search-ref
 			    (org-export-get-footnote-definition fn info))
 		   nil))))
-	     info 'first-match)))))
+	     ;; Don't enter footnote definitions since it will happen
+	     ;; when their first reference is found.
+	     info 'first-match 'footnote-definition)))))
     (catch 'exit (funcall search-ref (plist-get info :parse-tree)))))
 
 

+ 14 - 1
testing/lisp/test-org-export.el

@@ -363,7 +363,20 @@ body\n")))
 		    info (org-export-collect-tree-properties tree info 'test)))
 	;; Both footnotes should be seen.
 	(should
-	 (= (length (org-export-collect-footnote-definitions tree info)) 2))))))
+	 (= (length (org-export-collect-footnote-definitions tree info)) 2))))
+    ;; 4. Test footnotes definitions collection.
+    (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 (= (length (org-export-collect-footnote-definitions tree info))
+		   4))))))
 
 (ert-deftest test-org-export/fuzzy-links ()
   "Test fuzz link export specifications."