Browse Source

org-footnote: Fix `org-footnote-goto-previous-reference'

* lisp/org-footnote.el (org-footnote-goto-previous-reference): Only
  add to mark ring on a successful match.  Improve error message when
  reference is outside visible part of buffer.
(org-footnote-get-next-reference): Avoid using
`org-footnote-at-reference-p', which is inaccurate, due to
`org-footnote-in-valid-context-p'.
* testing/lisp/test-org-footnote.el (test-org-footnote/goto-previous-reference):
  New test.
Nicolas Goaziou 11 months ago
parent
commit
627cb7f578
2 changed files with 59 additions and 24 deletions
  1. 37 24
      lisp/org-footnote.el
  2. 22 0
      testing/lisp/test-org-footnote.el

+ 37 - 24
lisp/org-footnote.el

@@ -467,16 +467,27 @@ the buffer position bounding the search.
 
 Return value is a list like those provided by `org-footnote-at-reference-p'.
 If no footnote is found, return nil."
-  (save-excursion
-    (let* ((label-fmt (if label (format "\\[fn:%s[]:]" label) org-footnote-re)))
-      (catch 'exit
-	(while t
-	  (unless (funcall (if backward #'re-search-backward #'re-search-forward)
-			   label-fmt limit t)
-	    (throw 'exit nil))
+  (let ((label-fmt (if label (format "\\[fn:%s[]:]" label) org-footnote-re)))
+    (catch :exit
+      (save-excursion
+	(while (funcall (if backward #'re-search-backward #'re-search-forward)
+			label-fmt limit t)
 	  (unless backward (backward-char))
-	  (let ((ref (org-footnote-at-reference-p)))
-	    (when ref (throw 'exit ref))))))))
+	  (let ((reference (org-element-context)))
+	    (when (eq 'footnote-reference (org-element-type reference))
+	      (throw :exit
+		     (list
+		      (org-element-property :label reference)
+		      (org-element-property :begin reference)
+		      (save-excursion
+			(goto-char (org-element-property :end reference))
+			(skip-chars-backward " \t")
+			(point))
+		      (and (eq 'inline (org-element-property :type reference))
+			   (buffer-substring-no-properties
+			    (org-element-property :contents-begin reference)
+			    (org-element-property :contents-end
+						  reference))))))))))))
 
 (defun org-footnote-next-reference-or-definition (limit)
   "Move point to next footnote reference or definition.
@@ -537,21 +548,23 @@ value if point was successfully moved."
 (defun org-footnote-goto-previous-reference (label)
   "Find the first closest (to point) reference of footnote with label LABEL."
   (interactive "sLabel: ")
-  (org-mark-ring-push)
-  (let ((label (org-footnote-normalize-label label))
-	ref)
-    (save-excursion
-      (setq ref (or (org-footnote-get-next-reference label t)
-		    (org-footnote-get-next-reference label)
-		    (save-restriction
-		      (widen)
-		      (or
-		       (org-footnote-get-next-reference label t)
-		       (org-footnote-get-next-reference label))))))
-    (if (not ref)
-	(error "Cannot find reference of footnote %s" label)
-      (goto-char (nth 1 ref))
-      (org-show-context 'link-search))))
+  (let* ((label (org-footnote-normalize-label label))
+	 (reference
+	  (save-excursion
+	    (or (org-footnote-get-next-reference label t)
+		(org-footnote-get-next-reference label)
+		(and (buffer-narrowed-p)
+		     (org-with-wide-buffer
+		      (or (org-footnote-get-next-reference label t)
+			  (org-footnote-get-next-reference label)))))))
+	 (start (nth 1 reference)))
+    (cond ((not reference)
+	   (user-error "Cannot find reference of footnote %S" label))
+	  ((or (> start (point-max)) (< start (point-min)))
+	   (user-error "Reference is outside narrowed part of buffer")))
+    (org-mark-ring-push)
+    (goto-char start)
+    (org-show-context 'link-search)))
 
 
 ;;;; Getters

+ 22 - 0
testing/lisp/test-org-footnote.el

@@ -242,6 +242,28 @@
       (org-footnote-goto-definition "label")
       (buffer-substring (point) (point-max))))))
 
+(ert-deftest test-org-footnote/goto-previous-reference ()
+  "Test `org-footnote-goto-previous-reference' specifications."
+  ;; Error on unknown reference.
+  (should-error
+   (org-test-with-temp-text "No footnote reference"
+     (org-footnote-goto-previous-reference "1")))
+  ;; Error when trying to reach a reference outside narrowed part of
+  ;; buffer.
+  (should-error
+   (org-test-with-temp-text "Some text<point>\nReference[fn:1]."
+     (narrow-to-region (point-min) (point))
+     (org-footnote-goto-previous-reference "1")))
+  ;; Otherwise, move to closest reference from point.
+  (should
+   (org-test-with-temp-text "First reference[fn:1]\nReference[fn:1].<point>"
+     (org-footnote-goto-previous-reference "1")
+     (= (line-end-position) (point-max))))
+  (should
+   (org-test-with-temp-text "First reference[fn:1]\nReference[fn:1]."
+     (org-footnote-goto-previous-reference "1")
+     (= (line-beginning-position) (point-min)))))
+
 (ert-deftest test-org-footnote/sort ()
   "Test `org-footnote-sort' specifications."
   ;; Reorder definitions with a nil `org-footnote-section'.  In this