summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2015-05-06 23:21:10 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2015-05-06 23:47:13 +0200
commit360c4633e2bfad90dcb759146118c848aebcfae5 (patch)
treef63c1d3c4370f9ef8ea8e3e2266604bc2d45364e
parentf6492d953c5a2995e15efc8975c494f8aaebe918 (diff)
downloadorg-mode-360c4633e2bfad90dcb759146118c848aebcfae5.tar.gz
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.
-rw-r--r--lisp/org-footnote.el309
-rw-r--r--testing/lisp/test-org-footnote.el150
2 files changed, 233 insertions, 226 deletions
diff --git a/lisp/org-footnote.el b/lisp/org-footnote.el
index 1ebced5..556cc15 100644
--- a/lisp/org-footnote.el
+++ b/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.
diff --git a/testing/lisp/test-org-footnote.el b/testing/lisp/test-org-footnote.el
index 4e43fe1..d2e838a 100644
--- a/testing/lisp/test-org-footnote.el
+++ b/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."