Преглед на файлове

org-element: Ignore plain footnotes

* lisp/org-element.el (org-element--set-regexps):
(org-element-footnote-definition-interpreter):
(org-element-footnote-reference-parser):
(org-element-footnote-reference-interpreter): Do not consider [1]-like
constructs as footnotes anymore.

* lisp/ox.el (org-export-expand-include-keyword):
(org-export--prepare-file-contents): Apply changes to footnotes.

* doc/org.texi (Footnotes): Remove references to plain footnotes.

* testing/lisp/test-org-element.el (test-org-element/footnote-reference-parser):
(test-org-element/footnote-reference-interpreter):
* testing/lisp/test-ox.el (test-org-export/expand-include):
(test-org-export/expand-macro):
(test-org-export/get-footnote-number):
(test-org-export/collect-footnote-definitions):
(test-org-export/footnotes):
(test-org-export/fuzzy-link): Update tests.

Since it is possible to refer unambiguously to a label without the "fn:"
prefix, the latter becomes part of the syntax and no longer part of the
label.  In particular [fn:1] and [fn:label] are labelled, respectively,
"1" and "label".
Nicolas Goaziou преди 9 години
родител
ревизия
deafe56554
променени са 5 файла, в които са добавени 72 реда и са изтрити 72 реда
  1. 1 8
      doc/org.texi
  2. 13 12
      lisp/org-element.el
  3. 6 9
      lisp/ox.el
  4. 4 11
      testing/lisp/test-org-element.el
  5. 48 32
      testing/lisp/test-ox.el

+ 1 - 8
doc/org.texi

@@ -1922,16 +1922,9 @@ The Org homepage[fn:1] now looks a lot better than it used to.
 @end example
 
 Org mode extends the number-based syntax to @emph{named} footnotes and
-optional inline definition.  Using plain numbers as markers (as
-@file{footnote.el} does) is supported for backward compatibility, but not
-encouraged because of possible conflicts with @LaTeX{} snippets (@pxref{Embedded
-@LaTeX{}}).  Here are the valid references:
+optional inline definition.  Here are the valid references:
 
 @table @code
-@item [1]
-A plain numeric footnote marker.  Compatible with @file{footnote.el}, but not
-recommended because something like @samp{[1]} could easily be part of a code
-snippet.
 @item [fn:name]
 A named footnote reference, where @code{name} is a unique label word, or, for
 simplicity of automatic creation, a number.

+ 13 - 12
lisp/org-element.el

@@ -151,7 +151,7 @@ specially in `org-element--object-lex'.")
 		;; Headlines, inlinetasks.
 		org-outline-regexp "\\|"
 		;; Footnote definitions.
-		"\\[\\(?:[0-9]+\\|fn:[-_[:word:]]+\\)\\]" "\\|"
+		"\\[fn:[-_[:word:]]+\\]" "\\|"
 		;; Diary sexps.
 		"%%(" "\\|"
 		"[ \t]*\\(?:"
@@ -199,7 +199,12 @@ specially in `org-element--object-lex'.")
 		      ;; Objects starting with "[": regular link,
 		      ;; footnote reference, statistics cookie,
 		      ;; timestamp (inactive).
-		      "\\[\\(?:fn:\\|\\(?:[0-9]\\|\\(?:%\\|/[0-9]*\\)\\]\\)\\|\\[\\)"
+		      (concat "\\[\\(?:"
+			      "fn:" "\\|"
+			      "\\[" "\\|"
+			      "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}" "\\|"
+			      "[0-9]*\\(?:%\\|/[0-9]*\\)\\]"
+			      "\\)")
 		      ;; Objects starting with "@": export snippets.
 		      "@@"
 		      ;; Objects starting with "{": macro.
