forked from mirrors/org-mode
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:
parent
719dda85ea
commit
fa145361ec
|
@ -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.
|
||||
|
|
30
lisp/ox.el
30
lisp/ox.el
|
@ -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
|
||||
|
|
|
@ -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].
|
||||
|
|
Loading…
Reference in New Issue