summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <n.goaziou@gmail.com>2012-02-25 14:51:15 +0100
committerNicolas Goaziou <n.goaziou@gmail.com>2012-02-25 14:56:37 +0100
commit81cc6dff19a141271af89a20ba80359cde93a542 (patch)
tree94f571cdc764abe0a1ef5168a1237652042bcdaa
parent5313dc9d091ad7d8c26f17eb5d0f09be9a596f3b (diff)
downloadorg-mode-81cc6dff19a141271af89a20ba80359cde93a542.tar.gz
org-e-latex: Allow nested footnotes
* EXPERIMENTAL/org-e-latex.el (org-e-latex-footnote-reference): Allow nested footnotes. * contrib/lisp/org-element.el (org-element-string-restrictions): Allow footnote references within a footnote reference. * testing/contrib/lisp/test-org-export.el: Add a test for nested footnotes.
-rw-r--r--EXPERIMENTAL/org-e-latex.el52
-rw-r--r--contrib/lisp/org-element.el7
-rw-r--r--testing/contrib/lisp/test-org-export.el27
3 files changed, 67 insertions, 19 deletions
diff --git a/EXPERIMENTAL/org-e-latex.el b/EXPERIMENTAL/org-e-latex.el
index bf9ceba..4599549 100644
--- a/EXPERIMENTAL/org-e-latex.el
+++ b/EXPERIMENTAL/org-e-latex.el
@@ -1013,26 +1013,46 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(let ((prev (org-export-get-previous-element footnote-reference info)))
(when (eq (org-element-type prev) 'footnote-reference)
org-e-latex-footnote-separator))
- ;; Use \footnotemark if the footnote has already been defined.
- ;; Otherwise, define it with \footnote command.
(cond
+ ;; Use \footnotemark if the footnote has already been defined.
((not (org-export-footnote-first-reference-p footnote-reference info))
- (format "\\footnotemark[%s]"
+ (format "\\footnotemark[%s]{}"
(org-export-get-footnote-number footnote-reference info)))
- ;; Inline definitions are secondary strings.
- ((eq (org-element-property :type footnote-reference) 'inline)
- (format "\\footnote{%s}"
- (org-trim
- (org-export-secondary-string
- (org-export-get-footnote-definition footnote-reference info)
- 'e-latex info))))
- ;; Non-inline footnotes definitions are full Org data.
+ ;; Use also \footnotemark if reference is within another footnote
+ ;; reference or footnote definition.
+ ((loop for parent in (org-export-get-genealogy footnote-reference info)
+ thereis (memq (org-element-type parent)
+ '(footnote-reference footnote-definition)))
+ (format "\\footnotemark[%s]{}"
+ (org-export-get-footnote-number footnote-reference info)))
+ ;; Otherwise, define it with \footnote command.
(t
- (format "\\footnote{%s}"
- (org-trim
- (org-export-data
- (org-export-get-footnote-definition footnote-reference info)
- 'e-latex info)))))))
+ (let ((def (org-export-get-footnote-definition footnote-reference info)))
+ (unless (eq (org-element-type def) 'org-data)
+ (setq def (cons 'org-data (cons nil def))))
+ (concat
+ (format "\\footnote{%s}" (org-trim (org-export-data def 'e-latex info)))
+ ;; Retrieve all footnote references within the footnote to add
+ ;; their definition after it, since LaTeX doesn't support them
+ ;; inside.
+ (let ((all-refs
+ (org-element-map
+ def 'footnote-reference
+ (lambda (ref)
+ (when (org-export-footnote-first-reference-p ref info) ref))
+ info)))
+ (mapconcat
+ (lambda (ref)
+ (format
+ "\\footnotetext[%s]{%s}"
+ (org-export-get-footnote-number ref info)
+ (org-trim
+ (funcall
+ (if (org-element-property :inline-definition ref)
+ 'org-export-secondary-string
+ 'org-export-data)
+ (org-export-get-footnote-definition ref info) 'e-latex info))))
+ all-refs ""))))))))
;;;; Headline
diff --git a/contrib/lisp/org-element.el b/contrib/lisp/org-element.el
index ac389f3..75d50f5 100644
--- a/contrib/lisp/org-element.el
+++ b/contrib/lisp/org-element.el
@@ -2563,9 +2563,10 @@ entities, export snippets, latex-fragments, subscript and
superscript.")
(defconst org-element-string-restrictions
- '((footnote-reference entity export-snippet inline-babel-call inline-src-block
- latex-fragment line-break link macro radio-target
- sub/superscript target text-markup time-stamp)
+ '((footnote-reference entity export-snippet footnote-reference
+ inline-babel-call inline-src-block latex-fragment
+ line-break link macro radio-target sub/superscript
+ target text-markup time-stamp)
(headline entity inline-babel-call inline-src-block latex-fragment link
macro radio-target statistics-cookie sub/superscript text-markup
time-stamp)
diff --git a/testing/contrib/lisp/test-org-export.el b/testing/contrib/lisp/test-org-export.el
index 6d05d54..401975b 100644
--- a/testing/contrib/lisp/test-org-export.el
+++ b/testing/contrib/lisp/test-org-export.el
@@ -315,3 +315,30 @@ body\n")))
(let ((org-export-filter-parse-tree-functions '(skip-note-head)))
(org-test-with-temp-text "* Head1\n* Head2 (note)\n"
(should (equal (org-export-as 'test) "* Head1\n")))))))
+
+(ert-deftest test-org-export/footnotes ()
+ "Test footnotes specifications."
+ ;; 1. Test nested footnotes.
+ (let ((org-footnote-section nil))
+ (org-test-with-temp-text "
+Some text[fn:1] and some other text[fn:new:and an inline
+footnote with another one[fn:label:reference to[fn:1] and a new
+one[fn:label2:label2]].
+
+[fn:1] with a footnote inside[fn:inside] and a new footnote [fn:label3:label3].
+
+[fn:inside] like that."
+(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)))
+ (let* ((fn-numbers
+ (org-element-map
+ tree 'footnote-reference
+ (lambda (ref)
+ (or (org-export-get-footnote-number ref info) 'unknown)) info)))
+ ;; 1.1. Every nested footnote has a number.
+ (should (every 'numberp fn-numbers))
+ ;; 1.2. Can tell which are new and which aren't.
+ (should (= (apply 'max fn-numbers) 5)))))))