Browse Source

org-footnote: Rename `org-footnote-goto-local-insertion-point'

* lisp/org-footnote.el (org-footnote--goto-local-insertion-point):
  Renamed from `org-footnote-goto-local-insertion-point'.
(org-footnote-normalize): Use function above.  Small refactoring.

* testing/lisp/test-org-footnote.el (test-org-footnote/normalize-in-org):
  Small refactoring.
Nicolas Goaziou 5 years ago
parent
commit
360c4633e2
2 changed files with 233 additions and 226 deletions
  1. 154 155
      lisp/org-footnote.el
  2. 79 71
      testing/lisp/test-org-footnote.el

+ 154 - 155
lisp/org-footnote.el

@@ -711,163 +711,162 @@ referenced sequence."
 	  (concat "\\*" (if nstars (format "\\{1,%d\\} " nstars) "+ ")))
 	 (count 0)
 	 ins-point ref ref-table)
-    (save-excursion
-      ;; 1. Find every footnote reference, extract the definition, and
-      ;;    collect that data in REF-TABLE.  If SORT-ONLY is nil, also
-      ;;    normalize references.
-      (goto-char (point-min))
-      (while (setq ref (org-footnote-get-next-reference))
-	(let* ((lbl (car ref))
-	       (pos (nth 1 ref))
-	       ;; When footnote isn't anonymous, check if it's label
-	       ;; (REF) is already stored in REF-TABLE.  In that case,
-	       ;; extract number used to identify it (MARKER).  If
-	       ;; footnote is unknown, increment the global counter
-	       ;; (COUNT) to create an unused identifier.
-	       (a (and lbl (assoc lbl ref-table)))
-	       (marker (or (nth 1 a) (incf count)))
-	       ;; Is the reference inline or pointing to an inline
-	       ;; footnote?
-	       (inlinep (or (stringp (nth 3 ref)) (nth 3 a))))
-	  ;; Replace footnote reference with [MARKER].  Maybe fill
-	  ;; paragraph once done.  If SORT-ONLY is non-nil, only move
-	  ;; to the end of reference found to avoid matching it twice.
-	  (if sort-only (goto-char (nth 2 ref))
-	    (delete-region (nth 1 ref) (nth 2 ref))
-	    (goto-char (nth 1 ref))
-	    (insert (format "[%d]" marker))
-	    (and inlinep
-		 org-footnote-fill-after-inline-note-extraction
-		 (org-fill-paragraph)))
-	  ;; Add label (REF), identifier (MARKER), definition (DEF)
-	  ;; type (INLINEP) and position (POS) to REF-TABLE if data
-	  ;; was unknown.
-	  (unless a
-	    (let ((def (or (nth 3 ref)	; Inline definition.
-			   (nth 3 (org-footnote-get-definition lbl)))))
-	      (push (list lbl marker def
-			  ;; Reference beginning position is a marker
-			  ;; to preserve it during further buffer
-			  ;; modifications.
-			  inlinep (copy-marker pos)) ref-table)))))
-      ;; 2. Find and remove the footnote section, if any.  Also
-      ;;    determine where footnotes shall be inserted (INS-POINT).
-      (cond
-       ((and org-footnote-section (derived-mode-p 'org-mode))
-	(goto-char (point-min))
-	(if (re-search-forward
-	     (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
-		     "[ \t]*$") nil t)
-	    (delete-region (match-beginning 0) (org-end-of-subtree t t)))
-	;; A new footnote section is inserted by default at the end of
-	;; the buffer.
-	(goto-char (point-max))
-	(skip-chars-backward " \r\t\n")
-	(forward-line)
-	(unless (bolp) (newline)))
-       ;; No footnote section set: Footnotes will be added at the end
-       ;; of the section containing their first reference.
-       ((derived-mode-p 'org-mode))
-       (t
-	;; Remove any left-over tag in the buffer, if one is set up.
-	(when org-footnote-tag-for-non-org-mode-files
-	  (let ((tag (concat "^" (regexp-quote
-				  org-footnote-tag-for-non-org-mode-files)
-			     "[ \t]*$")))
-	    (goto-char (point-min))
-	    (while (re-search-forward tag nil t)
-	      (replace-match "")
-	      (delete-region (point) (progn (forward-line) (point))))))
-	;; In Message mode, ensure footnotes are inserted before the
-	;; signature.
-	(if (and (derived-mode-p 'message-mode)
-		 (goto-char (point-max))
-		 (re-search-backward message-signature-separator nil t))
-	    (beginning-of-line)
-	  (goto-char (point-max)))))
-      (setq ins-point (point-marker))
-      ;; 3. Clean-up REF-TABLE.
-      (setq ref-table
-	    (delq nil
-		  (mapcar
-		   (lambda (x)
-		     (cond
-		      ;; When only sorting, ignore inline footnotes.
-		      ;; Also clear position marker.
-		      ((and sort-only (nth 3 x))
-		       (set-marker (nth 4 x) nil) nil)
-		      ;; No definition available: provide one.
-		      ((not (nth 2 x))
-		       (append
-			(list (car x) (nth 1 x)
-			      (format "DEFINITION NOT FOUND: %s" (car x)))
-			(nthcdr 3 x)))
-		      (t x)))
-		   ref-table)))
-      (setq ref-table (nreverse ref-table))
-      ;; 4. Remove left-over definitions in the buffer.
-      (mapc (lambda (x)
-	      (unless (nth 3 x) (org-footnote-delete-definitions (car x))))
-	    ref-table)
-      ;; 5. Insert the footnotes again in the buffer, at the
-      ;;    appropriate spot.
-      (goto-char ins-point)
-      (cond
-       ;; No footnote: exit.
-       ((not ref-table))
-       ;; Cases when footnotes should be inserted in one place.
-       ((or (not (derived-mode-p 'org-mode)) org-footnote-section)
-	;; Insert again the section title, if any.  Ensure that title,
-	;; or the subsequent footnotes, will be separated by a blank
-	;; lines from the rest of the document.  In an Org buffer,
-	;; separate section with a blank line, unless explicitly
-	;; stated in `org-blank-before-new-entry'.
-	(if (not (derived-mode-p 'org-mode))
-	    (progn (skip-chars-backward " \t\n\r")
-		   (delete-region (point) ins-point)
-		   (unless (bolp) (newline))
-		   (when org-footnote-tag-for-non-org-mode-files
-		     (insert "\n" org-footnote-tag-for-non-org-mode-files "\n")))
-	  (when (and (cdr (assq 'heading org-blank-before-new-entry))
-		     (zerop (save-excursion (org-back-over-empty-lines))))
-	    (insert "\n"))
-	  (insert "* " org-footnote-section "\n"))
-	(set-marker ins-point nil)
-	;; Insert the footnotes, separated by a blank line.
-	(insert
-	 (mapconcat
-	  (lambda (x)
-	    ;; Clean markers.
-	    (set-marker (nth 4 x) nil)
-	    (format "\n[%s] %s" (nth (if sort-only 0 1) x) (nth 2 x)))
-	  ref-table "\n"))
-	(unless (eobp) (insert "\n\n")))
-       ;; Each footnote definition has to be inserted at the end of
-       ;; the section where its first reference belongs.
-       (t
-	(mapc
+    (org-with-wide-buffer
+     ;; 1. Find every footnote reference, extract the definition, and
+     ;;    collect that data in REF-TABLE.  If SORT-ONLY is nil, also
+     ;;    normalize references.
+     (goto-char (point-min))
+     (while (setq ref (org-footnote-get-next-reference))
+       (let* ((lbl (car ref))
+	      (pos (nth 1 ref))
+	      ;; When footnote isn't anonymous, check if it's label
+	      ;; (REF) is already stored in REF-TABLE.  In that case,
+	      ;; extract number used to identify it (MARKER).  If
+	      ;; footnote is unknown, increment the global counter
+	      ;; (COUNT) to create an unused identifier.
+	      (a (and lbl (assoc lbl ref-table)))
+	      (marker (or (nth 1 a) (incf count)))
+	      ;; Is the reference inline or pointing to an inline
+	      ;; footnote?
+	      (inlinep (or (stringp (nth 3 ref)) (nth 3 a))))
+	 ;; Replace footnote reference with [MARKER].  Maybe fill
+	 ;; paragraph once done.  If SORT-ONLY is non-nil, only move
+	 ;; to the end of reference found to avoid matching it twice.
+	 (if sort-only (goto-char (nth 2 ref))
+	   (delete-region (nth 1 ref) (nth 2 ref))
+	   (goto-char (nth 1 ref))
+	   (insert (format "[%d]" marker))
+	   (and inlinep
+		org-footnote-fill-after-inline-note-extraction
+		(org-fill-paragraph)))
+	 ;; Add label (REF), identifier (MARKER), definition (DEF)
+	 ;; type (INLINEP) and position (POS) to REF-TABLE if data was
+	 ;; unknown.
+	 (unless a
+	   (let ((def (or (nth 3 ref)	; Inline definition.
+			  (nth 3 (org-footnote-get-definition lbl)))))
+	     (push (list lbl marker def
+			 ;; Reference beginning position is a marker
+			 ;; to preserve it during further buffer
+			 ;; modifications.
+			 inlinep (copy-marker pos)) ref-table)))))
+     ;; 2. Find and remove the footnote section, if any.  Also
+     ;;    determine where footnotes shall be inserted (INS-POINT).
+     (cond
+      ((and org-footnote-section (derived-mode-p 'org-mode))
+       (goto-char (point-min))
+       (if (re-search-forward
+	    (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
+		    "[ \t]*$") nil t)
+	   (delete-region (match-beginning 0) (org-end-of-subtree t t)))
+       ;; A new footnote section is inserted by default at the end of
+       ;; the buffer.
+       (goto-char (point-max))
+       (skip-chars-backward " \r\t\n")
+       (forward-line)
+       (unless (bolp) (newline)))
+      ;; No footnote section set: Footnotes will be added at the end
+      ;; of the section containing their first reference.
+      ((derived-mode-p 'org-mode))
+      (t
+       ;; Remove any left-over tag in the buffer, if one is set up.
+       (when org-footnote-tag-for-non-org-mode-files
+	 (let ((tag (concat "^" (regexp-quote
+				 org-footnote-tag-for-non-org-mode-files)
+			    "[ \t]*$")))
+	   (goto-char (point-min))
+	   (while (re-search-forward tag nil t)
+	     (replace-match "")
+	     (delete-region (point) (progn (forward-line) (point))))))
+       ;; In Message mode, ensure footnotes are inserted before the
+       ;; signature.
+       (if (and (derived-mode-p 'message-mode)
+		(goto-char (point-max))
+		(re-search-backward message-signature-separator nil t))
+	   (beginning-of-line)
+	 (goto-char (point-max)))))
+     (setq ins-point (point-marker))
+     ;; 3. Clean-up REF-TABLE.
+     (setq ref-table
+	   (delq nil
+		 (mapcar
+		  (lambda (x)
+		    (cond
+		     ;; When only sorting, ignore inline footnotes.
+		     ;; Also clear position marker.
+		     ((and sort-only (nth 3 x))
+		      (set-marker (nth 4 x) nil) nil)
+		     ;; No definition available: provide one.
+		     ((not (nth 2 x))
+		      (append
+		       (list (car x) (nth 1 x)
+			     (format "DEFINITION NOT FOUND: %s" (car x)))
+		       (nthcdr 3 x)))
+		     (t x)))
+		  ref-table)))
+     (setq ref-table (nreverse ref-table))
+     ;; 4. Remove left-over definitions in the buffer.
+     (dolist (x ref-table)
+       (unless (nth 3 x) (org-footnote-delete-definitions (car x))))
+     ;; 5. Insert the footnotes again in the buffer, at the
+     ;;    appropriate spot.
+     (goto-char ins-point)
+     (cond
+      ;; No footnote: exit.
+      ((not ref-table))
+      ;; Cases when footnotes should be inserted in one place.
+      ((or (not (derived-mode-p 'org-mode)) org-footnote-section)
+       ;; Insert again the section title, if any.  Ensure that title,
+       ;; or the subsequent footnotes, will be separated by a blank
+       ;; lines from the rest of the document.  In an Org buffer,
+       ;; separate section with a blank line, unless explicitly stated
+       ;; in `org-blank-before-new-entry'.
+       (if (not (derived-mode-p 'org-mode))
+	   (progn (skip-chars-backward " \t\n\r")
+		  (delete-region (point) ins-point)
+		  (unless (bolp) (newline))
+		  (when org-footnote-tag-for-non-org-mode-files
+		    (insert "\n" org-footnote-tag-for-non-org-mode-files "\n")))
+	 (when (and (cdr (assq 'heading org-blank-before-new-entry))
+		    (zerop (save-excursion (org-back-over-empty-lines))))
+	   (insert "\n"))
+	 (insert "* " org-footnote-section "\n"))
+       (set-marker ins-point nil)
+       ;; Insert the footnotes, separated by a blank line.
+       (insert
+	(mapconcat
 	 (lambda (x)
-	   (let ((pos (nth 4 x)))
-	     (goto-char pos)
-	     ;; Clean marker.
-	     (set-marker pos nil))
-	   (org-footnote-goto-local-insertion-point)
-	   (insert (format "\n[%s] %s\n"
-			   (if sort-only (car x) (nth 1 x))
-			   (nth 2 x))))
-	 ref-table))))))
-
-(defun org-footnote-goto-local-insertion-point ()
-  "Find insertion point for footnote, just before next outline heading."
+	   ;; Clean markers.
+	   (set-marker (nth 4 x) nil)
+	   (format "\n[%s] %s" (nth (if sort-only 0 1) x) (nth 2 x)))
+	 ref-table "\n"))
+       (unless (eobp) (insert "\n\n")))
+      ;; Each footnote definition has to be inserted at the end of the
+      ;; section where its first reference belongs.
+      (t
+       (dolist (x ref-table)
+	 (let ((pos (nth 4 x)))
+	   (goto-char pos)
+	   ;; Clean marker.
+	   (set-marker pos nil))
+	 (org-footnote--goto-local-insertion-point)
+	 (insert (format "\n[%s] %s\n"
+			 (nth (if sort-only 0 1) x)
+			 (nth 2 x)))))))))
+
+(defun org-footnote--goto-local-insertion-point ()
+  "Find insertion point for footnote, just before next outline heading.
+Assume insertion point is within currently accessible part of the buffer."
   (org-with-limited-levels (outline-next-heading))
-  (or (bolp) (newline))
-  (beginning-of-line 0)
-  (while (and (not (bobp)) (= (char-after) ?#))
-    (beginning-of-line 0))
-  (if (let ((case-fold-search t)) (looking-at "[ \t]*#\\+tblfm:")) (beginning-of-line 2))
-  (end-of-line 1)
-  (skip-chars-backward "\n\r\t ")
-  (forward-line))
+  ;; Skip file local variables.  See `modify-file-local-variable'.
+  (when (eobp)
+    (let ((case-fold-search t))
+      (re-search-backward "^[ \t]*# +Local Variables:"
+			  (max (- (point-max) 3000) (point-min))
+			  t)))
+  (skip-chars-backward " \t\n")
+  (forward-line)
+  (unless (bolp) (insert "\n")))
 
 (defun org-footnote-delete-references (label)
   "Delete every reference to footnote LABEL.

+ 79 - 71
testing/lisp/test-org-footnote.el

@@ -185,25 +185,10 @@
 
 (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'.
-  (let ((org-footnote-section "Footnotes")
-	(org-blank-before-new-entry '((heading . auto))))
-    ;; 1.1. Normalize each type of footnote: standard, labelled,
-    ;;      numbered, inline, anonymous.
-    (org-test-with-temp-text
-	"Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
-
-* Footnotes
-
-\[fn:1] Standard
-
-\[fn:label] Labelled
-
-\[1] Numbered"
-      (org-footnote-normalize)
-      (should
-       (equal (buffer-string)
-	      "Paragraph[1][2][3][4][5]
+  ;; With a non-nil `org-footnote-section', normalize each type of
+  ;; footnote: standard, labelled, numbered, inline, anonymous.
+  (should
+   (equal "Paragraph[1][2][3][4][5]
 
 * Footnotes
 
@@ -218,51 +203,62 @@
 \[5] Anonymous
 
 
-")))
-    ;; 1.2. When no footnote section is present, create it.  Follow
-    ;;      `org-blank-before-new-entry' specifications when doing so.
-    (org-test-with-temp-text "Paragraph[fn:1]\n\n[fn:1] Definition"
-      (org-footnote-normalize)
-      (should (equal (buffer-string)
-		     "Paragraph[1]\n\n* Footnotes\n\n[1] Definition")))
-    (org-test-with-temp-text "Paragraph[fn:1]\n* Head1\n[fn:1] Definition"
-      (let ((org-blank-before-new-entry '((heading))))
-	(org-footnote-normalize))
-      (should (equal (buffer-string)
-		     "Paragraph[1]\n* Head1\n* Footnotes\n\n[1] Definition")))
-    ;; 1.3. When the footnote section is misplaced, move it at the end
-    ;;      of the buffer.
-    (org-test-with-temp-text "* Head1
-Body[fn:1]
-* Footnotes
-\[fn:1] Definition 1
-* Head2"
-      (org-footnote-normalize)
-      (should
-       (equal (buffer-string)
-	      "* Head1
-Body[1]
-* Head2
+"
+	  (let ((org-footnote-section "Footnotes")
+		(org-blank-before-new-entry '((heading . auto))))
+	    (org-test-with-temp-text
+		"Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
 
 * Footnotes
 
-\[1] Definition 1"))))
-  ;; 2. With a nil `org-footnote-section'.
-  (let ((org-footnote-section nil))
-    ;; 2.1. Normalize each type of footnote: standard, labelled,
-    ;;      numbered, inline, anonymous.
-    (org-test-with-temp-text
-	"Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
-
 \[fn:1] Standard
 
 \[fn:label] Labelled
 
 \[1] Numbered"
-      (org-footnote-normalize)
-      (should
-       (equal (buffer-string)
-	      "Paragraph[1][2][3][4][5]
+	      (org-footnote-normalize)
+	      (buffer-string)))))
+  ;; When no footnote section is present, create it.  Follow
+  ;; `org-blank-before-new-entry' specifications when doing so.
+  (should
+   (equal "Paragraph[1]\n\n* Footnotes\n\n[1] Definition"
+	  (let ((org-footnote-section "Footnotes")
+		(org-blank-before-new-entry '((heading . auto))))
+	    (org-test-with-temp-text "Paragraph[fn:1]\n\n[fn:1] Definition"
+	      (org-footnote-normalize)
+	      (buffer-string)))))
+  (should
+   (equal
+    "Paragraph[1]\n* Head1\n* Footnotes\n\n[1] Definition"
+    (let ((org-footnote-section "Footnotes")
+	  (org-blank-before-new-entry '((heading))))
+      (org-test-with-temp-text "Paragraph[fn:1]\n* Head1\n[fn:1] Definition"
+	(org-footnote-normalize)
+	(buffer-string)))))
+  ;; When the footnote section is misplaced, move it at the end of
+  ;; the buffer.
+  (should
+   (equal
+    "* Head1
+Body[1]
+* Head2
+
+* Footnotes
+
+\[1] Definition 1"
+    (let ((org-footnote-section "Footnotes")
+	  (org-blank-before-new-entry '((heading . auto))))
+      (org-test-with-temp-text "* Head1
+Body[fn:1]
+* Footnotes
+\[fn:1] Definition 1
+* Head2"
+	(org-footnote-normalize)
+	(buffer-string)))))
+  ;; With a nil `org-footnote-section', normalize each type of
+  ;; footnote: standard, labelled, numbered, inline, anonymous.
+  (should
+   (equal "Paragraph[1][2][3][4][5]
 
 \[1] Standard
 
@@ -273,20 +269,22 @@ Body[1]
 \[4] Inline
 
 \[5] Anonymous
-")))
-    ;; 2.2. Put each footnote definition at the end of the section
-    ;;      containing its first reference.
-    (org-test-with-temp-text
-	"* Head 1
-Text[fn:1:Def1]
-* Head 2
-Text[fn:1]
-* Head 3
-Text[fn:2:Def2]"
-      (org-footnote-normalize)
-      (should
-       (equal (buffer-string)
-	      "* Head 1
+"
+	  (let ((org-footnote-section nil))
+	    (org-test-with-temp-text
+		"Paragraph[fn:1][fn:label][1][fn:inline:Inline][fn::Anonymous]
+
+\[fn:1] Standard
+
+\[fn:label] Labelled
+
+\[1] Numbered"
+	      (org-footnote-normalize)
+	      (buffer-string)))))
+  ;; Also put each footnote definition at the end of the section
+  ;; containing its first reference.
+  (should
+   (equal "* Head 1
 Text[1]
 
 \[1] Def1
@@ -296,7 +294,17 @@ Text[1]
 Text[2]
 
 \[2] Def2
-")))))
+"
+	  (let ((org-footnote-section nil))
+	    (org-test-with-temp-text
+		"* Head 1
+Text[fn:1:Def1]
+* Head 2
+Text[fn:1]
+* Head 3
+Text[fn:2:Def2]"
+	      (org-footnote-normalize)
+	      (buffer-string))))))
 
 (ert-deftest test-org-footnote/normalize-outside-org ()
   "Test `org-footnote-normalize' specifications for buffers not in Org mode."