Commit | Line | Data |
---|---|---|
e8af40ee | 1 | ;;; footnote.el --- footnote support for message mode -*- coding: iso-latin-1;-*- |
55492d86 | 2 | |
f2e3589a | 3 | ;; Copyright (C) 1997, 2000, 2001, 2002, 2003, 2004, |
5df4f04c | 4 | ;; 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. |
55492d86 DL |
5 | |
6 | ;; Author: Steven L Baur <steve@xemacs.org> | |
7 | ;; Keywords: mail, news | |
8 | ;; Version: 0.19 | |
9 | ||
409f8a3f | 10 | ;; This file is part of GNU Emacs. |
55492d86 | 11 | |
b1fc2b50 GM |
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. | |
55492d86 | 16 | |
b1fc2b50 GM |
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. | |
55492d86 DL |
21 | |
22 | ;; You should have received a copy of the GNU General Public License | |
b1fc2b50 | 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
55492d86 | 24 | |
55492d86 DL |
25 | ;;; Commentary: |
26 | ||
27 | ;; This file provides footnote[1] support for message-mode in emacsen. | |
28 | ;; footnote-mode is implemented as a minor mode. | |
29 | ||
30 | ;; [1] Footnotes look something like this. Along with some decorative | |
31 | ;; stuff. | |
32 | ||
33 | ;; TODO: | |
34 | ;; Reasonable Undo support. | |
35 | ;; more language styles. | |
36 | ||
55492d86 DL |
37 | ;;; Code: |
38 | ||
409f8a3f DL |
39 | (eval-when-compile |
40 | (require 'cl) | |
41 | (defvar filladapt-token-table)) | |
42 | ||
55492d86 DL |
43 | (defgroup footnote nil |
44 | "Support for footnotes in mail and news messages." | |
5404d9b0 | 45 | :version "21.1" |
55492d86 DL |
46 | :group 'message) |
47 | ||
55492d86 | 48 | (defcustom footnote-mode-line-string " FN" |
6a8b4632 | 49 | "String to display in modes section of the mode-line." |
55492d86 DL |
50 | :group 'footnote) |
51 | ||
52 | (defcustom footnote-mode-hook nil | |
6a8b4632 | 53 | "Hook functions run when footnote-mode is activated." |
55492d86 DL |
54 | :type 'hook |
55 | :group 'footnote) | |
56 | ||
57 | (defcustom footnote-narrow-to-footnotes-when-editing nil | |
6a8b4632 | 58 | "If non-nil, narrow to footnote text body while editing a footnote." |
55492d86 DL |
59 | :type 'boolean |
60 | :group 'footnote) | |
61 | ||
62 | (defcustom footnote-prompt-before-deletion t | |
6a8b4632 | 63 | "If non-nil, prompt before deleting a footnote. |
55492d86 DL |
64 | There is currently no way to undo deletions." |
65 | :type 'boolean | |
66 | :group 'footnote) | |
67 | ||
68 | (defcustom footnote-spaced-footnotes t | |
6a8b4632 MR |
69 | "If non-nil, insert an empty line between footnotes. |
70 | Customizing this variable has no effect on buffers already | |
71 | displaying footnotes." | |
55492d86 DL |
72 | :type 'boolean |
73 | :group 'footnote) | |
74 | ||
6a8b4632 MR |
75 | (defcustom footnote-use-message-mode t ; Nowhere used. |
76 | "If non-nil, assume Footnoting will be done in `message-mode'." | |
55492d86 DL |
77 | :type 'boolean |
78 | :group 'footnote) | |
79 | ||
80 | (defcustom footnote-body-tag-spacing 2 | |
6a8b4632 MR |
81 | "Number of spaces separating a footnote body tag and its text. |
82 | Customizing this variable has no effect on buffers already | |
83 | displaying footnotes." | |
55492d86 DL |
84 | :type 'integer |
85 | :group 'footnote) | |
86 | ||
734db384 SM |
87 | (defcustom footnote-prefix [(control ?c) ?!] |
88 | "Prefix key to use for Footnote command in Footnote minor mode. | |
89 | The value of this variable is checked as part of loading Footnote mode. | |
90 | After that, changing the prefix key requires manipulating keymaps." | |
91 | ;; FIXME: the type should be a key-sequence, but it seems Custom | |
92 | ;; doesn't support that yet. | |
93 | ;; :type 'string | |
94 | ) | |
55492d86 DL |
95 | |
96 | ;;; Interface variables that probably shouldn't be changed | |
97 | ||
c4dc7971 | 98 | (defcustom footnote-section-tag "Footnotes: " |
6a8b4632 MR |
99 | "Tag inserted at beginning of footnote section. |
100 | If you set this to the empty string, no tag is inserted and the | |
101 | value of `footnote-section-tag-regexp' is ignored. Customizing | |
102 | this variable has no effect on buffers already displaying | |
103 | footnotes." | |
c4dc7971 RS |
104 | :type 'string |
105 | :group 'footnote) | |
55492d86 | 106 | |
5404d9b0 | 107 | (defcustom footnote-section-tag-regexp "Footnotes\\(\\[.\\]\\)?: " |
6a8b4632 MR |
108 | "Regexp which indicates the start of a footnote section. |
109 | This variable is disregarded when `footnote-section-tag' is the | |
110 | empty string. Customizing this variable has no effect on buffers | |
111 | already displaying footnotes." | |
5404d9b0 DL |
112 | :type 'regexp |
113 | :group 'footnote) | |
55492d86 DL |
114 | |
115 | ;; The following three should be consumed by footnote styles. | |
5404d9b0 | 116 | (defcustom footnote-start-tag "[" |
6a8b4632 MR |
117 | "String used to denote start of numbered footnote. |
118 | Should not be set to the empty string. Customizing this variable | |
119 | has no effect on buffers already displaying footnotes." | |
5404d9b0 DL |
120 | :type 'string |
121 | :group 'footnote) | |
55492d86 | 122 | |
5404d9b0 | 123 | (defcustom footnote-end-tag "]" |
6a8b4632 MR |
124 | "String used to denote end of numbered footnote. |
125 | Should not be set to the empty string. Customizing this variable | |
126 | has no effect on buffers already displaying footnotes." | |
5404d9b0 DL |
127 | :type 'string |
128 | :group 'footnote) | |
55492d86 DL |
129 | |
130 | (defvar footnote-signature-separator (if (boundp 'message-signature-separator) | |
131 | message-signature-separator | |
132 | "^-- $") | |
133 | "*String used to recognize .signatures.") | |
134 | ||
135 | ;;; Private variables | |
136 | ||
137 | (defvar footnote-style-number nil | |
138 | "Footnote style represented as an index into footnote-style-alist.") | |
139 | (make-variable-buffer-local 'footnote-style-number) | |
140 | ||
141 | (defvar footnote-text-marker-alist nil | |
142 | "List of markers pointing to text of footnotes in message buffer.") | |
143 | (make-variable-buffer-local 'footnote-text-marker-alist) | |
144 | ||
145 | (defvar footnote-pointer-marker-alist nil | |
146 | "List of markers pointing to footnote pointers in message buffer.") | |
147 | (make-variable-buffer-local 'footnote-pointer-marker-alist) | |
148 | ||
149 | (defvar footnote-mouse-highlight 'highlight | |
150 | "Text property name to enable mouse over highlight.") | |
151 | ||
55492d86 DL |
152 | ;;; Default styles |
153 | ;;; NUMERIC | |
62b1cb94 | 154 | (defconst footnote-numeric-regexp "[0-9]+" |
55492d86 DL |
155 | "Regexp for digits.") |
156 | ||
157 | (defun Footnote-numeric (n) | |
158 | "Numeric footnote style. | |
159 | Use Arabic numerals for footnoting." | |
160 | (int-to-string n)) | |
161 | ||
162 | ;;; ENGLISH UPPER | |
163 | (defconst footnote-english-upper "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
164 | "Upper case English alphabet.") | |
165 | ||
62b1cb94 | 166 | (defconst footnote-english-upper-regexp "[A-Z]+" |
55492d86 DL |
167 | "Regexp for upper case English alphabet.") |
168 | ||
169 | (defun Footnote-english-upper (n) | |
170 | "Upper case English footnoting. | |
171 | Wrapping around the alphabet implies successive repetitions of letters." | |
172 | (let* ((ltr (mod (1- n) (length footnote-english-upper))) | |
173 | (rep (/ (1- n) (length footnote-english-upper))) | |
174 | (chr (char-to-string (aref footnote-english-upper ltr))) | |
175 | rc) | |
176 | (while (>= rep 0) | |
177 | (setq rc (concat rc chr)) | |
178 | (setq rep (1- rep))) | |
179 | rc)) | |
a1506d29 | 180 | |
55492d86 DL |
181 | ;;; ENGLISH LOWER |
182 | (defconst footnote-english-lower "abcdefghijklmnopqrstuvwxyz" | |
183 | "Lower case English alphabet.") | |
184 | ||
62b1cb94 | 185 | (defconst footnote-english-lower-regexp "[a-z]+" |
55492d86 DL |
186 | "Regexp of lower case English alphabet.") |
187 | ||
188 | (defun Footnote-english-lower (n) | |
189 | "Lower case English footnoting. | |
190 | Wrapping around the alphabet implies successive repetitions of letters." | |
191 | (let* ((ltr (mod (1- n) (length footnote-english-lower))) | |
192 | (rep (/ (1- n) (length footnote-english-lower))) | |
193 | (chr (char-to-string (aref footnote-english-lower ltr))) | |
194 | rc) | |
195 | (while (>= rep 0) | |
196 | (setq rc (concat rc chr)) | |
197 | (setq rep (1- rep))) | |
198 | rc)) | |
199 | ||
200 | ;;; ROMAN LOWER | |
201 | (defconst footnote-roman-lower-list | |
202 | '((1 . "i") (5 . "v") (10 . "x") | |
203 | (50 . "l") (100 . "c") (500 . "d") (1000 . "m")) | |
204 | "List of roman numerals with their values.") | |
205 | ||
62b1cb94 | 206 | (defconst footnote-roman-lower-regexp "[ivxlcdm]+" |
55492d86 DL |
207 | "Regexp of roman numerals.") |
208 | ||
209 | (defun Footnote-roman-lower (n) | |
210 | "Generic Roman number footnoting." | |
211 | (Footnote-roman-common n footnote-roman-lower-list)) | |
212 | ||
213 | ;;; ROMAN UPPER | |
214 | (defconst footnote-roman-upper-list | |
215 | '((1 . "I") (5 . "V") (10 . "X") | |
216 | (50 . "L") (100 . "C") (500 . "D") (1000 . "M")) | |
217 | "List of roman numerals with their values.") | |
218 | ||
62b1cb94 | 219 | (defconst footnote-roman-upper-regexp "[IVXLCDM]+" |
55492d86 DL |
220 | "Regexp of roman numerals. Not complete") |
221 | ||
222 | (defun Footnote-roman-upper (n) | |
223 | "Generic Roman number footnoting." | |
224 | (Footnote-roman-common n footnote-roman-upper-list)) | |
225 | ||
226 | (defun Footnote-roman-common (n footnote-roman-list) | |
227 | "Lower case Roman footnoting." | |
228 | (let* ((our-list footnote-roman-list) | |
229 | (rom-lngth (length our-list)) | |
230 | (rom-high 0) | |
231 | (rom-low 0) | |
232 | (rom-div -1) | |
233 | (count-high 0) | |
234 | (count-low 0)) | |
235 | ;; find surrounding numbers | |
236 | (while (and (<= count-high (1- rom-lngth)) | |
237 | (>= n (car (nth count-high our-list)))) | |
238 | ;; (message "Checking %d" (car (nth count-high our-list))) | |
239 | (setq count-high (1+ count-high))) | |
240 | (setq rom-high count-high) | |
241 | (setq rom-low (1- count-high)) | |
242 | ;; find the appropriate divisor (if it exists) | |
243 | (while (and (= rom-div -1) | |
244 | (< count-low rom-high)) | |
245 | (when (or (> n (- (car (nth rom-high our-list)) | |
246 | (/ (car (nth count-low our-list)) | |
247 | 2))) | |
248 | (= n (- (car (nth rom-high our-list)) | |
249 | (car (nth count-low our-list))))) | |
250 | (setq rom-div count-low)) | |
251 | ;; (message "Checking %d and %d in div loop" rom-high count-low) | |
252 | (setq count-low (1+ count-low))) | |
253 | ;;(message "We now have high: %d, low: %d, div: %d, n: %d" | |
254 | ;; rom-high rom-low (if rom-div rom-div -1) n) | |
255 | (let ((rom-low-pair (nth rom-low our-list)) | |
256 | (rom-high-pair (nth rom-high our-list)) | |
257 | (rom-div-pair (if (not (= rom-div -1)) (nth rom-div our-list) nil))) | |
258 | ;; (message "pairs are: rom-low: %S, rom-high: %S, rom-div: %S" | |
259 | ;; rom-low-pair rom-high-pair rom-div-pair) | |
260 | (cond | |
261 | ((< n 0) (error "Footnote-roman-common called with n < 0")) | |
262 | ((= n 0) "") | |
263 | ((= n (car rom-low-pair)) (cdr rom-low-pair)) | |
264 | ((= n (car rom-high-pair)) (cdr rom-high-pair)) | |
265 | ((= (car rom-low-pair) (car rom-high-pair)) | |
266 | (concat (cdr rom-low-pair) | |
267 | (Footnote-roman-common | |
268 | (- n (car rom-low-pair)) | |
269 | footnote-roman-list))) | |
270 | ((>= rom-div 0) (concat (cdr rom-div-pair) (cdr rom-high-pair) | |
271 | (Footnote-roman-common | |
272 | (- n (- (car rom-high-pair) | |
273 | (car rom-div-pair))) | |
274 | footnote-roman-list))) | |
275 | (t (concat (cdr rom-low-pair) | |
276 | (Footnote-roman-common | |
277 | (- n (car rom-low-pair)) | |
278 | footnote-roman-list))))))) | |
279 | ||
5404d9b0 DL |
280 | ;; Latin-1 |
281 | ||
dedecfd6 MR |
282 |