Require 2 blank lines to separate footnote definition

* lisp/org-element.el (org-element-footnote-definition-parser):
  Require 2 blank lines to separate footnote definition.
* lisp/org-footnote.el (org-footnote-at-definition-p): Require 2 blank
  lines to separate footnote definition.
* doc/org.texi: Update documentation for footnotes.
* testing/lisp/test-org-element.el: Update tests.
* testing/lisp/test-org-footnote.el: Add tests.

Footnote definitions can still be separated with other footnote
definitions and headlines. This change allows to have multiple
paragraphs in a footnote definition without resorting to the "\par"
trick.
This commit is contained in:
Nicolas Goaziou 2013-02-21 15:30:16 +01:00
parent a965c06213
commit ca060f7be7
5 changed files with 89 additions and 31 deletions

View File

@ -1845,13 +1845,13 @@ or on a per-file basis by using
@cindex footnotes @cindex footnotes
Org mode supports the creation of footnotes. In contrast to the Org mode supports the creation of footnotes. In contrast to the
@file{footnote.el} package, Org mode's footnotes are designed for work on a @file{footnote.el} package, Org mode's footnotes are designed for work on
larger document, not only for one-off documents like emails. The basic a larger document, not only for one-off documents like emails.
syntax is similar to the one used by @file{footnote.el}, i.e., a footnote is
defined in a paragraph that is started by a footnote marker in square A footnote is started by a footnote marker in square brackets in column 0, no
brackets in column 0, no indentation allowed. If you need a paragraph break indentation allowed. It ends at the next footnote definition, headline, or
inside a footnote, use the @LaTeX{} idiom @samp{\par}. The footnote reference after two consecutive empty lines. The footnote reference is simply the
is simply the marker in square brackets, inside text. For example: marker in square brackets, inside text. For example:
@example @example
The Org homepage[fn:1] now looks a lot better than it used to. The Org homepage[fn:1] now looks a lot better than it used to.

View File

