ox: Allow to narrow scope in footnotes API

* lisp/ox.el (org-export--footnote-reference-map,
  org-export-collect-footnote-definitions,
  org-export-footnote-first-reference-p,
  org-export-get-footnote-number): Allow to specify scope, through
  a new optional argument.

* lisp/ox-odt.el (org-odt-footnote-reference): Apply API change.

* testing/lisp/test-ox.el (test-org-export/footnote-first-reference-p,
  test-org-export/get-footnote-number,
  test-org-export/collect-footnote-definitions): Update tests.
This commit is contained in:
Nicolas Goaziou 2015-02-21 09:34:15 +01:00
parent 719dda85ea
commit fa145361ec
3 changed files with 88 additions and 19 deletions

View File

@ -1740,9 +1740,10 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(format "<text:span text:style-name=\"%s\">%s</text:span>"
"OrgSuperscript" ",")))
;; Transcode footnote reference.
(let ((n (org-export-get-footnote-number footnote-reference info t)))
(let ((n (org-export-get-footnote-number footnote-reference info nil t)))
(cond
((not (org-export-footnote-first-reference-p footnote-reference info t))
((not
(org-export-footnote-first-reference-p footnote-reference info nil t))
(funcall --format-footnote-reference n))
;; Inline definitions are secondary strings.
;; Non-inline footnotes definitions are full Org data.

View File

@ -3556,8 +3556,9 @@ definition can be found, raise an error."
(org-element-contents footnote-reference))
(error "Definition not found for footnote %s" label))))
(defun org-export--footnote-reference-map (function info &optional body-first)
"Apply FUNCTION on every footnote reference in parse tree.
(defun org-export--footnote-reference-map
(function data info &optional body-first)
"Apply FUNCTION on every footnote reference in DATA.
INFO is a plist containing export state. By default, as soon as
a new footnote reference is encountered, FUNCTION is called onto
its definition. However, if BODY-FIRST is non-nil, this step is
@ -3597,15 +3598,18 @@ delayed until the end of the process."
;; definitions of inline references.
(if delayp '(footnote-definition footnote-reference)
'footnote-definition)))))
(funcall search-ref (plist-get info :parse-tree) body-first)
(funcall search-ref data body-first)
(funcall search-ref (nreverse definitions) nil)))
(defun org-export-collect-footnote-definitions (info &optional body-first)
(defun org-export-collect-footnote-definitions (info &optional data body-first)
"Return an alist between footnote numbers, labels and definitions.
INFO is the current export state, as a plist.
Definitions are sorted by order of references. As soon as a new
Definitions are collected throughout the whole parse tree, or
DATA when non-nil.
Sorting is done by order of references. As soon as a new
reference is encountered, other references are searched within
its definition. However, if BODY-FIRST is non-nil, this step is
delayed after the whole tree is checked. This alters results
@ -3623,16 +3627,19 @@ for inlined footnotes. Unreferenced definitions are ignored."
(incf n)
(push (list n l d) alist))
(when l (push l labels))))
info body-first)
(or data (plist-get info :parse-tree)) info body-first)
(nreverse alist)))
(defun org-export-footnote-first-reference-p
(footnote-reference info &optional body-first)
(footnote-reference info &optional data body-first)
"Non-nil when a footnote reference is the first one for its label.
FOOTNOTE-REFERENCE is the footnote reference being considered.
INFO is a plist containing current export state.
Search is done throughout the whole parse tree, or DATA when
non-nil.
By default, as soon as a new footnote reference is encountered,
other references are searched within its definition. However, if
BODY-FIRST is non-nil, this step is delayed after the whole tree
@ -3647,14 +3654,17 @@ footnote definitions."
(let ((l (org-element-property :label f)))
(when (and l label (string= label l))
(throw 'exit (eq footnote-reference f)))))
info body-first)))))
(or data (plist-get info :parse-tree)) info body-first)))))
(defun org-export-get-footnote-number (footnote info &optional body-first)
(defun org-export-get-footnote-number (footnote info &optional data body-first)
"Return number associated to a footnote.
FOOTNOTE is either a footnote reference or a footnote definition.
INFO is the plist containing export state.
Number is unique throughout the whole parse tree, or DATA, when
non-nil.
By default, as soon as a new footnote reference is encountered,
counting process moves into its definition. However, if
BODY-FIRST is non-nil, this step is delayed until the end of the
@ -3675,7 +3685,7 @@ process, leading to a different order when footnotes are nested."
;; wasn't encountered yet.
((not l) (incf count))
((not (member l seen)) (push l seen) (incf count)))))
info body-first))))
(or data (plist-get info :parse-tree)) info body-first))))
;;;; For Headlines

