ox: Fix footnotes in included files

* lisp/ox.el (org-export--prepare-file-contents): Do not error when
  including multiple footnotes with the same label.

* testing/lisp/test-ox.el (test-org-export/expand-include): Update test.

Reported-by: Leonard Randall <leonard.a.randall@gmail.com>
<http://permalink.gmane.org/gmane.emacs.orgmode/100906>
This commit is contained in:
Nicolas Goaziou 2015-09-06 21:54:57 +02:00
parent a2662dc365
commit a7394224aa
2 changed files with 17 additions and 13 deletions

View File

@ -3371,20 +3371,20 @@ lines, include only those lines.
Optional argument IND, when non-nil, is an integer specifying the Optional argument IND, when non-nil, is an integer specifying the
global indentation of returned contents. Since its purpose is to global indentation of returned contents. Since its purpose is to
allow an included file to stay in the same environment it was allow an included file to stay in the same environment it was
created \(i.e. a list item), it doesn't apply past the first created (e.g., a list item), it doesn't apply past the first
headline encountered. headline encountered.
Optional argument MINLEVEL, when non-nil, is an integer Optional argument MINLEVEL, when non-nil, is an integer
specifying the level that any top-level headline in the included specifying the level that any top-level headline in the included
file should have. file should have.
Optional argument ID is an integer that will be inserted before Optional argument ID is an integer that will be inserted before
each footnote definition and reference if FILE is an Org file. each footnote definition and reference if FILE is an Org file.
This is useful to avoid conflicts when more than one Org file This is useful to avoid conflicts when more than one Org file
with footnotes is included in a document. with footnotes is included in a document.
Optional argument FOOTNOTES is a hash-table to store footnotes in Optional argument FOOTNOTES is a hash-table to store footnotes in
the included document. the included document."
"
(with-temp-buffer (with-temp-buffer
(insert-file-contents file) (insert-file-contents file)
(when lines (when lines
@ -3413,7 +3413,7 @@ the included document.
(delete-region (point) (point-max)) (delete-region (point) (point-max))
;; If IND is set, preserve indentation of include keyword until ;; If IND is set, preserve indentation of include keyword until
;; the first headline encountered. ;; the first headline encountered.
(when ind (when (and ind (> ind 0))
(unless (eq major-mode 'org-mode) (unless (eq major-mode 'org-mode)
(let ((org-inhibit-startup t)) (org-mode))) (let ((org-inhibit-startup t)) (org-mode)))
(goto-char (point-min)) (goto-char (point-min))
@ -3435,13 +3435,14 @@ the included document.
(let ((levels (org-map-entries (let ((levels (org-map-entries
(lambda () (org-reduced-level (org-current-level)))))) (lambda () (org-reduced-level (org-current-level))))))
(when levels (when levels
(let ((offset (- minlevel (apply 'min levels)))) (let ((offset (- minlevel (apply #'min levels))))
(unless (zerop offset) (unless (zerop offset)
(when org-odd-levels-only (setq offset (* offset 2))) (when org-odd-levels-only (setq offset (* offset 2)))
;; Only change stars, don't bother moving whole ;; Only change stars, don't bother moving whole
;; sections. ;; sections.
(org-map-entries (org-map-entries
(lambda () (if (< offset 0) (delete-char (abs offset)) (lambda ()
(if (< offset 0) (delete-char (abs offset))
(insert (make-string offset ?*))))))))))) (insert (make-string offset ?*)))))))))))
;; Append ID to all footnote references and definitions, so they ;; Append ID to all footnote references and definitions, so they
;; become file specific and cannot collide with footnotes in other ;; become file specific and cannot collide with footnotes in other
@ -3449,7 +3450,8 @@ the included document.
;; LINES. ;; LINES.
(when id (when id
(let ((marker-min (point-min-marker)) (let ((marker-min (point-min-marker))
(marker-max (point-max-marker))) (marker-max (point-max-marker))
seen)
(goto-char (point-min)) (goto-char (point-min))
(while (re-search-forward org-footnote-re nil t) (while (re-search-forward org-footnote-re nil t)
(let ((reference (org-element-context))) (let ((reference (org-element-context)))
@ -3466,7 +3468,10 @@ the included document.
(let ((new-label (org-export--update-footnote-label (let ((new-label (org-export--update-footnote-label
(org-element-property :begin reference) (org-element-property :begin reference)
digit-label id))) digit-label id)))
(unless (eq (org-element-property :type reference) 'inline) (unless (or (eq (org-element-property :type reference)
'inline)
(member label seen))
(push label seen)
(org-with-wide-buffer (org-with-wide-buffer
(let* ((definition (org-footnote-get-definition label)) (let* ((definition (org-footnote-get-definition label))
(beginning (nth 1 definition))) (beginning (nth 1 definition)))
@ -3475,7 +3480,7 @@ the included document.
"Definition not found for footnote %s in file %s" "Definition not found for footnote %s in file %s"
label file)) label file))
(if (or (< beginning marker-min) (if (or (< beginning marker-min)
(> beginning marker-max)) (>= beginning marker-max))
;; Store since footnote-definition is ;; Store since footnote-definition is
;; outside of LINES. ;; outside of LINES.
(puthash new-label (puthash new-label

View File

@ -974,7 +974,7 @@ text
(length (length
(delete-dups (delete-dups
(let ((contents " (let ((contents "
Footnotes[fn:1], [fn:test] and [fn:inline:anonymous footnote]. Footnotes[fn:1], [fn:test], [fn:test] and [fn:inline:anonymous footnote].
\[fn:1] Footnote 1 \[fn:1] Footnote 1
\[fn:test] Footnote \"test\"")) \[fn:test] Footnote \"test\""))
(org-test-with-temp-text-in-file contents (org-test-with-temp-text-in-file contents
@ -987,8 +987,7 @@ Footnotes[fn:1], [fn:test] and [fn:inline:anonymous footnote].
(org-export-expand-include-keyword) (org-export-expand-include-keyword)
(org-element-map (org-element-parse-buffer) (org-element-map (org-element-parse-buffer)
'footnote-reference 'footnote-reference
(lambda (ref) (lambda (r) (org-element-property :label r)))))))))))))
(org-element-property :label ref)))))))))))))
;; Footnotes labels are not local to each include keyword. ;; Footnotes labels are not local to each include keyword.
(should (should
(= 4 (= 4