@ -693,7 +693,7 @@ Assume point is at the beginning of the footnote definition."
(re-search-forward (re-search-forward
(concat org-outline-regexp-bol "\\|" (concat org-outline-regexp-bol "\\|"
org-footnote-definition-re "\\|" org-footnote-definition-re "\\|"
"^[ \t]*$") limit 'move)) "^\\([ \t]*\n\\)\\{2,\\}") limit 'move))
(match-beginning 0) (match-beginning 0)
(point)))) (point))))
(contents-begin (progn (search-forward "]") (contents-begin (progn (search-forward "]")

View File

@ -251,11 +251,12 @@ otherwise."
(when (save-excursion (beginning-of-line) (org-footnote-in-valid-context-p)) (when (save-excursion (beginning-of-line) (org-footnote-in-valid-context-p))
(save-excursion (save-excursion
(end-of-line) (end-of-line)
;; Footnotes definitions are separated by new headlines or blank ;; Footnotes definitions are separated by new headlines, another
;; lines. ;; footnote definition or 2 blank lines.
(let ((lim (save-excursion (re-search-backward (let ((lim (save-excursion
(concat org-outline-regexp-bol (re-search-backward
"\\|^[ \t]*$") nil t)))) (concat org-outline-regexp-bol
"\\|^\\([ \t]*\n\\)\\{2,\\}") nil t))))
(when (re-search-backward org-footnote-definition-re lim t) (when (re-search-backward org-footnote-definition-re lim t)
(let ((label (org-match-string-no-properties 1)) (let ((label (org-match-string-no-properties 1))
(beg (match-beginning 0)) (beg (match-beginning 0))
@ -271,7 +272,7 @@ otherwise."
(re-search-forward (re-search-forward
(concat org-outline-regexp-bol "\\|" (concat org-outline-regexp-bol "\\|"
org-footnote-definition-re "\\|" org-footnote-definition-re "\\|"
"^[ \t]*$") bound 'move)) "^\\([ \t]*\n\\)\\{2,\\}") bound 'move))
(match-beginning 0) (match-beginning 0)
(point))))) (point)))))
(list label beg end (list label beg end

View File

@ -724,10 +724,10 @@ Some other text
(org-element-parse-buffer) 'footnote-definition 'identity nil t))) (org-element-parse-buffer) 'footnote-definition 'identity nil t)))
;; Footnote with more contents ;; Footnote with more contents
(should (should
(= 28 (= 29
(org-element-property (org-element-property
:end :end
(org-test-with-temp-text "[fn:1] Definition\n| a | b |" (org-test-with-temp-text "[fn:1] Definition\n\n| a | b |"
(org-element-map (org-element-map
(org-element-parse-buffer) (org-element-parse-buffer)
'footnote-definition 'identity nil t))))) 'footnote-definition 'identity nil t)))))

View File

@ -19,6 +19,58 @@
;;; Code: ;;; Code:
(ert-deftest test-org-footnote/delete ()
"Test `org-footnote-delete' specifications."
;; Regular test.
(should
(equal "Paragraph"
(org-test-with-temp-text "Paragraph[1]\n\n[1] Definition"
(search-forward "[")
(org-footnote-delete)
(org-trim (buffer-string)))))
;; Remove multiple definitions and references.
(should
(equal "Paragraph and another"
(org-test-with-temp-text
"Paragraph[1] and another[1]\n\n[1] def\n\n[1] def"
(search-forward "[")
(org-footnote-delete)
(org-trim (buffer-string)))))
;; Delete inline footnotes and all references.
(should
(equal "Para and"
(org-test-with-temp-text "Para[fn:label:def] and[fn:label]"
(search-forward "[")
(org-footnote-delete)
(org-trim (buffer-string)))))
;; Delete anonymous footnotes.
(should
(equal "Para"
(org-test-with-temp-text "Para[fn::def]"
(search-forward "[")
(org-footnote-delete)
(org-trim (buffer-string)))))
;; With an argument, delete footnote with specified label.
(should
(equal "Paragraph[1] and another\n\n[1] def"
(let ((org-footnote-section nil))
(org-test-with-temp-text
"Paragraph[1] and another[2]\n\n[1] def\n\n[2] def2"
(org-footnote-delete "2")
(org-trim (buffer-string))))))
;; Error when no argument is specified at point is not at a footnote
;; reference.
(should-error
(org-test-with-temp-text "Para[1]\n\n[1] Def"
(org-footnote-delete)))
;; Correctly delete footnotes with multiple paragraphs.
(should
(equal "Para\n\n\nOutside footnote."
(org-test-with-temp-text
"Para[1]\n\n[1] para1\n\npara2\n\n\nOutside footnote."
(org-footnote-delete "1")
(org-trim (buffer-string))))))
(ert-deftest test-org-footnote/normalize-in-org () (ert-deftest test-org-footnote/normalize-in-org ()
"Test specifications for `org-footnote-normalize' in an Org buffer." "Test specifications for `org-footnote-normalize' in an Org buffer."
;; 1. With a non-nil `org-footnote-section'. ;; 1. With a non-nil `org-footnote-section'.
@ -138,21 +190,10 @@ Text[2]
"Test `org-footnote-normalize' specifications for buffers not in Org mode." "Test `org-footnote-normalize' specifications for buffers not in Org mode."
;; 1. In a non-Org buffer, footnotes definitions are always put at ;; 1. In a non-Org buffer, footnotes definitions are always put at
;; its end. ;; its end.
(let ((org-footnote-tag-for-non-org-mode-files nil)) (should
(with-temp-buffer (equal
(insert "Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous] "Paragraph[1][2][3][4][5]
\[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. Some additional text.
@ -164,7 +205,21 @@ Some additional text.
\[4] Inline \[4] Inline
\[5] Anonymous")))) \[5] Anonymous"
(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)
(buffer-string)))))
;; 2. With a special tag. ;; 2. With a special tag.
(let ((org-footnote-tag-for-non-org-mode-files "Footnotes:")) (let ((org-footnote-tag-for-non-org-mode-files "Footnotes:"))
;; 2.1. The tag must be inserted before the footnotes, separated ;; 2.1. The tag must be inserted before the footnotes, separated
@ -174,12 +229,14 @@ Some additional text.
\[fn:1] Standard \[fn:1] Standard
Some additional text.") Some additional text.")
(org-footnote-normalize) (org-footnote-normalize)
(should (should
(equal (buffer-string) (equal (buffer-string)
"Paragraph[1][2] "Paragraph[1][2]
Some additional text. Some additional text.
Footnotes: Footnotes: