Upstream patches for integrating org-lprint and org-odt.
[org-mode/org-jambu.git] / lisp / org-footnote.el
blob8cf922145e7901b0e8b826e8e16e008d873d5988
1 ;;; org-footnote.el --- Footnote support in Org and elsewhere
2 ;;
3 ;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Carsten Dominik <carsten at orgmode dot org>
6 ;; Keywords: outlines, hypermedia, calendar, wp
7 ;; Homepage: http://orgmode.org
8 ;; Version: 7.5
9 ;;
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation, either version 3 of the License, or
15 ;; (at your option) any later version.
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26 ;;; Commentary:
28 ;; This file contains the code dealing with footnotes in Org-mode.
29 ;; The code can also be used in arbitrary text modes to provide
30 ;; footnotes. Compared to Steven L Baur's footnote.el it provides
31 ;; better support for resuming editing. It is less configurable than
32 ;; Steve's code, though.
34 ;;; Code:
36 (eval-when-compile
37 (require 'cl))
38 (require 'org-macs)
39 (require 'org-compat)
41 (declare-function org-in-commented-line "org" ())
42 (declare-function org-in-regexp "org" (re &optional nlines visually))
43 (declare-function org-mark-ring-push "org" (&optional pos buffer))
44 (declare-function outline-next-heading "outline")
45 (declare-function org-trim "org" (s))
46 (declare-function org-show-context "org" (&optional key))
47 (declare-function org-back-to-heading "org" (&optional invisible-ok))
48 (declare-function org-end-of-subtree "org" (&optional invisible-ok to-heading))
49 (declare-function org-in-verbatim-emphasis "org" ())
50 (declare-function org-inside-latex-macro-p "org" ())
51 (declare-function org-id-uuid "org" ())
52 (defvar org-odd-levels-only) ;; defined in org.el
53 (defvar message-signature-separator) ;; defined in message.el
55 (defconst org-footnote-re
56 (concat "[^][\n]" ; to make sure it is not at the beginning of a line
57 "\\["
58 "\\(?:"
59 "\\([0-9]+\\)"
60 "\\|"
61 (org-re "\\(fn:\\([-_[:word:]]+?\\)?\\)\\(?::\\([^\]]*?\\)\\)?")
62 "\\)"
63 "\\]")
64 "Regular expression for matching footnotes.")
66 (defconst org-footnote-definition-re
67 (org-re "^\\(\\[\\([0-9]+\\|fn:[-_[:word:]]+\\)\\]\\)")
68 "Regular expression matching the definition of a footnote.")
70 (defgroup org-footnote nil
71 "Footnotes in Org-mode."
72 :tag "Org Footnote"
73 :group 'org)
75 (defcustom org-footnote-section "Footnotes"
76 "Outline heading containing footnote definitions before export.
77 This can be nil, to place footnotes locally at the end of the current
78 outline node. If can also be the name of a special outline heading
79 under which footnotes should be put.
80 This variable defines the place where Org puts the definition
81 automatically, i.e. when creating the footnote, and when sorting the notes.
82 However, by hand you may place definitions *anywhere*.
83 If this is a string, during export, all subtrees starting with this
84 heading will be removed after extracting footnote definitions."
85 :group 'org-footnote
86 :type '(choice
87 (string :tag "Collect footnotes under heading")
88 (const :tag "Define footnotes locally" nil)))
90 (defcustom org-footnote-tag-for-non-org-mode-files "Footnotes:"
91 "Tag marking the beginning of footnote section.
92 The Org-mode footnote engine can be used in arbitrary text files as well
93 as in Org-mode. Outside Org-mode, new footnotes are always placed at
94 the end of the file. When you normalize the notes, any line containing
95 only this tag will be removed, a new one will be inserted at the end
96 of the file, followed by the collected and normalized footnotes."
97 :group 'org-footnote
98 :type 'string)
100 (defcustom org-footnote-define-inline nil
101 "Non-nil means define footnotes inline, at reference location.
102 When nil, footnotes will be defined in a special section near
103 the end of the document. When t, the [fn:label:definition] notation
104 will be used to define the footnote at the reference position."
105 :group 'org-footnote
106 :type 'boolean)
108 (defcustom org-footnote-auto-label t
109 "Non-nil means define automatically new labels for footnotes.
110 Possible values are:
112 nil prompt the user for each label
113 t create unique labels of the form [fn:1], [fn:2], ...
114 confirm like t, but let the user edit the created value. In particular,
115 the label can be removed from the minibuffer, to create
116 an anonymous footnote.
117 random Automatically generate a unique, random label.
118 plain Automatically create plain number labels like [1]"
119 :group 'org-footnote
120 :type '(choice
121 (const :tag "Prompt for label" nil)
122 (const :tag "Create automatic [fn:N]" t)
123 (const :tag "Offer automatic [fn:N] for editing" confirm)
124 (const :tag "Create a random label" random)
125 (const :tag "Create automatic [N]" plain)))
127 (defcustom org-footnote-auto-adjust nil
128 "Non-nil means automatically adjust footnotes after insert/delete.
129 When this is t, after each insertion or deletion of a footnote,
130 simple fn:N footnotes will be renumbered, and all footnotes will be sorted.
131 If you want to have just sorting or just renumbering, set this variable
132 to `sort' or `renumber'.
134 The main values of this variable can be set with in-buffer options:
136 #+STARTUP: fnadjust
137 #+STARTUP: nofnadjust"
138 :group 'org-footnote
139 :type '(choice
140 (const :tag "Renumber" renumber)
141 (const :tag "Sort" sort)
142 (const :tag "Renumber and Sort" t)))
144 (defcustom org-footnote-fill-after-inline-note-extraction nil
145 "Non-nil means fill paragraphs after extracting footnotes.
146 When extracting inline footnotes, the lengths of lines can change a lot.
147 When this option is set, paragraphs from which an inline footnote has been
148 extracted will be filled again."
149 :group 'org-footnote
150 :type 'boolean)
152 (defun org-footnote-at-reference-p ()
153 "Is the cursor at a footnote reference?
154 If yes, return the beginning position, the label, and the definition, if local."
155 (when (org-in-regexp org-footnote-re 15)
156 (list (match-beginning 0)
157 (or (match-string 1)
158 (if (equal (match-string 2) "fn:") nil (match-string 2)))
159 (match-string 4))))
161 (defun org-footnote-at-definition-p ()
162 "Is the cursor at a footnote definition.
163 This matches only pure definitions like [1] or [fn:name] at the beginning
164 of a line. It does not match references like [fn:name:definition], where the
165 footnote text is included and defined locally.
166 The return value will be nil if not at a footnote definition, and a list
167 with start and label of the footnote if there is a definition at point."
168 (save-excursion
169 (end-of-line 1)
170 (let ((lim (save-excursion (re-search-backward "^\\*+ \\|^[ \t]*$" nil t))))
171 (when (re-search-backward org-footnote-definition-re lim t)
172 (list (match-beginning 0) (match-string 2))))))
174 (defun org-footnote-goto-definition (label)
175 "Find the definition of the footnote with label LABEL."
176 (interactive "sLabel: ")
177 (org-mark-ring-push)
178 (setq label (org-footnote-normalize-label label))
179 (let ((re (format "^\\[%s\\]\\|.\\[%s:" label label))
180 pos)
181 (save-excursion
182 (setq pos (or (re-search-forward re nil t)
183 (and (goto-char (point-min))
184 (re-search-forward re nil t))
185 (and (progn (widen) t)
186 (goto-char (point-min))
187 (re-search-forward re nil t)))))
188 (if (not pos)
189 (error "Cannot find definition of footnote %s" label)
190 (goto-char pos)
191 (org-show-context 'link-search)
192 (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'."))))
194 (defun org-footnote-goto-previous-reference (label)
195 "Find the first closest (to point) reference of footnote with label LABEL."
196 (interactive "sLabel: ")
197 (org-mark-ring-push)
198 (setq label (org-footnote-normalize-label label))
199 (let ((re (format ".\\[%s[]:]" label))
200 (p0 (point)) pos)
201 (save-excursion
202 (setq pos (or (re-search-backward re nil t)
203 (and (goto-char (point-max))
204 (re-search-backward re nil t))
205 (and (progn (widen) t)
206 (goto-char p0)
207 (re-search-backward re nil t))
208 (and (goto-char (point-max))
209 (re-search-forward re nil t)))))
210 (if pos
211 (progn
212 (goto-char (match-end 0))
213 (org-show-context 'link-search))
214 (error "Cannot find reference of footnote %s" label))))
216 (defun org-footnote-normalize-label (label)
217 (if (numberp label) (setq label (number-to-string label)))
218 (if (not (string-match "^[0-9]+$\\|^$\\|^fn:" label))
219 (setq label (concat "fn:" label)))
220 label)
222 (defun org-footnote-all-labels ()
223 "Return list with all defined foot labels used in the buffer."
224 (let (rtn l)
225 (save-excursion
226 (save-restriction
227 (widen)
228 (goto-char (point-min))
229 (while (re-search-forward org-footnote-definition-re nil t)
230 (setq l (org-match-string-no-properties 2))
231 (and l (add-to-list 'rtn l)))
232 (goto-char (point-min))
233 (while (re-search-forward org-footnote-re nil t)
234 (setq l (or (org-match-string-no-properties 1)
235 (org-match-string-no-properties 2)))
236 (and l (not (equal l "fn:")) (add-to-list 'rtn l)))))
237 rtn))
239 (defun org-footnote-unique-label (&optional current)
240 "Return a new unique footnote label.
241 The returns the firsts fn:N labels that is currently not used."
242 (unless current (setq current (org-footnote-all-labels)))
243 (let ((fmt (if (eq org-footnote-auto-label 'plain) "%d" "fn:%d"))
244 (cnt 1))
245 (while (member (format fmt cnt) current)
246 (incf cnt))
247 (format fmt cnt)))
249 (defvar org-footnote-label-history nil
250 "History of footnote labels entered in current buffer.")
251 (make-variable-buffer-local 'org-footnote-label-history)
253 (defun org-footnote-new ()
254 "Insert a new footnote.
255 This command prompts for a label. If this is a label referencing an
256 existing label, only insert the label. If the footnote label is empty
257 or new, let the user edit the definition of the footnote."
258 (interactive)
259 (let* ((labels (and (not (equal org-footnote-auto-label 'random))
260 (org-footnote-all-labels)))
261 (propose (org-footnote-unique-label labels))
262 (label
263 (cond
264 ((member org-footnote-auto-label '(t plain))
265 propose)
266 ((equal org-footnote-auto-label 'random)
267 (require 'org-id)
268 (substring (org-id-uuid) 0 8))
270 (completing-read
271 "Label (leave empty for anonymous): "
272 (mapcar 'list labels) nil nil
273 (if (eq org-footnote-auto-label 'confirm) propose nil)
274 'org-footnote-label-history)))))
275 (setq label (org-footnote-normalize-label label))
276 (cond
277 ((equal label "")
278 (insert "[fn:: ]")
279 (backward-char 1))
280 ((member label labels)
281 (insert "[" label "]")
282 (message "New reference to existing note"))
283 (org-footnote-define-inline
284 (insert "[" label ": ]")
285 (backward-char 1)
286 (org-footnote-auto-adjust-maybe))
288 (insert "[" label "]")
289 (org-footnote-create-definition label)
290 (org-footnote-auto-adjust-maybe)))))
292 (defun org-footnote-create-definition (label)
293 "Start the definition of a footnote with label LABEL."
294 (interactive "sLabel: ")
295 (setq label (org-footnote-normalize-label label))
296 (let (re)
297 (cond
298 ((org-mode-p)
299 (if (not org-footnote-section)
300 ;; No section, put footnote into the current outline node
302 ;; Try to find or make the special node
303 (goto-char (point-min))
304 (setq re (concat "^\\*+[ \t]+" org-footnote-section "[ \t]*$"))
305 (unless (or (re-search-forward re nil t)
306 (and (progn (widen) t)
307 (re-search-forward re nil t)))
308 (goto-char (point-max))
309 (insert "\n\n* " org-footnote-section "\n")))
310 ;; Now go to the end of this entry and insert there.
311 (org-footnote-goto-local-insertion-point)
312 (org-show-context 'link-search))
314 (setq re (concat "^" org-footnote-tag-for-non-org-mode-files "[ \t]*$"))
315 (unless (re-search-forward re nil t)
316 (let ((max (if (and (derived-mode-p 'message-mode)
317 (re-search-forward message-signature-separator nil t))
318 (progn (beginning-of-line) (point))
319 (goto-char (point-max)))))
320 (skip-chars-backward " \t\r\n")
321 (delete-region (point) max)
322 (insert "\n\n")
323 (insert org-footnote-tag-for-non-org-mode-files "\n")))
324 ;; Skip existing footnotes
325 (while (re-search-forward "^[[:space:]]*\\[[^]]+\\] " nil t)
326 (forward-line))))
327 (insert "\n[" label "] \n")
328 (goto-char (1- (point)))
329 (message "Edit definition and go back with `C-c &' or, if unique, with `C-c C-c'.")))
331 ;;;###autoload
332 (defun org-footnote-action (&optional special)
333 "Do the right thing for footnotes.
334 When at a footnote reference, jump to the definition. When at a definition,
335 jump to the references. When neither at definition or reference,
336 create a new footnote, interactively.
337 With prefix arg SPECIAL, offer additional commands in a menu."
338 (interactive "P")
339 (let (tmp c)
340 (cond
341 (special
342 (message "Footnotes: [s]ort | [r]enumber fn:N | [S]=r+s |->[n]umeric | [d]elete")
343 (setq c (read-char-exclusive))
344 (cond
345 ((equal c ?s)
346 (org-footnote-normalize 'sort))
347 ((equal c ?r)
348 (org-footnote-renumber-fn:N))
349 ((equal c ?S)
350 (org-footnote-renumber-fn:N)
351 (org-footnote-normalize 'sort))
352 ((equal c ?n)
353 (org-footnote-normalize))
354 ((equal c ?d)
355 (org-footnote-delete))
356 (t (error "No such footnote command %c" c))))
357 ((setq tmp (org-footnote-at-reference-p))
358 (if (nth 1 tmp)
359 (org-footnote-goto-definition (nth 1 tmp))
360 (goto-char (match-beginning 4))))
361 ((setq tmp (org-footnote-at-definition-p))
362 (org-footnote-goto-previous-reference (nth 1 tmp)))
363 (t (org-footnote-new)))))
365 (defvar org-footnote-insert-pos-for-preprocessor 'point-max
366 "See `org-footnote-normalize'.")
368 ;;;###autoload
369 (defun org-footnote-normalize (&optional sort-only for-preprocessor)
370 "Collect the footnotes in various formats and normalize them.
371 This finds the different sorts of footnotes allowed in Org, and
372 normalizes them to the usual [N] format that is understood by the
373 Org-mode exporters.
374 When SORT-ONLY is set, only sort the footnote definitions into the
375 referenced sequence.
377 When FOR-PREPROCESSOR is non nil, the default action, is to
378 insert normalized footnotes towards the end of the pre-processing
379 buffer. Some exporters like docbook, odt etc expect that footnote
380 definitions be available before any references to them. Such
381 exporters can let bind `org-footnote-insert-pos-for-preprocessor'
382 to symbol 'point-min to achieve the desired behaviour.
384 Additional note on `org-footnote-insert-pos-for-preprocessor':
385 1. This variable has not effect when FOR-PREPROCESSOR is nil.
386 2. This variable (potentially) obviates the need for extra scan
387 of pre-processor buffer as witnessed in
388 `org-export-docbook-get-footnotes'."
389 ;; This is based on Paul's function, but rewritten.
390 (let* ((limit-level
391 (and (boundp 'org-inlinetask-min-level)
392 org-inlinetask-min-level
393 (1- org-inlinetask-min-level)))
394 (nstars (and limit-level
395 (if org-odd-levels-only
396 (and limit-level (1- (* limit-level 2)))
397 limit-level)))
398 (outline-regexp
399 (concat "\\*" (if nstars (format "\\{1,%d\\} " nstars) "+ ")))
400 (count 0)
401 ref def idef ref-table beg beg1 marker a before ins-point)
402 (save-excursion
403 ;; Now find footnote references, and extract the definitions
404 (goto-char (point-min))
405 (while (re-search-forward org-footnote-re nil t)
406 (unless (or (org-in-commented-line) (org-in-verbatim-emphasis)
407 (org-inside-latex-macro-p))
408 (org-if-unprotected
409 (setq def (match-string 4)
410 idef def
411 ref (or (match-string 1) (match-string 2))
412 before (char-to-string (char-after (match-beginning 0))))
413 (if (equal ref "fn:") (setq ref nil))
414 (if (and ref (setq a (assoc ref ref-table)))
415 (progn
416 (setq marker (nth 1 a))
417 (unless (nth 2 a) (setf (caddr a) def)))
418 (setq marker (number-to-string (incf count))))
419 (save-match-data
420 (if def
421 (setq def (org-trim def))
422 (save-excursion
423 (goto-char (point-min))
424 (if (not (re-search-forward (concat "^\\[" (regexp-quote ref)
425 "\\]") nil t))
426 (setq def nil)
427 (setq beg (match-beginning 0))
428 (setq beg1 (match-end 0))
429 (re-search-forward
430 (org-re "^[ \t]*$\\|^\\*+ \\|^\\[\\([0-9]+\\|fn:[-_[:word:]]+\\)\\]")
431 nil 'move)
432 (setq def (buffer-substring beg1 (or (match-beginning 0)
433 (point-max))))
434 (goto-char beg)
435 (skip-chars-backward " \t\n\t")
436 (delete-region (1+ (point)) (match-beginning 0))))))
437 (unless sort-only
438 (replace-match (concat before "[" marker "]") t t)
439 (and idef
440 org-footnote-fill-after-inline-note-extraction
441 (fill-paragraph)))
442 (if (not a) (push (list ref marker def (if idef t nil))
443 ref-table)))))
445 ;; First find and remove the footnote section
446 (goto-char (point-min))
447 (cond
448 ((org-mode-p)
449 (if (and org-footnote-section
450 (re-search-forward
451 (concat "^\\*[ \t]+" (regexp-quote org-footnote-section)
452 "[ \t]*$")
453 nil t))
454 (if (or for-preprocessor (not org-footnote-section))
455 (replace-match "")
456 (org-back-to-heading t)
457 (forward-line 1)
458 (setq ins-point (point))
459 (delete-region (point) (org-end-of-subtree t)))
460 (goto-char (point-max))
461 (unless for-preprocessor
462 (when org-footnote-section
463 (or (bolp) (insert "\n"))
464 (insert "* " org-footnote-section "\n")
465 (setq ins-point (point))))))
467 (if (re-search-forward
468 (concat "^"
469 (regexp-quote org-footnote-tag-for-non-org-mode-files)
470 "[ \t]*$")
471 nil t)
472 (replace-match ""))
473 (goto-char (point-max))
474 (skip-chars-backward " \t\n\r")
475 (delete-region (point) (point-max))
476 (insert "\n\n" org-footnote-tag-for-non-org-mode-files "\n")
477 (setq ins-point (point))))
479 ;; Insert the footnotes again
480 (goto-char (or (and for-preprocessor
481 (equal org-footnote-insert-pos-for-preprocessor
482 'point-min)
483 (point-min))
484 ins-point
485 (point-max)))
486 (setq ref-table (reverse ref-table))
487 (when sort-only
488 ;; remove anonymous and inline footnotes from the list
489 (setq ref-table
490 (delq nil (mapcar
491 (lambda (x) (and (car x)
492 (not (equal (car x) "fn:"))
493 (not (nth 3 x))
495 ref-table))))
496 ;; Make sure each footnote has a description, or an error message.
497 (setq ref-table
498 (mapcar
499 (lambda (x)
500 (if (not (nth 2 x))
501 (setcar (cddr x)
502 (format "FOOTNOTE DEFINITION NOT FOUND: %s" (car x)))
503 (setcar (cddr x) (org-trim (nth 2 x))))
505 ref-table))
507 (if (or (not (org-mode-p)) ; not an Org file
508 org-footnote-section ; we do not use a footnote section
509 (not sort-only) ; this is normalization
510 for-preprocessor) ; the is the preprocessor
511 ;; Insert the footnotes together in one place
512 (progn
513 (setq def
514 (mapconcat
515 (lambda (x)
516 (format "[%s] %s" (nth (if sort-only 0 1) x)
517 (org-trim (nth 2 x))))
518 ref-table "\n\n"))
519 (if ref-table (insert "\n" def "\n\n")))
520 ;; Insert each footnote near the first reference
521 ;; Happens only in Org files with no special footnote section,
522 ;; and only when doing sorting
523 (mapc 'org-insert-footnote-reference-near-definition
524 ref-table)))))
526 (defun org-insert-footnote-reference-near-definition (entry)
527 "Find first reference of footnote ENTRY and insert the definition there.
528 ENTRY is (fn-label num-mark definition)."
529 (when (car entry)
530 (goto-char (point-min))
531 (when (re-search-forward (format ".\\[%s[]:]" (regexp-quote (car entry)))
532 nil t)
533 (org-footnote-goto-local-insertion-point)
534 (insert (format "\n[%s] %s\n" (car entry) (nth 2 entry))))))
536 (defun org-footnote-goto-local-insertion-point ()
537 "Find insertion point for footnote, just before next outline heading."
538 (org-with-limited-levels (outline-next-heading))
539 (or (bolp) (newline))
540 (beginning-of-line 0)
541 (while (and (not (bobp)) (= (char-after) ?#))
542 (beginning-of-line 0))
543 (if (looking-at "[ \t]*#\\+TBLFM:") (beginning-of-line 2))
544 (end-of-line 1)
545 (skip-chars-backward "\n\r\t ")
546 (forward-line))
548 (defun org-footnote-delete (&optional label)
549 "Delete the footnote at point.
550 This will remove the definition (even multiple definitions if they exist)
551 and all references of a footnote label."
552 (catch 'done
553 (let (x label l beg def-re (nref 0) (ndef 0))
554 (unless label
555 (when (setq x (org-footnote-at-reference-p))
556 (setq label (nth 1 x))
557 (when (or (not label) (equal "fn:" label))
558 (delete-region (1+ (match-beginning 0)) (match-end 0))
559 (message "Anonymous footnote removed")
560 (throw 'done t)))
561 (when (and (not label) (setq x (org-footnote-at-definition-p)))
562 (setq label (nth 1 x)))
563 (unless label (error "Don't know which footnote to remove")))
564 (save-excursion
565 (save-restriction
566 (goto-char (point-min))
567 (while (re-search-forward org-footnote-re nil t)
568 (setq l (or (match-string 1) (match-string 2)))
569 (when (equal l label)
570 (delete-region (1+ (match-beginning 0)) (match-end 0))
571 (incf nref)))
572 (goto-char (point-min))
573 (setq def-re (concat "^\\[" (regexp-quote label) "\\]"))
574 (while (re-search-forward def-re nil t)
575 (setq beg (match-beginning 0))
576 (if (re-search-forward "^\\[\\|^[ \t]*$\\|^\\*+ " nil t)
577 (goto-char (match-beginning 0))
578 (goto-char (point-max)))
579 (delete-region beg (point))
580 (incf ndef))))
581 (org-footnote-auto-adjust-maybe)
582 (message "%d definition(s) of and %d reference(s) of footnote %s removed"
583 ndef nref label))))
585 (defun org-footnote-renumber-fn:N ()
586 "Renumber the simple footnotes like fn:17 into a sequence in the document."
587 (interactive)
588 (let (map i (n 0))
589 (save-excursion
590 (save-restriction
591 (widen)
592 (goto-char (point-min))
593 (while (re-search-forward "\\[fn:\\([0-9]+\\)[]:]" nil t)
594 (setq i (string-to-number (match-string 1)))
595 (when (and (string-match "\\S-" (buffer-substring
596 (point-at-bol) (match-beginning 0)))
597 (not (assq i map)))
598 (push (cons i (number-to-string (incf n))) map)))
599 (goto-char (point-min))
600 (while (re-search-forward "\\(\\[fn:\\)\\([0-9]+\\)\\([]:]\\)" nil t)
601 (replace-match (concat "\\1" (cdr (assq (string-to-number (match-string 2)) map)) "\\3")))))))
603 (defun org-footnote-auto-adjust-maybe ()
604 "Renumber and/or sort footnotes according to user settings."
605 (when (memq org-footnote-auto-adjust '(t renumber))
606 (org-footnote-renumber-fn:N))
607 (when (memq org-footnote-auto-adjust '(t sort))
608 (let ((label (nth 1 (org-footnote-at-definition-p))))
609 (org-footnote-normalize 'sort)
610 (when label
611 (goto-char (point-min))
612 (and (re-search-forward (concat "^\\[" (regexp-quote label) "\\]")
613 nil t)
614 (progn (insert " ")
615 (just-one-space)))))))
617 (provide 'org-footnote)
619 ;; arch-tag: 1b5954df-fb5d-4da5-8709-78d944dbfc37
621 ;;; org-footnote.el ends here