Update FSF's address.
[bpt/emacs.git] / lisp / international / iso-acc.el
CommitLineData
bf4de26a 1;;; iso-acc.el -- minor mode providing electric accent keys
b578f267
EN
2
3;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
bf4de26a
RS
4
5;; Author: Johan Vromans <jv@mh.nl>
a2b2b91b 6;; Version: 1.7 (modified)
7ab500f0
RS
7;; Maintainer: FSF
8;; Keywords: i18n
bf4de26a
RS
9
10;; This file is part of GNU Emacs.
11
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 2, or (at your option)
15;; any later version.
16
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.
21
22;; You should have received a copy of the GNU General Public License
b578f267
EN
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
bf4de26a
RS
26
27;;; Commentary:
28
a4332c3f
RS
29;; Function `iso-accents-mode' activates a minor mode in which
30;; typewriter "dead keys" are emulated. The purpose of this emulation
31;; is to provide a simple means for inserting accented characters
32;; according to the ISO-8859-1 character set.
bf4de26a 33;;
a4332c3f 34;; In `iso-accents-mode', pseudo accent characters are used to
298613df 35;; introduce accented keys. The pseudo-accent characters are:
bf4de26a
RS
36;;
37;; ' (minute) -> grave accent
38;; ` (backtick) -> acute accent
39;; " (second) -> diaeresis
7ab500f0
RS
40;; ^ (caret) -> circumflex
41;; ~ (tilde) -> tilde over the character
42;; / (slash) -> slash through the character.
a2b2b91b 43;; Also: /A is A-with-ring and /E is AE ligature.
bf4de26a
RS
44;;
45;; The action taken depends on the key that follows the pseudo accent.
46;; In general:
47;;
48;; pseudo-accent + appropriate letter -> accented letter
49;; pseudo-accent + space -> pseudo-accent
50;; pseudo-accent + pseudo-accent -> accent (if available)
51;; pseudo-accent + other -> pseudo-accent + other
52;;
53;; If the pseudo-accent is followed by anything else than a
54;; self-insert-command, the dead-key code is terminated, the
55;; pseudo-accent inserted 'as is' and the bell is rung to signal this.
56;;
8669cecf
RS
57;; Function `iso-accents-mode' can be used to enable the iso accents
58;; minor mode, or disable it.
6da676ad
RS
59
60;; If you want only some of these characters to serve as accents,
72c2a4c1
KH
61;; add a language to iso-languages which specifies the accent characters
62;; that you want, then select the language with iso-accents-customize.
bf4de26a
RS
63\f
64;;; Code:
65
66(provide 'iso-acc)
67
700be2bd
RS
68(defvar iso-languages
69 '(("portuguese"
70 (?' ?` ?^ ?\" ?~)
71 (((?' ?A) ?\301) ((?' ?E) ?\311) ((?' ?I) ?\315) ((?' ?O) ?\323)
72 ((?' ?U) ?\332) ((?' ?C) ?\307) ((?' ?a) ?\341) ((?' ?e) ?\351)
73 ((?' ?i) ?\355) ((?' ?o) ?\363) ((?' ?u) ?\372) ((?' ?c) ?\347)
74 ((?' ? ) ?') ((?` ?A) ?\300) ((?` ?a) ?\340) ((?` ? ) ?`)
75 ((?^ ?A) ?\302) ((?^ ?E) ?\312) ((?^ ?O) ?\324) ((?^ ?a) ?\342)
76 ((?^ ?e) ?\352) ((?^ ?o) ?\364) ((?^ ? ) ?^) ((?\" ?U) ?\334)
77 ((?\" ?u) ?\374) ((?\" ? ) ?\") ((?\~ ?A) ?\303) ((?\~ ?O) ?\325)
78 ((?\~ ?a) ?\343) ((?\~ ?o) ?\365) ((?\~ ?\ ) ?\~)))
8a452828
RS
79 ("irish"
80 (?')
81 (((?' ?A) ?\301) ((?' ?E) ?\311) ((?' ?I) ?\315) ((?' ?O) ?\323)
82 ((?' ?U) ?\332) ((?' ?a) ?\341) ((?' ?e) ?\351)
83 ((?' ?i) ?\355) ((?' ?o) ?\363) ((?' ?u) ?\372)
84 ((?' ? ) ?') ))
700be2bd
RS
85 ("french"
86 (?' ?` ?^ ?\" ?~)
87 (((?' ?A) ?\301) ((?' ?E) ?\311) ((?' ?I) ?\315) ((?' ?O) ?\323)
88 ((?' ?U) ?\332) ((?' ?C) ?\307) ((?' ?a) ?\341) ((?' ?e) ?\351)
89 ((?' ?i) ?\355) ((?' ?o) ?\363) ((?' ?u) ?\372) ((?' ?c) ?\347)
90 ((?' ? ) ?') ((?` ?A) ?\300) ((?` ?E) ?\310) ((?` ?a) ?\340)
91 ((?` ?e) ?\350) ((?` ? ) ?`) ((?^ ?A) ?\302) ((?^ ?E) ?\312)
92 ((?^ ?I) ?\316) ((?^ ?O) ?\324) ((?^ ?U) ?\333) ((?^ ?a) ?\342)
93 ((?^ ?e) ?\352) ((?^ ?i) ?\356) ((?^ ?o) ?\364) ((?^ ?u) ?\373)
94 ((?^ ? ) ?^) ((?\" ?U) ?\334) ((?\" ?u) ?\374) ((?\" ? ) ?\")
95 ((?\~ ?A) ?\303) ((?\~ ?O) ?\325) ((?\~ ?a) ?\343) ((?\~ ?o) ?\365)
96 ((?\~ ?\ ) ?\~)))
97 ("default"
98 (?' ?` ?^ ?\" ?~ ?/)
99 (((?' ?A) ?\301) ((?' ?E) ?\311) ((?' ?I) ?\315) ((?' ?O) ?\323)
100 ((?' ?U) ?\332) ((?' ?Y) ?\335) ((?' ?a) ?\341) ((?' ?e) ?\351)
101 ((?' ?i) ?\355) ((?' ?o) ?\363) ((?' ?u) ?\372) ((?' ?y) ?\375)
102 ((?' ?') ?\264) ((?' ? ) ?') ((?` ?A) ?\300) ((?` ?E) ?\310)
103 ((?` ?I) ?\314) ((?` ?O) ?\322) ((?` ?U) ?\331) ((?` ?a) ?\340)
104 ((?` ?e) ?\350) ((?` ?i) ?\354) ((?` ?o) ?\362) ((?` ?u) ?\371)
105 ((?` ? ) ?`) ((?` ?`) ?`) ((?^ ?A) ?\302) ((?^ ?E) ?\312)
106 ((?^ ?I) ?\316) ((?^ ?O) ?\324) ((?^ ?U) ?\333) ((?^ ?a) ?\342)
107 ((?^ ?e) ?\352) ((?^ ?i) ?\356) ((?^ ?o) ?\364) ((?^ ?u) ?\373)
108 ((?^ ? ) ?^) ((?^ ?^) ?^) ((?\" ?A) ?\304) ((?\" ?E) ?\313)
109 ((?\" ?I) ?\317) ((?\" ?O) ?\326) ((?\" ?U) ?\334) ((?\" ?a) ?\344)
110 ((?\" ?e) ?\353) ((?\" ?i) ?\357) ((?\" ?o) ?\366) ((?\" ?s) ?\337)
111 ((?\" ?u) ?\374) ((?\" ?y) ?\377) ((?\" ? ) ?\") ((?\" ?\") ?\250)
112 ((?\~ ?A) ?\303) ((?\~ ?C) ?\307) ((?\~ ?D) ?\320) ((?\~ ?N) ?\321)
113 ((?\~ ?O) ?\325) ((?\~ ?T) ?\336) ((?\~ ?a) ?\343) ((?\~ ?c) ?\347)
114 ((?\~ ?d) ?\360) ((?\~ ?n) ?\361) ((?\~ ?o) ?\365) ((?\~ ?t) ?\376)
115 ((?\~ ?>) ?\273) ((?\~ ?<) ?\253) ((?\~ ?\ ) ?\~) ((?\~ ?\~) ?\270)
116 ((?\/ ?A) ?\305) ((?\/ ?E) ?\306) ((?\/ ?O) ?\330) ((?\/ ?a) ?\345)
117 ((?\/ ?e) ?\346) ((?\/ ?o) ?\370) ((?\/ ?\ ) ?\/) ((?\/ ?\/) ?\260))))
118
119 "List of language-specific customizations for the ISO Accents mode.
120
9a71dcfd 121Each element of the list is of the form (LANGUAGE PREFIXES LIST).
700be2bd
RS
122
123LANGUAGE is a string naming the language.
124
9a71dcfd
KH
125PREFIXES is a list of characters that will be used as accent prefixes.
126It is currently not used.
700be2bd
RS
127
128LIST is a list of accent translations. It will be the value of the
72c2a4c1 129`iso-accents-list' variable.")
700be2bd
RS
130
131(defvar iso-language nil
132 "Language for which ISO Accents mode is currently customized.
133Change it with the `iso-accents-customize' function.")
134
135(defvar iso-accents-list nil
136 "Association list for ISO accent combinations, for the chosen language.")
bf4de26a 137
a4332c3f 138(defvar iso-accents-mode nil
884f2b81 139 "*Non-nil enables ISO Accents mode.
9c89d223 140Setting this variable makes it local to the current buffer.
700be2bd 141See the function `iso-accents-mode'.")
a4332c3f 142(make-variable-buffer-local 'iso-accents-mode)
bf4de26a 143
9a71dcfd
KH
144(defvar iso-accents-enable '(?' ?` ?^ ?\" ?~ ?/)
145 "*List of accent keys that become prefixes in ISO Accents mode.
146The default is (?' ?` ?^ ?\" ?~ ?/), which contains all the supported
147accent keys. If you set this variable to a list in which some of those
148characters are missing, the missing ones do not act as accents.
149
150Note that if you specify a language with `iso-accents-customize',
151that can also turn off certain prefixes (whichever ones are not needed in
152the language you choose).")
153
da8d0b9e
RS
154(defun iso-accents-accent-key (prompt)
155 "Modify the following character by adding an accent to it."
156 ;; Pick up the accent character.
9a71dcfd
KH
157 (if (and iso-accents-mode
158 (memq last-input-char iso-accents-enable))
da8d0b9e
RS
159 (iso-accents-compose prompt)
160 (char-to-string last-input-char)))
9c89d223 161
da8d0b9e
RS
162(defun iso-accents-compose-key (prompt)
163 "Modify the following character by adding an accent to it."
164 ;; Pick up the accent character.
165 (let ((combined (iso-accents-compose prompt)))
166 (if unread-command-events
167 (let ((unread unread-command-events))
168 (setq unread-command-events nil)
169 (error "Characters %s and %s cannot be composed"
170 (single-key-description (aref combined 0))
171 (single-key-description (car unread)))))
172 combined))
173
174(defun iso-accents-compose (prompt)
175 (let* ((first-char last-input-char)
176 ;; Wait for the second key and look up the combination.
177 (second-char (if (or prompt
178 (not (eq (key-binding "a")
9ebce7e1
RS
179 'self-insert-command))
180 ;; Called from anything but the command loop.
181 this-command)
da8d0b9e
RS
182 (progn
183 (message "%s%c"
184 (or prompt "Compose with ")
185 first-char)
186 (read-event))
187 (insert first-char)
188 (prog1 (read-event)
189 (delete-region (1- (point)) (point)))))
190 (entry (assoc (list first-char second-char) iso-accents-list)))
191 (if entry
192 ;; Found it: delete the first character and insert the combination.
193 (concat (list (nth 1 entry)))
194 ;; Otherwise, advance and schedule the second key for execution.
195 (setq unread-command-events (list second-char))
196 (vector first-char))))
197
bf4de26a
RS
198;; It is a matter of taste if you want the minor mode indicated
199;; in the mode line...
9c89d223 200;; If so, uncomment the next four lines.
a4332c3f 201;; (or (assq 'iso-accents-mode minor-mode-map-alist)
bf4de26a
RS
202;; (setq minor-mode-alist
203;; (append minor-mode-alist
a4332c3f 204;; '((iso-accents-mode " ISO-Acc")))))
bf4de26a
RS
205
206;;;###autoload
8669cecf 207(defun iso-accents-mode (&optional arg)
884f2b81 208 "Toggle ISO Accents mode, in which accents modify the following letter.
8669cecf
RS
209This permits easy insertion of accented characters according to ISO-8859-1.
210When Iso-accents mode is enabled, accent character keys
7ab500f0 211\(`, ', \", ^, / and ~) do not self-insert; instead, they modify the following
8669cecf
RS
212letter key so that it inserts an ISO accented letter.
213
72c2a4c1
KH
214You can customize ISO Accents mode to a particular language
215with the command `iso-accents-customize'.
6da676ad 216
7ab500f0 217Special combinations: ~c gives a c with cedilla,
298613df
KH
218~d gives an Icelandic eth (d with dash).
219~t gives an Icelandic thorn.
ab4d6ceb
RS
220\"s gives German sharp s.
221/a gives a with ring.
222/e gives an a-e ligature.
5e92ec88 223~< and ~> give guillemots.
947447f4
RS
224~! gives an inverted exclamation mark.
225~? gives an inverted question mark.
7ab500f0 226
6da676ad 227With an argument, a positive argument enables ISO Accents mode,
8669cecf 228and a negative argument disables it."
bf4de26a
RS
229
230 (interactive "P")
231
8669cecf
RS
232 (if (if arg
233 ;; Negative arg means switch it off.
234 (<= (prefix-numeric-value arg) 0)
235 ;; No arg means toggle.
a4332c3f
RS
236 iso-accents-mode)
237 (setq iso-accents-mode nil)
bf4de26a
RS
238
239 ;; Enable electric accents.
a4332c3f 240 (setq iso-accents-mode t)))
bf4de26a 241
700be2bd
RS
242(defun iso-accents-customize (language)
243 "Customize the ISO accents machinery for a particular language.
244It selects the customization based on the specifications in the
245`iso-languages' variable."
246 (interactive (list (completing-read "Language: " iso-languages nil t)))
247 (let ((table (assoc language iso-languages))
9a71dcfd 248 all-accents tail)
700be2bd
RS
249 (if (not table)
250 (error "Unknown language")
251 (setq iso-language language)
700be2bd
RS
252 (setq iso-accents-list (car (cdr (cdr table))))
253 (if key-translation-map
254 (substitute-key-definition
255 'iso-accents-accent-key nil key-translation-map)
256 (setq key-translation-map (make-sparse-keymap)))
9a71dcfd
KH
257 ;; Find all the characters that are used as accent prefixes
258 ;; in this language, and set up translation for them.
259 (setq tail iso-accents-list)
260 (while tail
261 (or (memq (car (car tail)) all-accents)
262 (setq all-accents (cons (car (car tail)) all-accents)))
263 (setq tail (cdr tail)))
264 (setq tail all-accents)
265 (while tail
266 (define-key key-translation-map (char-to-string (car tail))
267 'iso-accents-accent-key)
268 (setq tail (cdr tail))))))
700be2bd
RS
269
270(defun iso-accentuate (start end)
271 "Convert two-character sequences in region into accented characters.
272Noninteractively, this operates on text from START to END.
273This uses the same conversion that ISO Accents mode uses for type-in."
274 (interactive "r")
275 (save-excursion
276 (save-restriction
277 (narrow-to-region start end)
278 (goto-char start)
279 (forward-char 1)
280 (let (entry)
281 (while (< (point) end)
282 (if (and (memq (preceding-char) iso-accents-enable)
283 (<= ?A (following-char))
284 (<= (following-char) ?z)
285 (setq entry (assoc (list (preceding-char) (following-char))
286 iso-accents-list)))
287 (progn
288 (forward-char -1)
289 (delete-char 2)
290 (insert (car (cdr entry)))
291 (setq end (1- end)))
292 (forward-char 1)))))))
293
294(defun iso-accent-rassoc-unit (value alist)
295 (while (and alist
296 (not (eq (car (cdr (car alist))) value)))
297 (setq alist (cdr alist)))
298 (if alist
299 (car alist)
300 nil))
301
302(defun iso-unaccentuate (start end)
303 "Convert accented characters in the region into two-character sequences.
304Noninteractively, this operates on text from START to END.
305This uses the opposite of the conversion done by ISO Accents mode for type-in."
306 (interactive "r")
307 (save-excursion
308 (save-restriction
309 (narrow-to-region start end)
310 (goto-char start)
311 (let (entry)
312 (while (< (point) end)
313 (if (and (> (following-char) 127)
314 (setq entry (iso-accent-rassoc-unit (following-char)
315 iso-accents-list)))
316 (progn
317 (delete-char 1)
318 (insert (car (car entry)) (car (cdr (car entry))))
319 (setq end (1+ end)))
320 (forward-char 1)))))))
321
322(defun iso-deaccentuate (start end)
323 "Convert accented characters in the region into unaccented characters.
324Noninteractively, this operates on text from START to END."
325 (interactive "r")
326 (save-excursion
327 (save-restriction
328 (narrow-to-region start end)
329 (goto-char start)
330 (let (entry)
331 (while (< (point) end)
332 (if (and (> (following-char) 127)
333 (setq entry (iso-accent-rassoc-unit (following-char)
334 iso-accents-list)))
335 (progn
336 (delete-char 1)
337 (insert (car (cdr (car entry)))))
338 (forward-char 1)))))))
339
9a71dcfd
KH
340;; Set up the default settings.
341(iso-accents-customize "default")
700be2bd 342
bf4de26a 343;;; iso-acc.el ends here