Преглед изворни кода

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."