org-footnote: Fix normalization of inline footnotes with no footnote section
* lisp/org-footnote.el (org-footnote-normalize): Fix normalization of inline footnotes with no footnote section. * testing/lisp/test-org-footnote.el: New test file. Thanks to Samuel Wales for reporting this.
This commit is contained in:
parent
000afe01ab
commit
6b91eb9e65
|
@ -676,8 +676,7 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
;; If EXPORT-PROPS isn't nil, also add `org-footnote'
|
||||
;; property to it, so it can be easily recognized by
|
||||
;; exporters.
|
||||
(if sort-only
|
||||
(goto-char (nth 2 ref))
|
||||
(if sort-only (goto-char (nth 2 ref))
|
||||
(delete-region (nth 1 ref) (nth 2 ref))
|
||||
(goto-char (nth 1 ref))
|
||||
(let ((new-ref (format "[%d]" marker)))
|
||||
|
@ -706,7 +705,10 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
'(:todo-keywords t :tags t :priority t))))
|
||||
(org-export-preprocess-string def parameters))
|
||||
def)
|
||||
inlinep pos) ref-table)))))
|
||||
;; Reference beginning position is a marker
|
||||
;; to preserve it during further buffer
|
||||
;; modifications.
|
||||
inlinep (copy-marker pos)) ref-table)))))
|
||||
;; 2. Find and remove the footnote section, if any. Also
|
||||
;; determine where footnotes shall be inserted (INS-POINT).
|
||||
(cond
|
||||
|
@ -722,10 +724,9 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
(skip-chars-backward " \r\t\n")
|
||||
(forward-line)
|
||||
(unless (bolp) (newline)))
|
||||
;; No footnote section set: Footnotes will be added before next
|
||||
;; headline.
|
||||
((eq major-mode 'org-mode)
|
||||
(org-with-limited-levels (outline-next-heading)))
|
||||
;; No footnote section set: Footnotes will be added at the end
|
||||
;; of the section containing their first reference.
|
||||
((eq major-mode 'org-mode))
|
||||
(t
|
||||
;; Remove any left-over tag in the buffer, if one is set up.
|
||||
(when org-footnote-tag-for-non-org-mode-files
|
||||
|
@ -758,18 +759,21 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
(lambda (x)
|
||||
(cond
|
||||
;; When only sorting, ignore inline footnotes.
|
||||
((and sort-only (nth 3 x)) nil)
|
||||
;; Also clear position marker.
|
||||
((and sort-only (nth 3 x))
|
||||
(set-marker (nth 4 x) nil) nil)
|
||||
;; No definition available: provide one.
|
||||
((not (nth 2 x))
|
||||
(append (butlast x 2)
|
||||
(list (format "DEFINITION NOT FOUND: %s" (car x))
|
||||
(nth 3 x))))
|
||||
(append
|
||||
(list (car x) (nth 1 x)
|
||||
(format "DEFINITION NOT FOUND: %s" (car x)))
|
||||
(nthcdr 3 x)))
|
||||
(t x)))
|
||||
ref-table)))
|
||||
(setq ref-table (nreverse ref-table))
|
||||
;; 4. Remove left-over definitions in the buffer.
|
||||
(mapc (lambda (x) (unless (nth 3 x)
|
||||
(org-footnote-delete-definitions (car x))))
|
||||
(mapc (lambda (x)
|
||||
(unless (nth 3 x) (org-footnote-delete-definitions (car x))))
|
||||
ref-table)
|
||||
;; 5. Insert the footnotes again in the buffer, at the
|
||||
;; appropriate spot.
|
||||
|
@ -791,11 +795,6 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
(skip-chars-backward " \t\n\r")
|
||||
(delete-region (point) ins-point)
|
||||
(unless (bolp) (newline))
|
||||
;; Keep one blank line between footnotes and signature.
|
||||
(when (and (derived-mode-p 'message-mode)
|
||||
(save-excursion
|
||||
(re-search-forward message-signature-separator nil t)))
|
||||
(open-line 1))
|
||||
(when org-footnote-tag-for-non-org-mode-files
|
||||
(insert "\n" org-footnote-tag-for-non-org-mode-files "\n")))
|
||||
((and org-footnote-section (not export-props))
|
||||
|
@ -808,6 +807,8 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
(insert
|
||||
(mapconcat
|
||||
(lambda (x)
|
||||
;; Clean markers.
|
||||
(set-marker (nth 4 x) nil)
|
||||
(format "\n[%s] %s" (nth (if sort-only 0 1) x) (nth 2 x)))
|
||||
ref-table "\n"))
|
||||
(unless (eobp) (insert "\n\n"))
|
||||
|
@ -819,7 +820,10 @@ Additional note on `org-footnote-insert-pos-for-preprocessor':
|
|||
((not sort-only)
|
||||
(mapc
|
||||
(lambda (x)
|
||||
(goto-char (nth 4 x))
|
||||
(let ((pos (nth 4 x)))
|
||||
(goto-char pos)
|
||||
;; Clean marker.
|
||||
(set-marker pos nil))
|
||||
(org-footnote-goto-local-insertion-point)
|
||||
(insert (format "\n[%s] %s\n" (nth 1 x) (nth 2 x))))
|
||||
ref-table))
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
;;; test-org-footnote.el --- Tests for org-footnote.el
|
||||
|
||||
;; Copyright (C) 2012 Nicolas Goaziou
|
||||
|
||||
;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(ert-deftest test-org-footnote/normalize-in-org ()
|
||||
"Test specifications for `org-footnote-normalize' in an Org buffer."
|
||||
;; 1. With a non-nil `org-footnote-section'.
|
||||
(let ((org-footnote-section "Footnotes")
|
||||
(org-blank-before-new-entry '((heading . auto))))
|
||||
;; 1.1. Normalize each type of footnote: standard, labelled,
|
||||
;; numbered, inline, anonymous.
|
||||
(org-test-with-temp-text
|
||||
"Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
|
||||
|
||||
* Footnotes
|
||||
|
||||
\[fn:1] Standard
|
||||
|
||||
\[fn:label] Labelled
|
||||
|
||||
\[1] Numbered"
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Paragraph[1][2][3][4][5]
|
||||
|
||||
* Footnotes
|
||||
|
||||
\[1] Standard
|
||||
|
||||
\[2] Labelled
|
||||
|
||||
\[3] Numbered
|
||||
|
||||
\[4] Inline
|
||||
|
||||
\[5] Anonymous
|
||||
|
||||
|
||||
")))
|
||||
;; 1.2. When no footnote section is present, create it. Follow
|
||||
;; `org-blank-before-new-entry' specifications when doing so.
|
||||
(org-test-with-temp-text "Paragraph[fn:1]\n\n[fn:1] Definition"
|
||||
(org-footnote-normalize)
|
||||
(should (equal (buffer-string)
|
||||
"Paragraph[1]\n\n* Footnotes\n\n[1] Definition")))
|
||||
(org-test-with-temp-text "Paragraph[fn:1]\n* Head1\n[fn:1] Definition"
|
||||
(let ((org-blank-before-new-entry '((heading))))
|
||||
(org-footnote-normalize))
|
||||
(should (equal (buffer-string)
|
||||
"Paragraph[1]\n* Head1\n* Footnotes\n\n[1] Definition")))
|
||||
;; 1.3. When the footnote section is misplaced, move it at the end
|
||||
;; of the buffer.
|
||||
(org-test-with-temp-text "* Head1
|
||||
Body[fn:1]
|
||||
* Footnotes
|
||||
\[fn:1] Definition 1
|
||||
* Head2"
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"* Head1
|
||||
Body[1]
|
||||
* Head2
|
||||
|
||||
* Footnotes
|
||||
|
||||
\[1] Definition 1"))))
|
||||
;; 2. With a nil `org-footnote-section'.
|
||||
(let ((org-footnote-section nil))
|
||||
;; 2.1. Normalize each type of footnote: standard, labelled,
|
||||
;; numbered, inline, anonymous.
|
||||
(org-test-with-temp-text
|
||||
"Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
|
||||
|
||||
\[fn:1] Standard
|
||||
|
||||
\[fn:label] Labelled
|
||||
|
||||
\[1] Numbered"
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Paragraph[1][2][3][4][5]
|
||||
|
||||
\[1] Standard
|
||||
|
||||
\[2] Labelled
|
||||
|
||||
\[3] Numbered
|
||||
|
||||
\[4] Inline
|
||||
|
||||
\[5] Anonymous
|
||||
|
||||
")))
|
||||
;; 2.2. Put each footnote definition at the end of the section
|
||||
;; containing its first reference.
|
||||
(org-test-with-temp-text
|
||||
"* Head 1
|
||||
Text[fn:1:Def1]
|
||||
* Head 2
|
||||
Text[fn:1]
|
||||
* Head 3
|
||||
Text[fn:2:Def2]"
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"* Head 1
|
||||
Text[1]
|
||||
|
||||
\[1] Def1
|
||||
* Head 2
|
||||
Text[1]
|
||||
* Head 3
|
||||
Text[2]
|
||||
|
||||
\[2] Def2
|
||||
")))))
|
||||
|
||||
(ert-deftest test-org-footnote/normalize-outside-org ()
|
||||
"Test `org-footnote-normalize' specifications for buffers not in Org mode."
|
||||
;; 1. In a non-Org buffer, footnotes definitions are always put at
|
||||
;; its end.
|
||||
(let ((org-footnote-tag-for-non-org-mode-files nil))
|
||||
(with-temp-buffer
|
||||
(insert "Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
|
||||
|
||||
\[fn:1] Standard
|
||||
|
||||
\[fn:label] Labelled
|
||||
|
||||
\[1] Numbered
|
||||
|
||||
Some additional text.")
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Paragraph[1][2][3][4][5]
|
||||
|
||||
Some additional text.
|
||||
|
||||
\[1] Standard
|
||||
|
||||
\[2] Labelled
|
||||
|
||||
\[3] Numbered
|
||||
|
||||
\[4] Inline
|
||||
|
||||
\[5] Anonymous"))))
|
||||
;; 2. With a special tag.
|
||||
(let ((org-footnote-tag-for-non-org-mode-files "Footnotes:"))
|
||||
;; 2.1. The tag must be inserted before the footnotes, separated
|
||||
;; from the rest of the text with a blank line.
|
||||
(with-temp-buffer
|
||||
(insert "Paragraph[fn:1][fn::Anonymous]
|
||||
|
||||
\[fn:1] Standard
|
||||
|
||||
Some additional text.")
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Paragraph[1][2]
|
||||
|
||||
Some additional text.
|
||||
|
||||
Footnotes:
|
||||
|
||||
\[1] Standard
|
||||
|
||||
\[2] Anonymous")))
|
||||
;; 2.2. Any tag already inserted in the buffer should be removed
|
||||
;; prior to footnotes insertion.
|
||||
(with-temp-buffer
|
||||
(insert "Text[fn:1]
|
||||
Footnotes:
|
||||
|
||||
Additional text.
|
||||
|
||||
Footnotes:
|
||||
|
||||
\[fn:1] Definition")
|
||||
(org-footnote-normalize)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Text[1]
|
||||
|
||||
Additional text.
|
||||
|
||||
Footnotes:
|
||||
|
||||
\[1] Definition"))))
|
||||
;; 3. As an exception, in `message-mode' buffer, if a signature is
|
||||
;; present, insert footnotes before it.
|
||||
(let ((org-footnote-tag-for-non-org-mode-files nil)
|
||||
(message-signature-separator "^-- $"))
|
||||
(with-temp-buffer
|
||||
(insert "Body[fn::def]
|
||||
--
|
||||
Fake signature
|
||||
--
|
||||
Signature")
|
||||
(let ((major-mode 'message-mode)) (org-footnote-normalize))
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Body[1]
|
||||
--
|
||||
Fake signature
|
||||
|
||||
\[1] def
|
||||
|
||||
--
|
||||
Signature")))))
|
||||
|
||||
(ert-deftest test-org-footnote/sort ()
|
||||
"Test footnotes definitions sorting."
|
||||
(let ((org-footnote-section nil))
|
||||
(org-test-with-temp-text
|
||||
"Text[fn:1][fn::inline][fn:2][fn:label]
|
||||
|
||||
\[fn:label] C
|
||||
|
||||
\[fn:1] A
|
||||
|
||||
\[fn:2] B"
|
||||
(org-footnote-normalize 'sort)
|
||||
(should
|
||||
(equal (buffer-string)
|
||||
"Text[fn:1][fn::inline][fn:2][fn:label]
|
||||
|
||||
\[fn:1] A
|
||||
|
||||
\[fn:2] B
|
||||
|
||||
\[fn:label] C
|
||||
|
||||
")))))
|
||||
|
||||
|
||||
(provide 'test-org-footnote)
|
||||
;;; test-org-footnote.el ends here
|
Loading…
Reference in New Issue