فهرست منبع

Improve footnotes handling in exporters

* lisp/org-exp.el (org-export-footnotes-markers,
  org-export-footnotes-data): new variables.
  (org-export-preprocess-string): use a more explicit argument.

* lisp/org-html.el (org-export-as-html): initialize new variables.

* lisp/org-docbook.el (org-export-as-docbook): initialize new variables.

* lisp/org-latex.el (org-export-latex-footmark-seen): new variable.
  (org-export-as-latex): initialize new variables.
  (org-export-latex-preprocess): allow to export two or more footnotes
  in a row. Also permit to have footnotes refering to previously
  defined footnotes.

* lisp/org-ascii.el (org-export-as-ascii): feed org-footnote-normalize
  with data so it can normalize footnotes before first headline, or
  footnotes with their definition outside exported region.
Nicolas Goaziou 14 سال پیش
والد
کامیت
ab9c52fd79
6فایلهای تغییر یافته به همراه88 افزوده شده و 64 حذف شده
  1. 2 0
      lisp/org-ascii.el
  2. 2 0
      lisp/org-docbook.el
  3. 5 1
      lisp/org-exp.el
  4. 24 9
      lisp/org-footnote.el
  5. 2 0
      lisp/org-html.el
  6. 53 54
      lisp/org-latex.el

+ 2 - 0
lisp/org-ascii.el

@@ -291,6 +291,8 @@ publishing directory."
 	  (buffer-substring
 	   (if (org-region-active-p) (region-beginning) (point-min))
 	   (if (org-region-active-p) (region-end) (point-max))))