@@ -836,7 +841,7 @@ Assume point is at the beginning of the footnote definition."
 (defun org-element-footnote-definition-interpreter (footnote-definition contents)
   "Interpret FOOTNOTE-DEFINITION element as Org syntax.
 CONTENTS is the contents of the footnote-definition."
-  (concat (format "[%s]" (org-element-property :label footnote-definition))
+  (concat (format "[fn:%s]" (org-element-property :label footnote-definition))
 	  " "
 	  contents))
 
@@ -2767,14 +2772,10 @@ When at a footnote reference, return a list whose car is
       (when closing
 	(save-excursion
 	  (let* ((begin (point))
-		 (label
-		  (or (org-match-string-no-properties 2)
-		      (org-match-string-no-properties 3)
-		      (and (match-string 1)
-			   (concat "fn:" (org-match-string-no-properties 1)))))
-		 (type (if (or (not label) (match-string 1)) 'inline 'standard))
+		 (label (match-string-no-properties 1))
 		 (inner-begin (match-end 0))
 		 (inner-end (1- closing))
+		 (type (if (match-end 2) 'inline 'standard))
 		 (post-blank (progn (goto-char closing)
 				    (skip-chars-forward " \t")))
 		 (end (point)))
@@ -2790,9 +2791,9 @@ When at a footnote reference, return a list whose car is
 (defun org-element-footnote-reference-interpreter (footnote-reference contents)
   "Interpret FOOTNOTE-REFERENCE object as Org syntax.
 CONTENTS is its definition, when inline, or nil."
-  (format "[%s]"
-	  (concat (or (org-element-property :label footnote-reference) "fn:")
-		  (and contents (concat ":" contents)))))
+  (format "[fn:%s%s]"
+	  (or (org-element-property :label footnote-reference) "")
+	  (if contents (concat ":" contents) "")))
 
 
 ;;;; Inline Babel Call

+ 6 - 9
lisp/ox.el

@@ -3351,7 +3351,7 @@ storing and resolving footnotes.  It is created automatically."
 	      (unless included
 		(org-with-wide-buffer
 		 (goto-char (point-max))
-		 (maphash (lambda (k v) (insert (format "\n[%s] %s\n" k v)))
+		 (maphash (lambda (k v) (insert (format "\n[fn:%s] %s\n" k v)))
 			  footnotes)))))))))))
 
 (defun org-export--inclusion-absolute-lines (file location only-contents lines)
@@ -3472,7 +3472,7 @@ the included document."
       (unless (eq major-mode 'org-mode)
 	(let ((org-inhibit-startup t)) (org-mode)))
       (goto-char (point-min))
-      (let ((ind-str (make-string ind ? )))
+      (let ((ind-str (make-string ind ?\s)))
 	(while (not (or (eobp) (looking-at org-outline-regexp-bol)))
 	  ;; Do not move footnote definitions out of column 0.
 	  (unless (and (looking-at org-footnote-definition-re)
@@ -3508,17 +3508,14 @@ the included document."
 	    (marker-max (point-max-marker))
 	    (get-new-label
 	     (lambda (label)
-	       ;; Generate new label from LABEL.  If LABEL is akin to
-	       ;; [1] convert it to [fn:--ID-1].  Otherwise add "-ID-"
-	       ;; after "fn:".
-	       (if (org-string-match-p "\\`[0-9]+\\'" label)
-		   (format "fn:--%d-%s" id label)
-		 (format "fn:-%d-%s" id (substring label 3)))))
+	       ;; Generate new label from LABEL by prefixing it with
+	       ;; "-ID-".
+	       (format "-%d-%s" id label)))
 	    (set-new-label
 	     (lambda (f old new)
 	       ;; Replace OLD label with NEW in footnote F.
 	       (save-excursion
-		 (goto-char (1+ (org-element-property :begin f)))
+		 (goto-char (+ (org-element-property :begin f) 4))
 		 (looking-at (regexp-quote old))
 		 (replace-match new))))
 	    (seen-alist))

+ 4 - 11
testing/lisp/test-org-element.el

@@ -938,11 +938,6 @@ Some other text
    (org-test-with-temp-text "Text[fn:label]"
      (org-element-map
 	 (org-element-parse-buffer) 'footnote-reference 'identity)))
-  ;; Parse a normalized reference.
-  (should
-   (org-test-with-temp-text "Text[1]"
-     (org-element-map
-	 (org-element-parse-buffer) 'footnote-reference 'identity)))
   ;; Parse an inline reference.
   (should
    (org-test-with-temp-text "Text[fn:test:def]"
@@ -2893,17 +2888,15 @@ DEADLINE: <2012-03-29 thu.> SCHEDULED: <2012-03-29 thu.> CLOSED: [2012-03-29 thu
 
 (ert-deftest test-org-element/footnote-reference-interpreter ()
   "Test footnote reference interpreter."
-  ;; 1. Regular reference.
+  ;; Regular reference.
   (should (equal (org-test-parse-and-interpret "Text[fn:1]") "Text[fn:1]\n"))
-  ;; 2. Normalized reference.
-  (should (equal (org-test-parse-and-interpret "Text[1]") "Text[1]\n"))
-  ;; 3. Named reference.
+  ;; Named reference.
   (should (equal (org-test-parse-and-interpret "Text[fn:label]")
 		 "Text[fn:label]\n"))
-  ;; 4. Inline reference.
+  ;; Inline reference.
   (should (equal (org-test-parse-and-interpret "Text[fn:label:def]")
 		 "Text[fn:label:def]\n"))
-  ;; 5. Anonymous reference.
+  ;; Anonymous reference.
   (should (equal (org-test-parse-and-interpret "Text[fn::def]")
 		 "Text[fn::def]\n")))
 

+ 48 - 32
testing/lisp/test-ox.el

@@ -1054,7 +1054,7 @@ text
       (length
        (delete-dups
 	(let ((contents "
-Footnotes[fn:1], [fn:test], [fn:test] and [fn:inline:anonymous footnote].
+Footnotes[fn:1], [fn:test], [fn:test] and [fn:inline:inline footnote].
 \[fn:1] Footnote 1
 \[fn:test] Footnote \"test\""))
 	  (org-test-with-temp-text-in-file contents
@@ -1070,13 +1070,12 @@ Footnotes[fn:1], [fn:test], [fn:test] and [fn:inline:anonymous footnote].
 		      (lambda (r) (org-element-property :label r)))))))))))))
   ;; Footnotes labels are not local to each include keyword.
   (should
-   (= 4
+   (= 3
       (length
        (delete-dups
 	(let ((contents "
-Footnotes[fn:1], [fn:test], [2] and [fn:inline:anonymous footnote].
+Footnotes[fn:1], [fn:test] and [fn:inline:inline footnote].
 \[fn:1] Footnote 1
-\[2] Footnote 2
 \[fn:test] Footnote \"test\""))
 	  (org-test-with-temp-text-in-file contents
 	    (let ((file (buffer-file-name)))
@@ -1089,26 +1088,24 @@ Footnotes[fn:1], [fn:test], [2] and [fn:inline:anonymous footnote].
   ;; Footnotes are supported by :lines-like elements and unnecessary
   ;; footnotes are dropped.
   (should
-   (= 4
+   (= 3
       (length
        (delete-dups
 	(let ((contents "
 * foo
 Footnotes[fn:1]
 * bar
-Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote]
+Footnotes[fn:2], foot[fn:test] and [fn:inline:inline footnote]
 
 \[fn:1] Footnote 1
 \[fn:2] Footnote 1
 * Footnotes
 \[fn:test] Footnote \"test\"
-\[3] Footnote 3
 "))
 	  (org-test-with-temp-text-in-file contents
 	    (let ((file (buffer-file-name)))
 	      (org-test-with-temp-text
-		  (format "#+INCLUDE: \"%s::*bar\"
-" file)
+		  (format "#+INCLUDE: \"%s::*bar\"\n" file)
 		(org-export-expand-include-keyword)
 		(org-element-map (org-element-parse-buffer)
 		    'footnote-definition
@@ -1119,7 +1116,8 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
     "body\n"
     (org-test-with-temp-text
 	(concat
-	 (format "#+INCLUDE: \"%s/examples/include.org::*Heading\" " org-test-dir)
+	 (format "#+INCLUDE: \"%s/examples/include.org::*Heading\" "
+		 org-test-dir)
 	 ":only-contents t")
       (org-export-expand-include-keyword)
       (buffer-string))))
@@ -1135,27 +1133,32 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
    (equal
     "| 1 |\n"
     (org-test-with-temp-text
-	(format "#+INCLUDE: \"%s/examples/include.org::tbl\" :only-contents t" org-test-dir)
+	(format "#+INCLUDE: \"%s/examples/include.org::tbl\" :only-contents t"
+		org-test-dir)
       (org-export-expand-include-keyword)
       (buffer-string))))
   ;; Including non-existing elements should result in an error.
   (should-error
    (org-test-with-temp-text
-       (format "#+INCLUDE: \"%s/examples/include.org::*non-existing heading\"" org-test-dir)
+       (format "#+INCLUDE: \"%s/examples/include.org::*non-existing heading\""
+	       org-test-dir)
      (org-export-expand-include-keyword)))
   ;; Lines work relatively to an included element.
   (should
    (equal
     "2\n3\n"
     (org-test-with-temp-text
-	(format "#+INCLUDE: \"%s/examples/include.org::#ah\" :only-contents t :lines \"2-3\"" org-test-dir)
+	(format "#+INCLUDE: \"%s/examples/include.org::#ah\" :only-contents t \
+:lines \"2-3\""
+		org-test-dir)
       (org-export-expand-include-keyword)
       (buffer-string))))
   ;; Properties should be dropped from headlines.
   (should
    (equal
     (org-test-with-temp-text
-	(format "#+INCLUDE: \"%s/examples/include.org::#ht\" :only-contents t" org-test-dir)
+	(format "#+INCLUDE: \"%s/examples/include.org::#ht\" :only-contents t"
+		org-test-dir)
       (org-export-expand-include-keyword)
       (buffer-string))
     (org-test-with-temp-text
@@ -1167,7 +1170,8 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
    (equal
     ":LOGBOOK:\ndrawer\n:END:\ncontent\n"
     (org-test-with-temp-text
-	(format "#+INCLUDE: \"%s/examples/include.org::#dh\" :only-contents t" org-test-dir)
+	(format "#+INCLUDE: \"%s/examples/include.org::#dh\" :only-contents t"
+		org-test-dir)
       (org-export-expand-include-keyword)
       (buffer-string))))
   ;; Adjacent INCLUDE-keywords should have the same :minlevel if unspecified.
@@ -1175,8 +1179,10 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
    (cl-every (lambda (level) (zerop (1- level)))
 	      (org-test-with-temp-text
 		  (concat
-		   (format "#+INCLUDE: \"%s/examples/include.org::#ah\"\n" org-test-dir)
-		   (format "#+INCLUDE: \"%s/examples/include.org::*Heading\"" org-test-dir))
+		   (format "#+INCLUDE: \"%s/examples/include.org::#ah\"\n"
+			   org-test-dir)
+		   (format "#+INCLUDE: \"%s/examples/include.org::*Heading\""
+			   org-test-dir))
 		(org-export-expand-include-keyword)
 		(org-element-map (org-element-parse-buffer) 'headline
 		  (lambda (head) (org-element-property :level head))))))
@@ -1184,30 +1190,37 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
   (should-not
    (equal
     (org-test-with-temp-text
-	(format "#+INCLUDE: \"%s/examples/include2.org\" src emacs-lisp" org-test-dir)
+	(format "#+INCLUDE: \"%s/examples/include2.org\" src emacs-lisp"
+		org-test-dir)
       (org-export-expand-include-keyword)
       (buffer-string))
     (org-test-with-temp-text
-	(format "#+INCLUDE: \"%s/examples/include2.org\" src emacs-lisp :minlevel 1" org-test-dir)
+	(format
+	 "#+INCLUDE: \"%s/examples/include2.org\" src emacs-lisp :minlevel 1"
+	 org-test-dir)
       (org-export-expand-include-keyword)
       (buffer-string))))
   ;; INCLUDE assigns the relative :minlevel conditional on narrowing.
   (should
    (org-test-with-temp-text-in-file
-       (format "* h1\n<point>#+INCLUDE: \"%s/examples/include.org::#ah\"" org-test-dir)
+       (format "* h1\n<point>#+INCLUDE: \"%s/examples/include.org::#ah\""
+	       org-test-dir)
      (narrow-to-region (point) (point-max))
      (org-export-expand-include-keyword)
      (eq 1 (org-current-level))))
   ;; If :minlevel is present do not alter it.
   (should
    (org-test-with-temp-text
-       (format "* h1\n<point>#+INCLUDE: \"%s/examples/include.org::#ah\" :minlevel 3" org-test-dir)
+       (format
+	"* h1\n<point>#+INCLUDE: \"%s/examples/include.org::#ah\" :minlevel 3"
+	org-test-dir)
      (narrow-to-region (point) (point-max))
      (org-export-expand-include-keyword)
      (eq 3 (org-current-level)))))
 
 (ert-deftest test-org-export/expand-macro ()
   "Test macro expansion in an Org buffer."
+  (require 'ox-org)
   ;; Standard macro expansion.
   (should
    (equal "#+MACRO: macro1 value\nvalue\n"
@@ -1873,7 +1886,7 @@ Para2"
   ;; Test nested footnotes order.
   (should
    (equal
-    '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (3 . "fn:3") (4))
+    '((1 . "1") (2 . "2") (3 . "3") (3 . "3") (4))
     (org-test-with-parsed-data
 	"Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
       (org-element-map tree 'footnote-reference
@@ -1904,7 +1917,7 @@ Para2"
   ;; then footnote definitions.
   (should
    (equal
-    '(("fn:1" . 1) ("fn:2" . 2) ("fn:3" . 3) ("fn:3" . 3))
+    '(("1" . 1) ("2" . 2) ("3" . 3) ("3" . 3))
     (org-test-with-parsed-data
 	"Text[fn:1][fn:2][fn:3]\n\n[fn:1] Def[fn:3]\n[fn:2] Def\n[fn:3] Def"
       (org-element-map tree 'footnote-reference
@@ -1914,7 +1927,7 @@ Para2"
 	info))))
   (should
    (equal
-    '(("fn:1" . 1) ("fn:2" . 3) ("fn:3" . 2) ("fn:3" . 2))
+    '(("1" . 1) ("2" . 3) ("3" . 2) ("3" . 2))
     (org-test-with-parsed-data
 	"Text[fn:1][fn:2][fn:3]\n\n[fn:1] Def[fn:3]\n[fn:2] Def\n[fn:3] Def"
       (org-element-map tree 'footnote-reference
@@ -1936,7 +1949,7 @@ Para2"
   ;; Limit number to provided DATA, when non-nil.
   (should
    (equal
-    '((1 "fn:2"))
+    '((1 "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
@@ -1944,14 +1957,14 @@ Para2"
 	       info (org-element-map tree 'headline #'identity info t))))))
   (should
    (equal
-    '((1 "fn:1") (2 "fn:2"))
+    '((1 "1") (2 "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)
+   (equal '("1" "3" "2" nil)
 	  (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
 
 \[fn:2] B [fn:3] [fn::D].
@@ -1960,7 +1973,7 @@ Para2"
 	    (mapcar (lambda (e) (nth 1 e))
 		    (org-export-collect-footnote-definitions info nil t)))))
   (should-not
-   (equal '("fn:1" "fn:3" "fn:2" nil)
+   (equal '("1" "3" "2" nil)
 	  (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
 
 \[fn:2] B [fn:3] [fn::D].
@@ -1976,9 +1989,9 @@ Para2"
     ;; Read every type of footnote.
     (should
      (equal
-      '((1 . "A\n") (2 . "B") (3 . "C") (4 . "D"))
+      '((1 . "A\n") (2 . "C") (3 . "D"))
       (org-test-with-parsed-data
-	  "Text[fn:1] [1] [fn:label:C] [fn::D]\n\n[fn:1] A\n\n[1] B"
+	  "Text[fn:1] [fn:label:C] [fn::D]\n\n[fn:1] A\n"
 	(org-element-map tree 'footnote-reference
 	  (lambda (ref)
 	    (let ((def (org-export-get-footnote-definition ref info)))
@@ -1990,7 +2003,7 @@ Para2"
     ;; Test nested footnote in invisible definitions.
     (should
      (= 2
-	(org-test-with-temp-text "Text[1]\n\n[1] B [2]\n\n[2] C."
+	(org-test-with-temp-text "Text[fn:1]\n\n[fn:1] B [fn:2]\n\n[fn:2] C."
 	  (narrow-to-region (point) (line-end-position))
 	  (catch 'exit
 	    (org-export-as
@@ -2497,7 +2510,10 @@ Para2"
 		 (org-export-resolve-fuzzy-link link info) info)) info t))))
   ;; Link to a target in a footnote should return footnote's number.
   (org-test-with-parsed-data "
-Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
+Paragraph[fn:1][fn:2][fn:lbl3:C<<target>>][[test]][[target]]
+\[fn:1] A
+
+\[fn:2] <<test>>B"
     (should
      (equal '(2 3)
 	    (org-element-map tree 'link