View File

@ -1557,6 +1557,30 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
(paragraph . (lambda (p c i) c))))
nil nil nil '(:with-footnotes t))
(nreverse result)))))
;; Limit check to DATA, when non-nil.
(should
(equal
'(nil t)
(org-test-with-parsed-data "Text[fn:1]\n* H\nText[fn:1]\n\n[fn:1] D1"
(let (result)
(org-element-map tree 'footnote-reference
(lambda (ref)
(push
(org-export-footnote-first-reference-p
ref info (org-element-map tree 'headline #'identity info t))
result))
info)
(nreverse result)))))
(should
(equal
'(t nil)
(org-test-with-parsed-data "Text[fn:1]\n* H\nText[fn:1]\n\n[fn:1] D1"
(let (result)
(org-element-map tree 'footnote-reference
(lambda (ref)
(push (org-export-footnote-first-reference-p ref info) result))
info)
(nreverse result)))))
;; If optional argument BODY-FIRST is non-nil, first find footnote
;; in the main body of the document. Otherwise, enter footnote
;; definitions when they are encountered.
@ -1593,7 +1617,7 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
`(,(cons 'footnote-reference
(lambda (f c i)
(when (org-element-lineage f '(drawer))
(push (org-export-footnote-first-reference-p f info t)
(push (org-export-footnote-first-reference-p f info nil t)
result))
""))
(drawer . (lambda (d c i) c))
@ -1631,8 +1655,27 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
(cons (org-export-get-footnote-number ref info)
(org-element-property :label ref)))
info))))
;; With a non-nil optional argument, first check body, then footnote
;; definitions.
;; Limit number to provided DATA, when non-nil.
(should
(equal
'(1)
(org-test-with-parsed-data
"Text[fn:1]\n* H\nText[fn:2]\n\n[fn:1] D1\n[fn:2] D2"
(org-element-map tree 'footnote-reference
(lambda (ref)
(org-export-get-footnote-number
ref info (org-element-map tree 'headline #'identity info t)))
info))))
(should
(equal
'(1 2)
(org-test-with-parsed-data
"Text[fn:1]\n* H\nText[fn:2]\n\n[fn:1] D1\n[fn:2]"
(org-element-map tree 'footnote-reference
(lambda (ref) (org-export-get-footnote-number ref info))
info))))
;; With a non-nil BODY-FIRST optional argument, first check body,
;; then footnote definitions.
(should
(equal
'(("fn:1" . 1) ("fn:2" . 2) ("fn:3" . 3) ("fn:3" . 3))
@ -1641,7 +1684,7 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
(org-element-map tree 'footnote-reference
(lambda (ref)
(cons (org-element-property :label ref)
(org-export-get-footnote-number ref info t)))
(org-export-get-footnote-number ref info nil t)))
info))))
(should
(equal
@ -1664,8 +1707,23 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
\[fn:3] C."
(length (org-export-collect-footnote-definitions info)))))
;; With optional argument, first check body, then footnote
;; definitions.
;; Limit number to provided DATA, when non-nil.
(should
(equal
'((1 "fn:2"))
(org-test-with-parsed-data
"Text[fn:1]\n* H\nText[fn:2]\n\n[fn:1] D1\n[fn:2] D2"
(mapcar #'butlast
(org-export-collect-footnote-definitions
info (org-element-map tree 'headline #'identity info t))))))
(should
(equal
'((1 "fn:1") (2 "fn:2"))
(org-test-with-parsed-data
"Text[fn:1]\n* H\nText[fn:2]\n\n[fn:1] D1\n[fn:2] D2"
(mapcar #'butlast (org-export-collect-footnote-definitions info)))))
;; With optional argument BODY-FIRST, first check body, then
;; footnote definitions.
(should
(equal '("fn:1" "fn:3" "fn:2" nil)
(org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
@ -1674,7 +1732,7 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
\[fn:3] C."
(mapcar (lambda (e) (nth 1 e))
(org-export-collect-footnote-definitions info t)))))
(org-export-collect-footnote-definitions info nil t)))))
(should-not
(equal '("fn:1" "fn:3" "fn:2" nil)
(org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].