+	 (org-export-footnotes-markers nil)
+	 (org-export-footnotes-data (org-footnote-all-labels 'with-defs))
 	 (lines (org-split-string
 		 (org-export-preprocess-string
 		  region

+ 2 - 0
lisp/org-docbook.el

@@ -519,6 +519,8 @@ publishing directory."
 	  (buffer-substring
 	   (if region-p (region-beginning) (point-min))
 	   (if region-p (region-end) (point-max))))
+	 (org-export-footnotes-markers nil)
+	 (org-export-footnotes-data (org-footnote-all-labels 'with-defs))
 	 (lines
 	  (org-split-string
 	   (org-export-preprocess-string

+ 5 - 1
lisp/org-exp.el

@@ -623,6 +623,10 @@ table.el tables."
 (defvar org-last-level nil) ; dynamically scoped variable
 (defvar org-min-level nil) ; dynamically scoped variable
 (defvar org-levels-open nil) ; dynamically scoped parameter
+(defvar org-export-footnotes-markers nil
+  "Alist of markers used for footnotes, along with their associated definition.")
+(defvar org-export-footnotes-data nil
+  "Alist of labels used in buffers, along with their associated definition.")
 
 (defconst org-export-plist-vars
   '((:link-up		      nil	  org-export-html-link-up)
@@ -1153,7 +1157,7 @@ on this string to produce the exported version."
 
       ;; Normalize footnotes
       (when (plist-get parameters :footnotes)
-	(org-footnote-normalize nil t))
+	(org-footnote-normalize nil 'pre-process-p))
 
       ;; Find all headings and compute the targets for them
       (setq target-alist (org-export-define-heading-targets target-alist))

+ 24 - 9
lisp/org-footnote.el

@@ -309,22 +309,37 @@ If no footnote is found, return nil."
     (concat "fn:" label))
    (t label)))
 
-(defun org-footnote-all-labels ()
-  "Return list with all defined foot labels used in the buffer."
-  (let (rtn l ref)
+(defun org-footnote-all-labels (&optional with-defs)
+  "Return list with all defined foot labels used in the buffer.
+
+If WITH-DEFS is non-nil, also associate the definition to each
+label.  The function will then return an alist whose key is label
+and value definition."
+  (let (rtn
+	(push-to-rtn
+	 (function
+	  ;; Depending on WITH-DEFS, store label or (label . def) of
+	  ;; footnote reference/definition given as argument in RTN.
+	  (lambda (el)
+	    (let ((lbl (car el)))
+	      (push (if with-defs (cons lbl (nth 3 el)) lbl) rtn))))))
     (save-excursion
       (save-restriction
 	(widen)
 	;; Find all labels found in definitions.
 	(goto-char (point-min))
-	(while (re-search-forward org-footnote-definition-re nil t)
-	  (setq l (org-match-string-no-properties 2))
-	  (and l (add-to-list 'rtn l)))
+	(let (def)
+	  (while (re-search-forward org-footnote-definition-re nil t)
+	    (when (setq def (org-footnote-at-definition-p))
+	      (funcall push-to-rtn def))))
 	;; Find all labels found in references.
 	(goto-char (point-min))
-	(while (and (setq ref (org-footnote-get-next-reference))
-		    (goto-char (nth 2 ref)))
-	  (and (car ref) (add-to-list 'rtn (car ref))))))
+	(let (ref)
+	  (while (setq ref (org-footnote-get-next-reference))
+	    (goto-char (nth 2 ref))
+	    (and (car ref)		; ignore anonymous footnotes
+		 (not (funcall (if with-defs #'assoc #'member) (car ref) rtn))
+		 (funcall push-to-rtn ref))))))
     rtn))
 
 (defun org-footnote-unique-label (&optional current)

+ 2 - 0
lisp/org-html.el

@@ -1177,6 +1177,8 @@ PUB-DIR is set, use this as the publishing directory."
 	   (if region-p (region-beginning) (point-min))
 	   (if region-p (region-end) (point-max))))
 	 (org-export-have-math nil)
+	 (org-export-footnotes-markers nil)
+	 (org-export-footnotes-data (org-footnote-all-labels 'with-defs))
 	 (lines
 	  (org-split-string
 	   (org-export-preprocess-string

+ 53 - 54
lisp/org-latex.el

@@ -65,6 +65,8 @@
 (defvar org-export-latex-display-custom-times nil)
 (defvar org-export-latex-all-targets-re nil)
 (defvar org-export-latex-add-level 0)
+(defvar org-export-latex-footmark-seen nil
+  "List of footnotes markers seen so far by exporter.")
 (defvar org-export-latex-sectioning "")
 (defvar org-export-latex-sectioning-depth 0)
 (defvar org-export-latex-special-keyword-regexp
@@ -766,7 +768,10 @@ when PUB-DIR is set, use this as the publishing directory."
 			     '(:org-license-to-kill nil))))
   (org-update-radio-target-regexp)
   (org-export-latex-set-initial-vars ext-plist arg)
-  (setq org-export-opt-plist org-export-latex-options-plist)
+  (setq org-export-opt-plist org-export-latex-options-plist
+	org-export-footnotes-data (org-footnote-all-labels 'with-defs)
+	org-export-footnotes-markers nil
+	org-export-latex-footmark-seen nil)
   (org-install-letbind)
   (run-hooks 'org-export-latex-after-initial-vars-hook)
   (let* ((wcf (current-window-configuration))
@@ -2412,60 +2417,54 @@ The conversion is made depending of STRING-BEFORE and STRING-AFTER."
     (org-if-unprotected
      (replace-match "")))
 
-  ;; When converting to LaTeX, replace footnotes
-  ;; FIXME: don't protect footnotes from conversion
-  (when (plist-get org-export-latex-options-plist :footnotes)
+  ;; When converting to LaTeX, replace footnotes.
+  (when (plist-get opt-plist :footnotes)
     (goto-char (point-min))
-    (while (and (re-search-forward "\\[\\([0-9]+\\)\\]" nil t)
-		(not (equal (char-before (match-beginning 0)) ?\])))
-      (org-if-unprotected
-       (when (and (save-match-data
-		    (save-excursion (beginning-of-line)
-				    (looking-at "[^:|#]")))
-		  (not (org-in-verbatim-emphasis)))
-	 (let ((foot-beg (match-beginning 0))
-	       (foot-end (match-end 0))
-	       (foot-prefix (match-string 0))
-	       footnote footnote-rpl)
-	   (save-excursion
-	     (if (not (re-search-forward (concat "^" (regexp-quote foot-prefix))
-					 nil t))
-		 (replace-match (org-export-latex-protect-string
-				 (concat "$^{" (match-string 1) "}$")))
-	       (replace-match "")
-	       (let* ((end (save-excursion
-			     (if (re-search-forward "^$\\|^#.*$\\|\\[[0-9]+\\]" nil t)
-				 (match-beginning 0) (point-max))))
-		      (body (org-trim (buffer-substring (point) end))))
-		 ;; Fix for footnotes ending on a link or a list.
-		 (setq footnote
-		       (concat body
-			       (if (string-match "ORG-LIST-END-MARKER\\'" body)
-				   "\n" " ")))
-		 (delete-region (point) end))
-	       (goto-char foot-beg)
-	       (delete-region foot-beg foot-end)
-	       (unless (null footnote)
-		 (setq footnote-rpl (format "\\footnote{%s}" footnote))
-		 (add-text-properties 0 10 '(org-protected t) footnote-rpl)
-		 (add-text-properties (1- (length footnote-rpl))
-				      (length footnote-rpl)
-				      '(org-protected t) footnote-rpl)
-		 (put-text-property 0 (length footnote-rpl)
-				    'original-indentation 1000 footnote-rpl)
-		 (if (org-on-heading-p)
-		     (setq footnote-rpl
-			   (concat (org-export-latex-protect-string "\\protect")
-				   footnote-rpl)))
-		 (insert footnote-rpl)))
-	     )))))
-
-    ;; Remove footnote section tag for LaTeX
-    (goto-char (point-min))
-    (while (re-search-forward
-	    (concat "^" footnote-section-tag-regexp) nil t)
-      (org-if-unprotected
-       (replace-match "")))))
+    (let (ref mark-max)
+      (while (setq ref (org-footnote-get-next-reference))
+	(let* ((beg (nth 1 ref))
+	       (lbl (string-to-number (car ref)))
+	       (def (or (cdr (assoc lbl org-export-footnotes-markers)) "")))
+	  ;; Fix body for footnotes ending on a link or a list and
+	  ;; remove definition from buffer.
+	  (setq def
+		(concat def
+			(if (string-match "ORG-LIST-END-MARKER\\'" def)
+			    "\n" " ")))
+	  (org-footnote-delete-definitions (number-to-string lbl))
+	  ;; Compute string to insert (FNOTE), and protect the outside
+	  ;; macro from further transformation. When footnote at point
+	  ;; is referring to a previously defined footnote, use
+	  ;; \footnotemark. Otherwise, use \footnote.
+	  (let ((fnote (if (memq lbl org-export-latex-footmark-seen)
+			   (org-export-latex-protect-string
+			    (format "\\footnotemark[%d]" lbl))
+			 (push lbl org-export-latex-footmark-seen)
+			 (concat (org-export-latex-protect-string "\\footnote{")
+				 def
+				 (org-export-latex-protect-string "}")))))
+	    (when (org-on-heading-p)
+	      (setq fnote
+		    (concat (org-export-latex-protect-string "\\protect") fnote)))
+	    ;; Replace footnote reference with FOOTNOTE.
+	    ;; `save-excursion' is required if there are two footnotes
+	    ;; in a row. In that case, point would be left at the
+	    ;; beginning of the second one, and
+	    ;; `org-footnote-get-next-reference' would then skip it.
+	    (goto-char beg)
+	    (delete-region beg (nth 2 ref))
+	    (save-excursion (insert fnote)))))))
+
+  ;; Remove footnote section tag for LaTeX
+  (goto-char (point-min))
+  (while (re-search-forward
+	  (concat "^" footnote-section-tag-regexp) nil t)
+    (org-if-unprotected
+     (replace-match "")))
+  ;; Remove any left-over footnote definition.
+  (goto-char (point-min))
+  (mapc (lambda (fn) (org-footnote-delete-definitions (car fn)))
+	org-export-footnotes-data))
 
 (defun org-export-latex-fix-inputenc ()
   "Set the coding system in inputenc to what the buffer is."