1 ;;; footnote.el --- Footnote support for message mode
3 ;; Copyright (C) 1997 by Free Software Foundation, Inc.
5 ;; Author: Steven L Baur <steve@xemacs.org>
6 ;; Keywords: mail, news
9 ;; This file is part of XEmacs.
11 ;; XEmacs is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; XEmacs is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free
23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 ;;; Synched up with: Not in FSF
30 ;; This file provides footnote[1] support for message-mode in emacsen.
31 ;; footnote-mode is implemented as a minor mode.
33 ;; [1] Footnotes look something like this. Along with some decorative
37 ;; Reasonable Undo support.
38 ;; more language styles.
40 ;;; Change Log before introduction of the separate ChangeLog file:
42 ;; Apr-04-1997: Added option to narrow buffer when editing the text of
44 ;; Insertion and renumbering now works.
45 ;; Deletion and renumbering now works.
46 ;; Footnote styles implemented.
47 ;; Apr-05-1997: Added dumb version of footnote-set-style.
48 ;; Merged minor corrections from Hrvoje Niksic, Sudish Joseph,
50 ;; Remove absolute dependency on message-mode.
51 ;; Replicate letters when footnote numbers hit the end of
53 ;; Apr-06-1997: Emacs portability patches from Lars Magne Ingebrigtsen.
54 ;; Apr-18-1997: Stricter matching of footnote tag. (Idea from Colin Rafferty)
55 ;; May-16-1997: Allow customization of spacing of footnote body tag. (Idea
56 ;; from Samuel Tardieu).
62 (defgroup footnote nil
63 "Support for footnotes in mail and news messages."
67 (defcustom footnote-mode-line-string " FN"
68 "*String to display in modes section of the mode-line."
71 (defcustom footnote-mode-hook nil
72 "*Hook functions run when footnote-mode is activated."
76 (defcustom footnote-narrow-to-footnotes-when-editing nil
77 "*If set, narrow to footnote text body while editing a footnote."
81 (defcustom footnote-prompt-before-deletion t
82 "*If set, prompt before deleting a footnote.
83 There is currently no way to undo deletions."
87 (defcustom footnote-spaced-footnotes t
88 "If set true it will put a blank line between each footnote.
89 If nil, no blank line will be inserted."
93 (defcustom footnote-always-blank-line-before-signature t
94 "If set true, a blank line will always be inserted before signature.
95 This has visible effect only when `footnote-spaced-footnotes' is not true."
99 (defcustom footnote-style 'numeric
100 "*Style used for footnoting.
101 numeric == 1, 2, 3, ...
102 numeric-latin == {¹, ², ³} | {1, 2, 3, 4, ...}
103 english-lower == a, b, c, ...
104 english-upper == A, B, C, ...
105 roman-lower == i, ii, iii, iv, v, ...
106 roman-upper == I, II, III, IV, V, ...
107 Some versions of XEmacs and Emacs/mule may support further styles
108 like 'hebrew, 'greek-lower, and 'greek-upper."
112 (defcustom footnote-use-message-mode t
113 "*If non-nil assume Footnoting will be done in message-mode."
117 (defcustom footnote-body-tag-spacing 2
118 "*Number of blanks separating a footnote body tag and its text."
123 (defvar footnote-prefix [(control ?c) ?!]
124 "*When not using message mode, the prefix to bind in `mode-specific-map'")
126 ;;; Interface variables that probably shouldn't be changed
128 ;; FIXME! Make this customize-able?
129 (defvar footnote-section-tag "Footnotes: "
130 "*Tag inserted at beginning of footnote section.")
132 (defvar footnote-section-tag-regexp footnote-section-tag
133 "*Regexp which indicates the start of a footnote section.")
135 ;; FIXME! Make these customize-able?
136 (defvar footnote-start-tag "["
137 "*String used to denote start of numbered footnote.")
139 (defvar footnote-end-tag "]"
140 "*String used to denote end of numbered footnote.")
142 (defvar footnote-signature-separator (if (boundp 'message-signature-separator)
143 message-signature-separator
145 "*String used to recognize .signatures.")
147 ;;; Private variables
149 (defvar footnote-text-marker-alist nil
150 "List of markers pointing to text of footnotes in message buffer.")
151 (make-variable-buffer-local 'footnote-text-marker-alist)
153 (defvar footnote-pointer-marker-alist nil
154 "List of markers pointing to footnote pointers in message buffer.")
155 (make-variable-buffer-local 'footnote-pointer-marker-alist)
157 (defvar footnote-mouse-highlight 'highlight
158 "Text property name to enable mouse over highlight.")
160 (defvar footnote-mode nil
161 "Variable indicating whether footnote minor mode is active.")
162 (make-variable-buffer-local 'footnote-mode)
164 (defvar footnote-style-is-really-numeric-latin nil
165 "Whether current numeric style is actually numeric-latin.")
166 (make-variable-buffer-local 'footnote-style-is-really-numeric-latin)
170 (defconst footnote-numeric-latin-regexp "[¹²³]"
171 "Regexp for Latin superscript digits.")
173 (defun Footnote-numeric-latin (n)
174 "Numeric-latin footnote style.
175 Use latin superscript digits if no more than three footnotes."
180 (t (error "This should never happen."))))
183 (defconst footnote-numeric-regexp "[0-9]"
184 "Regexp for digits.")
186 (defun Footnote-numeric (n)
187 "Numeric footnote style.
188 Use Arabic numerals for footnoting."
192 (defconst footnote-english-upper "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
193 "Upper case English alphabet.")
195 (defconst footnote-english-upper-regexp "[A-Z]"
196 "Regexp for upper case English alphabet.")
198 (defun Footnote-english-upper (n)
199 "Upper case English footnoting.
200 Wrapping around the alphabet implies successive repetitions of letters."
201 (let* ((ltr (mod (1- n) (length footnote-english-upper)))
202 (rep (/ (1- n) (length footnote-english-upper)))
203 (chr (char-to-string (aref footnote-english-upper ltr)))
206 (setq rc (concat rc chr))
211 (defconst footnote-english-lower "abcdefghijklmnopqrstuvwxyz"
212 "Lower case English alphabet.")
214 (defconst footnote-english-lower-regexp "[a-z]"
215 "Regexp of lower case English alphabet.")
217 (defun Footnote-english-lower (n)
218 "Lower case English footnoting.
219 Wrapping around the alphabet implies successive repetitions of letters."
220 (let* ((ltr (mod (1- n) (length footnote-english-lower)))
221 (rep (/ (1- n) (length footnote-english-lower)))
222 (chr (char-to-string (aref footnote-english-lower ltr)))
225 (setq rc (concat rc chr))
230 (defconst footnote-roman-lower-list
231 '((1 . "i") (5 . "v") (10 . "x")
232 (50 . "l") (100 . "c") (500 . "d") (1000 . "m"))
233 "List of roman numerals with their values.")
235 (defconst footnote-roman-lower-regexp "[ivxlcdm]"
236 "Regexp of roman numerals.")
238 (defun Footnote-roman-lower (n)
239 "Generic Roman number footnoting."
240 (Footnote-roman-common n footnote-roman-lower-list))
243 (defconst footnote-roman-upper-list
244 '((1 . "I") (5 . "V") (10 . "X")
245 (50 . "L") (100 . "C") (500 . "D") (1000 . "M"))
246 "List of roman numerals with their values.")
248 (defconst footnote-roman-upper-regexp "[IVXLCDM]"
249 "Regexp of roman numerals. Not complete")
251 (defun Footnote-roman-upper (n)
252 "Generic Roman number footnoting."
253 (Footnote-roman-common n footnote-roman-upper-list))
255 (defun Footnote-roman-common (n footnote-roman-list)
256 "Lower case Roman footnoting."
257 (let* ((our-list footnote-roman-list)
258 (rom-lngth (length our-list))
264 ;; find surrounding numbers
265 (while (and (<= count-high (1- rom-lngth))
266 (>= n (car (nth count-high our-list))))
267 ;; (message "Checking %d" (car (nth count-high our-list)))
268 (setq count-high (1+ count-high)))
269 (setq rom-high count-high)
270 (setq rom-low (1- count-high))
271 ;; find the appropriate divisor (if it exists)
272 (while (and (= rom-div -1)
273 (< count-low rom-high))
274 (when (or (> n (- (car (nth rom-high our-list))
275 (/ (car (nth count-low our-list))
277 (= n (- (car (nth rom-high our-list))
278 (car (nth count-low our-list)))))
279 (setq rom-div count-low))
280 ;; (message "Checking %d and %d in div loop" rom-high count-low)
281 (setq count-low (1+ count-low)))
282 ;;(message "We now have high: %d, low: %d, div: %d, n: %d"
283 ;; rom-high rom-low (if rom-div rom-div -1) n)
284 (let ((rom-low-pair (nth rom-low our-list))
285 (rom-high-pair (nth rom-high our-list))
286 (rom-div-pair (if (not (= rom-div -1)) (nth rom-div our-list) nil)))
287 ;; (message "pairs are: rom-low: %S, rom-high: %S, rom-div: %S"
288 ;; rom-low-pair rom-high-pair rom-div-pair)
290 ((< n 0) (error "Footnote-roman-common called with n < 0"))
292 ((= n (car rom-low-pair)) (cdr rom-low-pair))
293 ((= n (car rom-high-pair)) (cdr rom-high-pair))
294 ((= (car rom-low-pair) (car rom-high-pair))
295 (concat (cdr rom-low-pair)
296 (Footnote-roman-common
297 (- n (car rom-low-pair))
298 footnote-roman-list)))
299 ((>= rom-div 0) (concat (cdr rom-div-pair) (cdr rom-high-pair)
300 (Footnote-roman-common
301 (- n (- (car rom-high-pair)
303 footnote-roman-list)))
304 (t (concat (cdr rom-low-pair)
305 (Footnote-roman-common
306 (- n (car rom-low-pair))
307 footnote-roman-list)))))))
309 ;;; list of all footnote styles
310 (defvar footnote-style-alist
311 `((numeric Footnote-numeric ,footnote-numeric-regexp)
312 (numeric-latin Footnote-numeric-latin ,footnote-numeric-latin-regexp
314 (english-lower Footnote-english-lower ,footnote-english-lower-regexp)
315 (english-upper Footnote-english-upper ,footnote-english-upper-regexp)
316 (roman-lower Footnote-roman-lower ,footnote-roman-lower-regexp)
317 (roman-upper Footnote-roman-upper ,footnote-roman-upper-regexp))
318 "Styles of footnote tags available.
319 By default only boring Arabic numbers, latin superscript numbers, English
320 letters and Roman Numerals are available.
321 See footnote-han.el, footnote-greek.el and footnote-hebrew.el for more
324 ;;; Style utilities & functions
326 (defun* Footnote-start-tag (&optional (style footnote-style))
327 (or (fourth (assq style footnote-style-alist))
330 (defun* Footnote-end-tag (&optional (style footnote-style))
331 (or (fifth (assq style footnote-style-alist))
334 (defun Footnote-style-p (style)
335 "Return non-nil if style is a valid style known to footnote-mode."
336 (assq style footnote-style-alist))
338 (defun Footnote-index-to-string (index)
339 "Convert a binary index into a string to display as a footnote.
340 Conversion is done based upon the current selected style."
341 (let ((alist (if (Footnote-style-p footnote-style)
342 (assq footnote-style footnote-style-alist)
343 (first footnote-style-alist))))
344 (funcall (second alist) index)))
346 (defun Footnote-current-regexp ()
347 "Return the regexp of the index of the current style."
348 (concat (third (or (assq footnote-style footnote-style-alist)
349 (first footnote-style-alist))) "+"))
351 (defun* Footnote-refresh-footnotes (&optional (old-style
353 footnote-style-alist)))
354 "Redraw all footnotes.
355 The old footnotes are assumed to be of OLD-STYLE and the style they will
356 be redrawn is the current one. You must call this or arrange to have this
357 called after changing footnote styles."
358 (let ((old-ind-regexp (third old-style))
359 (old-start-tag (Footnote-start-tag (first old-style)))
360 (old-end-tag (Footnote-end-tag (first old-style)))
361 (new-start-tag (Footnote-start-tag))
362 (new-end-tag (Footnote-end-tag)))
364 ;; Take care of the pointers first
366 for footnote-entry in footnote-pointer-marker-alist
367 do (loop for location in (cdr footnote-entry)
369 (setf (point) location)
370 (search-backward-regexp (concat (regexp-quote old-start-tag)
373 (when (looking-at (concat
374 (regexp-quote old-start-tag)
375 "\\(" old-ind-regexp "+\\)"
376 (regexp-quote old-end-tag)))
377 (replace-match (concat
379 (Footnote-index-to-string i)
383 ;; Now take care of the text section
385 for footnote-entry in footnote-text-marker-alist
386 do (setf (point) (cdr footnote-entry))
387 (when (looking-at (concat
388 (regexp-quote old-start-tag)
389 "\\(" old-ind-regexp "+\\)"
390 (regexp-quote old-end-tag)))
391 (replace-match (concat
393 (Footnote-index-to-string i)
397 (defun Footnote-assoc-index (key alist)
398 "Give index of key in alist."
399 (position key alist :key #'first))
401 (defun Footnote-switch-style (to)
402 "Switch to another footnote style TO, refreshing the footnotes."
403 (let ((old (assq footnote-style footnote-style-alist))
404 (to (if (and (eq footnote-style 'numeric)
405 (eq to 'numeric-latin)
406 footnote-style-is-really-numeric-latin)
407 (or (car (first (rest (member* 'numeric-latin
408 footnote-style-alist :key #'car))))
409 (car (first footnote-style-alist)))
411 (cond ((and (eq to 'numeric-latin)
412 (>= (length footnote-text-marker-alist) 4))
413 (message "You won't see latin superscripts until you have less than four footnotes.")
414 (Footnote-set-style 'numeric)
415 (setq footnote-style-is-really-numeric-latin t))
416 (t (Footnote-set-style to)))
417 (Footnote-refresh-footnotes old)))
419 (defun* Footnote-cycle-style (&optional (arg 1))
420 "Select ARG'th (from the current one) defined footnote style."
422 (Footnote-switch-style
423 (first (nth (mod (+ (Footnote-assoc-index footnote-style
424 footnote-style-alist)
426 (length footnote-style-alist))
427 footnote-style-alist))))
429 (defun Footnote-set-style (&optional style)
430 "Select a specific style."
432 (list (intern (completing-read
434 obarray #'Footnote-style-p 'require-match))))
435 (setq footnote-style-is-really-numeric-latin nil)
436 (setq footnote-style style))
438 ;; Internal functions
439 (defun Footnote-insert-numbered-footnote (arg &optional mousable)
440 "Insert numbered footnote at (point)."
441 (let* ((start (point))
443 (insert-before-markers (concat (Footnote-start-tag)
444 (Footnote-index-to-string arg)
448 (add-text-properties start end
449 (list 'footnote-number arg 'start-open t))
451 (add-text-properties start end
452 (list footnote-mouse-highlight t)))))
454 (defun Footnote-renumber (from to pointer-alist text-alist)
455 "Renumber a single footnote."
456 (let* ((posn-list (cdr pointer-alist)))
457 (setcar pointer-alist to)
458 (setcar text-alist to)
460 (goto-char (car posn-list))
461 (search-backward (Footnote-start-tag) nil t)
462 (when (looking-at (format "%s%s%s"
463 (regexp-quote (Footnote-start-tag))
464 (Footnote-current-regexp)
465 (regexp-quote (Footnote-end-tag))))
466 (add-text-properties (match-beginning 0) (match-end 0)
467 (list 'footnote-number to))
468 (replace-match (format "%s%s%s"
470 (Footnote-index-to-string to)
471 (Footnote-end-tag))))
472 (setq posn-list (cdr posn-list)))
473 (goto-char (cdr text-alist))
474 (when (looking-at (format "%s%s%s"
475 (regexp-quote (Footnote-start-tag))
476 (Footnote-current-regexp)
477 (regexp-quote (Footnote-end-tag))))
478 (add-text-properties (match-beginning 0) (match-end 0)
479 (list 'footnote-number to))
480 (replace-match (format "%s%s%s"
482 (Footnote-index-to-string to)
483 (Footnote-end-tag)) nil t))))
486 (defun Footnote-narrow-to-footnotes ()
487 "Restrict text in buffer to show only text of footnotes."
488 (interactive) ; testing
489 (goto-char (point-max))
490 (when (re-search-backward footnote-signature-separator nil t)
492 (when (re-search-backward (concat "^" footnote-section-tag-regexp) nil t)
493 (narrow-to-region (point) end)))))
495 (defun Footnote-goto-char-point-max ()
496 "Move to end of buffer or prior to start of .signature."
497 (goto-char (point-max))
498 (or (re-search-backward footnote-signature-separator nil t)
501 (defun Footnote-insert-text-marker (arg locn)
502 "Insert a marker pointing to footnote arg, at buffer location locn."
503 (let ((marker (make-marker)))
504 (unless (assq arg footnote-text-marker-alist)
505 (set-marker marker locn)
506 (setq footnote-text-marker-alist
507 (acons arg marker footnote-text-marker-alist))
508 (setq footnote-text-marker-alist
509 (Footnote-sort footnote-text-marker-alist)))))
511 (defun Footnote-insert-pointer-marker (arg locn)
512 "Insert a marker pointing to footnote arg, at buffer location locn."
513 (let ((marker (make-marker))
515 (set-marker marker locn)
516 (if (setq alist (assq arg footnote-pointer-marker-alist))
518 (cons marker (cdr alist)))
519 (setq footnote-pointer-marker-alist
520 (acons arg (list marker) footnote-pointer-marker-alist))
521 (setq footnote-pointer-marker-alist
522 (Footnote-sort footnote-pointer-marker-alist)))))
524 (defun Footnote-insert-footnote (arg)
525 "Insert a footnote numbered arg, at (point)."
527 (Footnote-insert-pointer-marker arg (point))
528 (Footnote-insert-numbered-footnote arg t)
529 (Footnote-goto-char-point-max)
530 (let (insertion-before-signature)
531 (if (re-search-backward (concat "^" footnote-section-tag-regexp) nil t)
533 (when footnote-narrow-to-footnotes-when-editing
534 (Footnote-narrow-to-footnotes))
535 (Footnote-goto-footnote (1- arg)) ; evil, FIXME (less evil now)
537 (when (re-search-forward (if footnote-spaced-footnotes
540 (regexp-quote (Footnote-start-tag))
541 (Footnote-current-regexp)
542 (regexp-quote (Footnote-end-tag))))
546 (progn (Footnote-goto-char-point-max)
547 (when (and (setq insertion-before-signature
548 (looking-at footnote-signature-separator))
549 (not footnote-spaced-footnotes)
550 footnote-always-blank-line-before-signature)
552 (when (looking-at "^$")
554 ;; Need to create footnote section.
555 (setq insertion-before-signature (looking-at footnote-signature-separator))
556 (unless (looking-at "^$")
560 (insert footnote-section-tag "\n"))
561 (let ((old-point (point)))
562 (Footnote-insert-numbered-footnote arg nil)
563 (Footnote-insert-text-marker arg old-point))
564 insertion-before-signature))
566 (defun Footnote-sort (list)
567 (sort list (lambda (e1 e2)
568 (< (car e1) (car e2)))))
570 (defun Footnote-text-under-cursor ()
571 "Return the number of footnote if in footnote text.
572 Nil is returned if the cursor is not positioned over the text of
574 (when (and (let ((old-point (point)))
577 (Footnote-narrow-to-footnotes)
578 (and (>= old-point (point-min))
579 (<= old-point (point-max))))))
580 (>= (point) (cdar footnote-text-marker-alist)))
583 (while (and (setq alist-txt (nth i footnote-text-marker-alist))
585 (when (< (point) (cdr alist-txt))
586 (setq rc (car (nth (1- i) footnote-text-marker-alist))))
590 (setq rc (car (nth (1- i) footnote-text-marker-alist))))
593 (defun Footnote-under-cursor ()
594 "Return the number of the footnote underneath the cursor.
595 Nil is returned if the cursor is not over a footnote."
596 (or (get-text-property (point) 'footnote-number)
597 (Footnote-text-under-cursor)))
601 (defun Footnote-make-hole ()
604 (notes (length footnote-pointer-marker-alist))
605 alist-ptr alist-txt rc)
607 (setq alist-ptr (nth i footnote-pointer-marker-alist))
608 (setq alist-txt (nth i footnote-text-marker-alist))
609 (when (< (point) (- (cadr alist-ptr) 3))
611 (setq rc (car alist-ptr)))
613 (message "Renumbering from %s to %s"
614 (Footnote-index-to-string (car alist-ptr))
615 (Footnote-index-to-string
616 (1+ (car alist-ptr))))
617 (Footnote-renumber (car alist-ptr)
625 (defun Footnote-add-footnote (&optional arg)
626 "Add a numbered footnote.
627 The number the footnote receives is dependent upon the relative location
628 of any other previously existing footnotes.
629 If the variable `footnote-narrow-to-footnotes-when-editing' is set,
630 the buffer is narrowed to the footnote body. The restriction is removed
631 by using `Footnote-back-to-message'."
633 (when (and (eq footnote-style 'numeric-latin)
634 (= 3 (length footnote-text-marker-alist)))
635 (Footnote-switch-style 'numeric)
636 (setq footnote-style-is-really-numeric-latin t))
637 (let ((num (if footnote-text-marker-alist
638 (if (< (point) (cadar (last footnote-pointer-marker-alist)))
640 (1+ (caar (last footnote-text-marker-alist))))
642 (message "Adding footnote %d" num)
643 (let ((insertion-before-signature (Footnote-insert-footnote num)))
644 (insert-before-markers (make-string footnote-body-tag-spacing ? ))
645 (let ((opoint (point)))
647 (insert-before-markers
648 (if (or footnote-spaced-footnotes
649 (and footnote-always-blank-line-before-signature
650 insertion-before-signature))
653 (when footnote-narrow-to-footnotes-when-editing
654 (Footnote-narrow-to-footnotes)))
655 ;; Emacs/XEmacs bug? save-excursion doesn't restore point when using
656 ;; insert-before-markers.
657 (goto-char opoint)))))
659 (defun Footnote-delete-footnote (&optional arg)
660 "Delete a numbered footnote.
661 With no parameter, delete the footnote under (point). With arg specified,
662 delete the footnote with that number."
664 (let ((arg (or arg (Footnote-under-cursor))))
666 (or (not footnote-prompt-before-deletion)
667 (y-or-n-p (format "Really delete footnote %d?" arg))))
668 (let* ((alist-ptr (assq arg footnote-pointer-marker-alist))
669 (alist-at-entry (member* arg footnote-text-marker-alist :key #'car))
670 (alist-txt (first alist-at-entry)))
671 (unless (and alist-ptr alist-txt)
672 (error "Can't delete footnote %d" arg))
673 (loop for location in (cdr alist-ptr)
675 (setf (point) location)
676 (kill-region (search-backward-regexp
677 (concat (regexp-quote (Footnote-start-tag))
678 (Footnote-current-regexp))
682 (if (rest alist-at-entry)
683 (Footnote-goto-footnote (1+ arg))
684 (Footnote-goto-char-point-max)
685 (unless (or (looking-at "^$")
686 footnote-spaced-footnotes
687 footnote-always-blank-line-before-signature))
688 (when (and (not (looking-at "^$"))
689 (not footnote-spaced-footnotes)
690 footnote-always-blank-line-before-signature)
692 (kill-region (cdr alist-txt)
694 (setq footnote-pointer-marker-alist
695 (delq alist-ptr footnote-pointer-marker-alist))
696 (setq footnote-text-marker-alist
697 (delq alist-txt footnote-text-marker-alist))
698 (Footnote-renumber-footnotes)
699 (when (and footnote-style-is-really-numeric-latin
700 (eq footnote-style 'numeric)
701 (< (length footnote-text-marker-alist) 4))
702 (Footnote-switch-style 'numeric-latin))
703 (when (and (null footnote-text-marker-alist)
704 (null footnote-pointer-marker-alist))
706 (let ((end (Footnote-goto-char-point-max))
707 (start (1- (re-search-backward
708 (concat "^" footnote-section-tag-regexp)
711 (let ((end (- end (cond ((looking-at "\n")
715 (kill-region start (if (< end (point-max))
717 (point-max)))))))))))
719 (defun Footnote-renumber-footnotes (&optional arg)
720 "Renumber footnotes, starting from 1."
724 (notes (length footnote-pointer-marker-alist))
727 (setq alist-ptr (nth i footnote-pointer-marker-alist))
728 (setq alist-txt (nth i footnote-text-marker-alist))
729 (unless (eq (1+ i) (car alist-ptr))
730 (Footnote-renumber (car alist-ptr) (1+ i) alist-ptr alist-txt))
733 (defun Footnote-goto-footnote (&optional arg)
734 "Jump to the text of a footnote.
735 With no parameter, jump to the text of the footnote under (point). With arg
736 specified, jump to the text of that footnote."
738 (setq zmacs-region-stays t)
741 (setq footnote (assq arg footnote-text-marker-alist))
742 (when (setq arg (Footnote-under-cursor))
743 (setq footnote (assq arg footnote-text-marker-alist))))
745 (goto-char (cdr footnote))
748 (goto-char (point-max))
749 (re-search-backward (concat "^" footnote-section-tag-regexp))
751 (error "I don't see a footnote here.")))))
753 (defun Footnote-back-to-message (&optional arg)
754 "Move cursor back to footnote referent.
755 If the cursor is not over the text of a footnote, point is not changed.
756 If the buffer was narrowed due to `footnote-narrow-to-footnotes-when-editing'
757 being set it is automatically widened."
759 (setq zmacs-region-stays t)
760 (let ((note (Footnote-text-under-cursor)))
762 (when footnote-narrow-to-footnotes-when-editing
764 (goto-char (cadr (assq note footnote-pointer-marker-alist))))))
767 (defvar footnote-mode-map nil
768 "Keymap used for footnote minor mode.")
772 (unless footnote-mode-map
773 (setq footnote-mode-map (make-sparse-keymap))
774 (define-key footnote-mode-map "a" 'Footnote-add-footnote)
775 (define-key footnote-mode-map "b" 'Footnote-back-to-message)
776 (define-key footnote-mode-map "c" 'Footnote-cycle-style)
777 (define-key footnote-mode-map "d" 'Footnote-delete-footnote)
778 (define-key footnote-mode-map "g" 'Footnote-goto-footnote)
779 (define-key footnote-mode-map "r" 'Footnote-renumber-footnotes)
780 (define-key footnote-mode-map "s" 'Footnote-set-style))
783 (defvar footnote-minor-mode-map nil
784 "Keymap used for binding footnote minor mode.")
787 (unless footnote-minor-mode-map
788 (define-key global-map footnote-prefix footnote-mode-map))
791 (if (progn (condition-case () (require 'easymenu) (error nil))
792 (fboundp 'easy-menu-add-item))
793 (easy-menu-add-item nil '("Cmds")
795 ["Add Footnote" Footnote-add-footnote t]
796 ["Delete Footnote" Footnote-delete-footnote t]
797 ["Goto Footnote" Footnote-goto-footnote t]
798 ["Back to Message" Footnote-back-to-message t]
799 ["Renumber Footnotes" Footnote-renumber-footnotes t]
801 ["Set Footnote Style" Footnote-set-style t]
802 ["Cycle Footnote Style" Footnote-cycle-style t]
807 (defun footnote-mode (&optional arg)
808 "Toggle footnote minor mode.
813 \\[Footnote-set-style] Footnote-set-style
814 \\[Footnote-renumber-footnotes] Footnote-renumber-footnotes
815 \\[Footnote-goto-footnote] Footnote-goto-footnote
816 \\[Footnote-delete-footnote] Footnote-delete-footnote
817 \\[Footnote-cycle-style] Footnote-cycle-style
818 \\[Footnote-back-to-message] Footnote-back-to-message
819 \\[Footnote-add-footnote] Footnote-add-footnote
823 ;; (filladapt-mode t)
824 (setq zmacs-region-stays t)
826 (if (null arg) (not footnote-mode)
827 (> (prefix-numeric-value arg) 0)))
829 ;; (Footnote-setup-keybindings)
830 (make-local-variable 'footnote-style)
831 (if (fboundp 'force-mode-line-update)
832 (force-mode-line-update)
833 (set-buffer-modified-p (buffer-modified-p)))
835 (when (boundp 'filladapt-token-table)
836 ;; add tokens to filladapt to match footnotes
837 ;; 1] xxxxxxxxxxx x x x or [1] x x x x x x x
838 ;; xxx x xx xxx xxxx x x x xxxxxxxxxx
839 (let ((bullet-regexp (concat (regexp-quote (Footnote-start-tag))
841 (regexp-quote (Footnote-end-tag))
843 (unless (assoc bullet-regexp filladapt-token-table)
844 (setq filladapt-token-table
845 (append filladapt-token-table
846 (list (list bullet-regexp 'bullet)))))))
848 (run-hooks 'footnote-mode-hook)))
850 ;; install on minor-mode-alist
852 (when (fboundp 'add-minor-mode)
854 (add-minor-mode 'footnote-mode
855 footnote-mode-line-string
856 footnote-minor-mode-map))
858 ;; Emacs -- don't autoload
859 (unless (assq 'footnote-mode minor-mode-alist)
860 (setq minor-mode-alist
861 (cons '(footnote-mode footnote-mode-line-string)
866 ;;; footnote.el ends here