Browse Source

org-element: Remove :inline-definition from inline footnotes

* lisp/org-element.el (org-element-recursive-objects): Add
  `footnote-reference'.
(org-element-secondary-value-alist): Remove reference to
`footnote-reference'.
(org-element-footnote-reference-parser): Definition for inline
references is stored as the contents of the reference, not in
a secondary string.
(org-element-footnote-reference-interpreter): Apply changes from
parser.

* lisp/ox.el (org-export-get-footnote-definition,
  org-export-get-environment): Apply changes from parser.

* testing/lisp/test-org-element.el (test-org-element/footnote-reference-parser):
  Update test.
(test-org-element/context): Add test.

Storing definition in a secondary string was a poor design choice as
there is no "primary" string anyway.  This also prevents
`org-element-context' from finding objects within the inline
definition.
Nicolas Goaziou 3 years ago
parent
commit
ca6ecf9e49
3 changed files with 86 additions and 77 deletions
  1. 22 32
      lisp/org-element.el
  2. 29 15
      lisp/ox.el
  3. 35 30
      testing/lisp/test-org-element.el

+ 22 - 32
lisp/org-element.el

@@ -194,8 +194,8 @@ is not sufficient to know if point is at a paragraph ending.  See
   "Complete list of object types.")
 
 (defconst org-element-recursive-objects
-  '(bold italic link subscript radio-target strike-through superscript
-	 table-cell underline)
+  '(bold footnote-reference italic link subscript radio-target strike-through
+	 superscript table-cell underline)
   "List of recursive object types.")
 
 (defvar org-element-block-name-alist
@@ -341,8 +341,7 @@ still has an entry since one of its properties (`:title') does.")
 (defconst org-element-secondary-value-alist
   '((headline . :title)
     (inlinetask . :title)
-    (item . :tag)
-    (footnote-reference . :inline-definition))
+    (item . :tag))
   "Alist between element types and location of secondary value.")
 
 (defconst org-element-object-variables '(org-link-abbrev-alist-local)
@@ -2755,16 +2754,17 @@ CONTENTS is nil."
 
 When at a footnote reference, return a list whose car is
 `footnote-reference' and cdr a plist with `:label', `:type',
-`:inline-definition', `:begin', `:end' and `:post-blank' as
-keywords.  Otherwise, return nil."
+`:begin', `:end', `:content-begin', `:contents-end' and
+`:post-blank' as keywords.  Otherwise, return nil."
   (catch 'no-object
     (when (looking-at org-footnote-re)
       (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)))))
+	       (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))
 	       (inner-begin (match-end 0))
 	       (inner-end
@@ -2776,32 +2776,22 @@ keywords.  Otherwise, return nil."
 		  (1- (point))))
 	       (post-blank (progn (goto-char (1+ inner-end))
 				  (skip-chars-forward " \t")))
-	       (end (point))
-	       (footnote-reference
-		(list 'footnote-reference
-		      (list :label label
-			    :type type
-			    :begin begin
-			    :end end
-			    :post-blank post-blank))))
-	  (org-element-put-property
-	   footnote-reference :inline-definition
-	   (and (eq type 'inline)
-		(org-element-parse-secondary-string
-		 (buffer-substring inner-begin inner-end)
-		 (org-element-restriction 'footnote-reference)
-		 footnote-reference))))))))
+	       (end (point)))
+	  (list 'footnote-reference
+		(list :label label
+		      :type type
+		      :begin begin
+		      :end end
+		      :contents-begin (and (eq type 'inline) inner-begin)
+		      :contents-end (and (eq type 'inline) inner-end)
+		      :post-blank post-blank)))))))
 
 (defun org-element-footnote-reference-interpreter (footnote-reference contents)
   "Interpret FOOTNOTE-REFERENCE object as Org syntax.
 CONTENTS is nil."
-  (let ((label (or (org-element-property :label footnote-reference) "fn:"))
-	(def
-	 (let ((inline-def
-		(org-element-property :inline-definition footnote-reference)))
-	   (if (not inline-def) ""
-	     (concat ":" (org-element-interpret-data inline-def))))))
-    (format "[%s]" (concat label def))))
+  (format "[%s]"
+	  (concat (or (org-element-property :label footnote-reference) "fn:")
+		  (and contents (concat ":" contents)))))
 
 
 ;;;; Inline Babel Call

+ 29 - 15
lisp/ox.el

@@ -1579,17 +1579,31 @@ inferior to file-local settings."
     (let (alist)
       (org-with-wide-buffer
        (goto-char (point-min))
-       (while (re-search-forward org-footnote-definition-re nil t)
-	 (let ((def (save-match-data (org-element-at-point))))
-	   (when (eq (org-element-type def) 'footnote-definition)
-	     (push
-	      (cons (org-element-property :label def)
-		    (let ((cbeg (org-element-property :contents-begin def)))
-		      (when cbeg
-			(org-element--parse-elements
-			 cbeg (org-element-property :contents-end def)
-			 nil nil nil nil (list 'org-data nil)))))
-	      alist))))
+       (while (re-search-forward org-footnote-re nil t)
+	 (backward-char)
+	 (let ((fn (save-match-data (org-element-context))))
+	   (case (org-element-type fn)
+	     (footnote-definition
+	      (push
+	       (cons (org-element-property :label fn)
+		     (let ((cbeg (org-element-property :contents-begin fn)))
+		       (when cbeg
+			 (org-element--parse-elements
+			  cbeg (org-element-property :contents-end fn)
+			  nil nil nil nil (list 'org-data nil)))))
+	       alist))
+	     (footnote-reference
+	      (let ((label (org-element-property :label fn))
+		    (cbeg (org-element-property :contents-begin fn)))
+		(when (and label cbeg
+			   (eq (org-element-property :type fn) 'inline))
+		  (push
+		   (cons label
+			 (org-element-parse-secondary-string
+			  (buffer-substring
+			   cbeg (org-element-property :contents-end fn))
+			  (org-element-restriction 'footnote-reference)))
+		   alist)))))))
        alist))
     :id-alist
     ;; Collect id references.
@@ -3689,11 +3703,11 @@ INFO is the plist used as a communication channel."
 (defun org-export-get-footnote-definition (footnote-reference info)
   "Return definition of FOOTNOTE-REFERENCE as parsed data.
 INFO is the plist used as a communication channel.  If no such
-definition can be found, return the \"DEFINITION NOT FOUND\"
-string."
+definition can be found, return \"DEFINITION NOT FOUND\"."
   (let ((label (org-element-property :label footnote-reference)))
-    (or (org-element-property :inline-definition footnote-reference)
-        (cdr (assoc label (plist-get info :footnote-definition-alist)))
+    (or (if label
+	    (cdr (assoc label (plist-get info :footnote-definition-alist)))
+	  (org-element-contents footnote-reference))
 	"DEFINITION NOT FOUND.")))
 
 (defun org-export-get-footnote-number (footnote info)

+ 35 - 30
testing/lisp/test-org-element.el

@@ -891,45 +891,45 @@ Some other text
 
 (ert-deftest test-org-element/footnote-reference-parser ()
   "Test `footnote-reference' parser."
-  ;; 1. Parse a standard reference.
-  (org-test-with-temp-text "Text[fn:label]"
-    (should
+  ;; Parse a standard reference.
+  (should
+   (org-test-with-temp-text "Text[fn:label]"
      (org-element-map
-      (org-element-parse-buffer) 'footnote-reference 'identity)))
-  ;; 2. Parse a normalized reference.
-  (org-test-with-temp-text "Text[1]"
-    (should
+	 (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)))
-  ;; 3. Parse an inline reference.
-  (org-test-with-temp-text "Text[fn:test:def]"
-    (should
+	 (org-element-parse-buffer) 'footnote-reference 'identity)))
+  ;; Parse an inline reference.
+  (should
+   (org-test-with-temp-text "Text[fn:test:def]"
      (org-element-map
-      (org-element-parse-buffer) 'footnote-reference 'identity)))
-  ;; 4. Parse an anonymous reference.
-  (org-test-with-temp-text "Text[fn::def]"
-    (should
+	 (org-element-parse-buffer) 'footnote-reference 'identity)))
+  ;; Parse an anonymous reference.
+  (should
+   (org-test-with-temp-text "Text[fn::def]"
      (org-element-map
-      (org-element-parse-buffer) 'footnote-reference 'identity)))
-  ;; 5. Parse nested footnotes.
-  (org-test-with-temp-text "Text[fn::def [fn:label]]"
-    (should
-     (= 2
-	(length
+	 (org-element-parse-buffer) 'footnote-reference 'identity)))
+  ;; Parse nested footnotes.
+  (should
+   (= 2
+      (length
+       (org-test-with-temp-text "Text[fn::def [fn:label]]"
 	 (org-element-map
-	  (org-element-parse-buffer) 'footnote-reference 'identity)))))
-  ;; 6. Parse adjacent footnotes.
-  (org-test-with-temp-text "Text[fn:label1][fn:label2]"
-    (should
+	     (org-element-parse-buffer) 'footnote-reference 'identity)))))
+  ;; Parse adjacent footnotes.
+  (should
+   (org-test-with-temp-text "Text[fn:label1][fn:label2]"
      (= 2
 	(length
 	 (org-element-map
-	  (org-element-parse-buffer) 'footnote-reference 'identity)))))
-  ;; 7. Only properly closed footnotes are recognized as such.
-  (org-test-with-temp-text "Text[fn:label"
-    (should-not
+	     (org-element-parse-buffer) 'footnote-reference 'identity)))))
+  ;; Only properly closed footnotes are recognized as such.
+  (should-not
+   (org-test-with-temp-text "Text[fn:label"
      (org-element-map
-      (org-element-parse-buffer) 'footnote-reference 'identity))))
+	 (org-element-parse-buffer) 'footnote-reference 'identity))))
 
 
 ;;;; Headline
@@ -3136,6 +3136,11 @@ Paragraph \\alpha."
    (eq 'table-cell
        (org-test-with-temp-text "|a|b|c"
 	 (goto-char (point-max))
+	 (org-element-type (org-element-context)))))
+  ;; Special case: objects in inline footnotes.
+  (should
+   (eq 'link
+       (org-test-with-temp-text "[fn::[[<point>http://orgmode.org]]]"
 	 (org-element-type (org-element-context))))))