Browse Source

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.
Nicolas Goaziou 12 years ago
parent
commit
ca060f7be7
5 changed files with 89 additions and 31 deletions
  1. 7 7
      doc/org.texi
  2. 1 1
      lisp/org-element.el
  3. 7 6
      lisp/org-footnote.el
  4. 2 2
      testing/lisp/test-org-element.el
  5. 72 15
      testing/lisp/test-org-footnote.el

+ 7 - 7
doc/org.texi

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

+ 1 - 1
lisp/org-element.el

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

+ 7 - 6
lisp/org-footnote.el

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

+ 2 - 2
testing/lisp/test-org-element.el

@@ -724,10 +724,10 @@ Some other text
       (org-element-parse-buffer) 'footnote-definition 'identity nil t)))
   ;; Footnote with more contents
   (should
-   (= 28
+   (= 29
       (org-element-property
        :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-parse-buffer)
 	  'footnote-definition 'identity nil t)))))

+ 72 - 15
testing/lisp/test-org-footnote.el

@@ -19,6 +19,58 @@
 
 ;;; 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 ()
   "Test specifications for `org-footnote-normalize' in an Org buffer."
   ;; 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."
   ;; 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]
+  (should
+   (equal
+    "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.
 
@@ -164,7 +205,21 @@ Some additional text.
 
 \[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.
   (let ((org-footnote-tag-for-non-org-mode-files "Footnotes:"))
     ;; 2.1. The tag must be inserted before the footnotes, separated
@@ -174,12 +229,14 @@ Some additional text.
 
 \[fn:1] Standard
 
+
 Some additional text.")
       (org-footnote-normalize)
       (should
        (equal (buffer-string)
 	      "Paragraph[1][2]
 
+
 Some additional text.
 
 Footnotes: