Browse Source

org-element: Remove dependency on org-footnote predicates

* contrib/lisp/org-element.el (org-element-footnote-definition-parser):
  Remove the need for `org-footnote-at-definition-p'.
  (org-element-footnote-reference-parser): Remove the need for
  `org-footnote-at-reference-p'.
(org-element-footnote-reference-successor): Do not use
`org-footnote-get-next-reference'.
* testing/lisp/test-org-element.el: Add test.
Nicolas Goaziou 13 years ago
parent
commit
8453ac1bf3
2 changed files with 110 additions and 29 deletions
  1. 53 29
      contrib/lisp/org-element.el
  2. 57 0
      testing/lisp/test-org-element.el

+ 53 - 29
contrib/lisp/org-element.el

@@ -273,20 +273,27 @@ CONTENTS is the contents of the element."
 (defun org-element-footnote-definition-parser ()
   "Parse a footnote definition.
 
-Return a list whose car is `footnote-definition' and cdr is
+Return a list whose CAR is `footnote-definition' and CDR is
 a plist containing `:label', `:begin' `:end', `:contents-begin',
-`:contents-end' and `:post-blank' keywords."
+`:contents-end' and `:post-blank' keywords.
+
+Assume point is at the beginning of the footnote definition."
   (save-excursion
-    (let* ((f-def (org-footnote-at-definition-p))
-	   (label (car f-def))
-	   (keywords (progn (goto-char (nth 1 f-def))
-			    (org-element-collect-affiliated-keywords)))
+    (looking-at org-footnote-definition-re)
+    (let* ((label (org-match-string-no-properties 1))
+	   (keywords (org-element-collect-affiliated-keywords))
 	   (begin (car keywords))
-	   (contents-begin (progn (looking-at (concat "\\[" label "\\]"))
-				  (goto-char (match-end 0))
+	   (contents-begin (progn (search-forward "]")
 				  (org-skip-whitespace)
 				  (point)))
-	   (contents-end (goto-char (nth 2 f-def)))
+	   (contents-end (if (progn
+			       (end-of-line)
+			       (re-search-forward
+				(concat org-outline-regexp-bol "\\|"
+					org-footnote-definition-re "\\|"
+					"^[ \t]*$") nil t))
+			     (match-beginning 0)
+			   (point-max)))
 	   (end (progn (org-skip-whitespace)
 		       (if (eobp) (point) (point-at-bol)))))
       `(footnote-definition
@@ -1783,28 +1790,37 @@ its beginning position."
 (defun org-element-footnote-reference-parser ()
   "Parse footnote reference at point.
 
-Return a list whose car is `footnote-reference' and cdr a plist
+Return a list whose CAR is `footnote-reference' and CDR a plist
 with `:label', `:type', `:inline-definition', `:begin', `:end'
 and `:post-blank' as keywords."
   (save-excursion
-    (let* ((ref (org-footnote-at-reference-p))
-	   (label (car ref))
-	   (inline-def
-	    (let ((raw-def (nth 3 ref)))
-	      (and raw-def
-		   (org-element-parse-secondary-string
-		    raw-def
-		    (cdr (assq 'footnote-reference
-			       org-element-string-restrictions))))))
-	   (type (if (nth 3 ref) 'inline 'standard))
-	   (begin (nth 1 ref))
-	   (post-blank (progn (goto-char (nth 2 ref))
+    (looking-at org-footnote-re)
+    (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))
+	   (inner-begin (match-end 0))
+	   (inner-end
+	    (let ((count 1))
+	      (forward-char)
+	      (while (and (> count 0) (re-search-forward "[][]" nil t))
+		(if (equal (match-string 0) "[") (incf count) (decf count)))
+	      (1- (point))))
+	   (post-blank (progn (goto-char (1+ inner-end))
 			      (skip-chars-forward " \t")))
-	   (end (point)))
+	   (end (point))
+	   (inline-definition
+	    (and (eq type 'inline)
+		 (org-element-parse-secondary-string
+		  (buffer-substring inner-begin inner-end)
+		  (cdr (assq 'footnote-reference
+			     org-element-string-restrictions))))))
       `(footnote-reference
 	(:label ,label
 		:type ,type
-		:inline-definition ,inline-def
+		:inline-definition ,inline-definition
 		:begin ,begin
 		:end ,end
 		:post-blank ,post-blank)))))
@@ -1825,11 +1841,19 @@ CONTENTS is nil."
 
 LIMIT bounds the search.
 
-Return value is a cons cell whose car is `footnote-reference' and
-cdr is beginning position."
-  (let (fn-ref)
-     (when (setq fn-ref (org-footnote-get-next-reference nil nil limit))
-       (cons 'footnote-reference (nth 1 fn-ref)))))
+Return value is a cons cell whose CAR is `footnote-reference' and
+CDR is beginning position."
+  (save-excursion
+    (catch 'exit
+      (while (re-search-forward org-footnote-re limit t)
+	(save-excursion
+	  (let ((beg (match-beginning 0))
+		(count 1))
+	    (backward-char)
+	    (while (re-search-forward "[][]" limit t)
+	      (if (equal (match-string 0) "[") (incf count) (decf count))
+	      (when (zerop count)
+		(throw 'exit (cons 'footnote-reference beg))))))))))
 
 
 ;;;; Inline Babel Call

+ 57 - 0
testing/lisp/test-org-element.el

@@ -203,6 +203,63 @@
 	 (equal (org-element-property :label-fmt element) "[ref:%s]"))))))
 
 
+
+;;;; Footnotes references and definitions
+
+(ert-deftest test-org-element/footnote-reference ()
+  "Test footnote-reference parsing."
+  ;; 1. Parse a standard reference.
+  (org-test-with-temp-text "[fn:label]"
+    (should (equal (org-element-footnote-reference-parser)
+		   '(footnote-reference
+		     (:label "fn:label" :type standard :inline-definition nil
+			     :begin 1 :end 11 :post-blank 0)))))
+  ;; 2. Parse a normalized reference.
+  (org-test-with-temp-text "[1]"
+    (should (equal (org-element-footnote-reference-parser)
+		   '(footnote-reference
+		     (:label "1" :type standard :inline-definition nil
+			     :begin 1 :end 4 :post-blank 0)))))
+  ;; 3. Parse an inline reference.
+  (org-test-with-temp-text "[fn:test:def]"
+    (should (equal (org-element-footnote-reference-parser)
+		   '(footnote-reference
+		     (:label "fn:test" :type inline :inline-definition ("def")
+			     :begin 1 :end 14 :post-blank 0)))))
+  ;; 4. Parse an anonymous reference.
+  (org-test-with-temp-text "[fn::def]"
+    (should (equal (org-element-footnote-reference-parser)
+		   '(footnote-reference
+		     (:label nil :type inline :inline-definition ("def")
+			     :begin 1 :end 10 :post-blank 0)))))
+  ;; 5. Parse nested footnotes.
+  (org-test-with-temp-text "[fn::def [fn:label]]"
+    (should
+     (equal
+      (org-element-footnote-reference-parser)
+      '(footnote-reference
+	(:label nil :type inline
+		:inline-definition
+		("def "
+		 (footnote-reference
+		  (:label "fn:label" :type standard :inline-definition nil
+			  :begin 5 :end 15 :post-blank 0)))
+		:begin 1 :end 21 :post-blank 0)))))
+  ;; 6. Parse adjacent footnotes.
+  (org-test-with-temp-text "[fn:label1][fn:label2]"
+    (should
+     (equal
+      (org-element-footnote-reference-parser)
+      '(footnote-reference
+	(:label "fn:label1" :type standard :inline-definition nil :begin 1
+		:end 12 :post-blank 0)))))
+  ;; 7. Only properly closed footnotes are recognized as such.
+  (org-test-with-temp-text "Text [fn:label"
+    (should-not
+     (org-element-map
+      (org-element-parse-buffer) 'footnote-reference 'identity))))
+
+
 
 ;;; Granularity