Commit | Line | Data |
---|---|---|
3fdc9c8f | 1 | ;;; quail.el --- Provides simple input method for multilingual text |
4ed46869 | 2 | |
4ed46869 | 3 | ;; Copyright (C) 1995 Electrotechnical Laboratory, JAPAN. |
fa526c4a | 4 | ;; Licensed to the Free Software Foundation. |
4ed46869 KH |
5 | |
6 | ;; Author: Kenichi HANDA <handa@etl.go.jp> | |
7 | ;; Naoto TAKAHASHI <ntakahas@etl.go.jp> | |
8 | ;; Maintainer: Kenichi HANDA <handa@etl.go.jp> | |
9 | ;; Keywords: mule, multilingual, input method | |
10 | ||
11 | ;; This file is part of GNU Emacs. | |
12 | ||
13 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
14 | ;; it under the terms of the GNU General Public License as published by | |
15 | ;; the Free Software Foundation; either version 2, or (at your option) | |
16 | ;; any later version. | |
17 | ||
18 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | ;; GNU General Public License for more details. | |
22 | ||
23 | ;; You should have received a copy of the GNU General Public License | |
369314dc KH |
24 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
25 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
26 | ;; Boston, MA 02111-1307, USA. | |
4ed46869 KH |
27 | |
28 | ;;; Commentary: | |
29 | ||
30 | ;; In Quail minor mode, you can input multilingual text easily. By | |
31 | ;; defining a translation table (named Quail map) which maps ASCII key | |
32 | ;; string to multilingual character or string, you can input any text | |
33 | ;; from ASCII keyboard. | |
34 | ;; | |
35 | ;; We use words "translation" and "conversion" differently. The | |
36 | ;; former is done by Quail package itself, the latter is the further | |
37 | ;; process of converting a translated text to some more desirable | |
38 | ;; text. For instance, Quail package for Japanese (`quail-jp') | |
39 | ;; translates Roman text (transliteration of Japanese in Latin | |
40 | ;; alphabets) to Hiragana text, which is then converted to | |
41 | ;; Kanji-and-Kana mixed text or Katakana text by commands specified in | |
42 | ;; CONVERSION-KEYS argument of the Quail package. | |
43 | ||
44 | ;;; Code: | |
45 | ||
46 | (require 'faces) | |
47 | ||
48 | ;; Buffer local variables | |
49 | ||
50 | (defvar quail-current-package nil | |
105ef6bf | 51 | "The current Quail package, which depends on the current input method. |
4ed46869 KH |
52 | See the documentation of `quail-package-alist' for the format.") |
53 | (make-variable-buffer-local 'quail-current-package) | |
54 | (put 'quail-current-package 'permanent-local t) | |
55 | ||
56 | ;; Quail uses the following two buffers to assist users. | |
57 | ;; A buffer to show available key sequence or translation list. | |
58 | (defvar quail-guidance-buf nil) | |
59 | ;; A buffer to show completion list of the current key sequence. | |
60 | (defvar quail-completion-buf nil) | |
61 | ||
7d842556 KH |
62 | ;; Each buffer in which Quail is activated should use different |
63 | ;; guidance buffers. | |
64 | (make-variable-buffer-local 'quail-guidance-buf) | |
105ef6bf | 65 | (put 'quail-guidance-buf 'permanent-local t) |
7d842556 KH |
66 | |
67 | ;; A main window showing Quail guidance buffer. | |
68 | (defvar quail-guidance-win nil) | |
69 | (make-variable-buffer-local 'quail-guidance-win) | |
70 | ||
4ed46869 KH |
71 | (defvar quail-overlay nil |
72 | "Overlay which covers the current translation region of Quail.") | |
73 | (make-variable-buffer-local 'quail-overlay) | |
74 | ||
75 | (defvar quail-conv-overlay nil | |
76 | "Overlay which covers the text to be converted in Quail mode.") | |
77 | (make-variable-buffer-local 'quail-conv-overlay) | |
78 | ||
79 | (defvar quail-current-key nil | |
80 | "Current key for translation in Quail mode.") | |
b58fc490 | 81 | (make-variable-buffer-local 'quail-current-key) |
4ed46869 KH |
82 | |
83 | (defvar quail-current-str nil | |
84 | "Currently selected translation of the current key.") | |
b58fc490 | 85 | (make-variable-buffer-local 'quail-current-str) |
4ed46869 KH |
86 | |
87 | (defvar quail-current-translations nil | |
7d842556 KH |
88 | "Cons of indices and vector of possible translations of the current key. |
89 | Indices is a list of (CURRENT START END BLOCK BLOCKS), where | |
90 | CURRENT is an index of the current translation, | |
91 | START and END are indices of the start and end of the current block, | |
92 | BLOCK is the current block index, | |
93 | BLOCKS is a number of blocks of translation.") | |
b58fc490 | 94 | (make-variable-buffer-local 'quail-current-translations) |
4ed46869 | 95 | |
ff913e92 KH |
96 | (defvar quail-current-data nil |
97 | "Any Lisp object holding information of current translation status. | |
98 | When a key sequence is mapped to TRANS and TRANS is a cons | |
cd30a521 | 99 | of actual translation and some Lisp object to be referred |
ff913e92 KH |
100 | for translating the longer key sequence, this variable is set |
101 | to that Lisp object.") | |
7d842556 | 102 | (make-variable-buffer-local 'quail-current-data) |
ff913e92 | 103 | |
4ed46869 KH |
104 | ;; Quail package handlers. |
105 | ||
106 | (defvar quail-package-alist nil | |
107 | "List of Quail packages. | |
108 | A Quail package is a list of these elements: | |
109 | NAME, TITLE, QUAIL-MAP, GUIDANCE, DOCSTRING, TRANSLATION-KEYS, | |
110 | FORGET-LAST-SELECTION, DETERMINISTIC, KBD-TRANSLATE, SHOW-LAYOUT, | |
111 | DECODE-MAP, MAXIMUM-SHORTEST, OVERLAY-PLIST, UPDATE-TRANSLATION-FUNCTION, | |
b55ba027 | 112 | CONVERSION-KEYS, SIMPLE. |
4ed46869 KH |
113 | |
114 | QUAIL-MAP is a data structure to map key strings to translations. For | |
115 | the format, see the documentation of `quail-map-p'. | |
116 | ||
117 | DECODE-MAP is an alist of translations and corresponding keys. | |
118 | ||
119 | See the documentation of `quail-define-package' for the other elements.") | |
120 | ||
121 | ;; Return various slots in the current quail-package. | |
122 | ||
123 | (defsubst quail-name () | |
124 | "Return the name of the current Quail package." | |
125 | (nth 0 quail-current-package)) | |
126 | (defsubst quail-title () | |
127 | "Return the title of the current Quail package." | |
128 | (nth 1 quail-current-package)) | |
129 | (defsubst quail-map () | |
130 | "Return the translation map of the current Quail package." | |
131 | (nth 2 quail-current-package)) | |
132 | (defsubst quail-guidance () | |
133 | "Return an object used for `guidance' feature of the current Quail package. | |
134 | See also the documentation of `quail-define-package'." | |
135 | (nth 3 quail-current-package)) | |
136 | (defsubst quail-docstring () | |
137 | "Return the documentation string of the current Quail package." | |
138 | (nth 4 quail-current-package)) | |
139 | (defsubst quail-translation-keymap () | |
140 | "Return translation keymap in the current Quail package. | |
141 | Translation keymap is a keymap used while translation region is active." | |
142 | (nth 5 quail-current-package)) | |
143 | (defsubst quail-forget-last-selection () | |
144 | "Return `forget-last-selection' flag of the current Quail package. | |
145 | See also the documentation of `quail-define-package'." | |
146 | (nth 6 quail-current-package)) | |
147 | (defsubst quail-deterministic () | |
148 | "Return `deterministic' flag of the current Quail package. | |
149 | See also the documentation of `quail-define-package'." | |
150 | (nth 7 quail-current-package)) | |
151 | (defsubst quail-kbd-translate () | |
152 | "Return `kbd-translate' flag of the current Quail package. | |
153 | See also the documentation of `quail-define-package'." | |
154 | (nth 8 quail-current-package)) | |
155 | (defsubst quail-show-layout () | |
156 | "Return `show-layout' flag of the current Quail package. | |
157 | See also the documentation of `quail-define-package'." | |
158 | (nth 9 quail-current-package)) | |
159 | (defsubst quail-decode-map () | |
160 | "Return decode map of the current Quail package. | |
161 | It is an alist of translations and corresponding keys." | |
162 | (nth 10 quail-current-package)) | |
163 | (defsubst quail-maximum-shortest () | |
164 | "Return `maximum-shortest' flag of the current Quail package. | |
165 | See also the documentation of `quail-define-package'." | |
166 | (nth 11 quail-current-package)) | |
167 | (defsubst quail-overlay-plist () | |
168 | "Return property list of an overly used in the current Quail package." | |
169 | (nth 12 quail-current-package)) | |
170 | (defsubst quail-update-translation-function () | |
171 | "Return a function for updating translation in the current Quail package." | |
172 | (nth 13 quail-current-package)) | |
173 | (defsubst quail-conversion-keymap () | |
174 | "Return conversion keymap in the current Quail package. | |
175 | Conversion keymap is a keymap used while conversion region is active | |
176 | but translation region is not active." | |
177 | (nth 14 quail-current-package)) | |
b55ba027 KH |
178 | (defsubst quail-simple () |
179 | "Return t if the current Quail package is simple." | |
180 | (nth 15 quail-current-package)) | |
4ed46869 KH |
181 | |
182 | (defsubst quail-package (name) | |
183 | "Return Quail package named NAME." | |
184 | (assoc name quail-package-alist)) | |
185 | ||
186 | (defun quail-add-package (package) | |
187 | "Add Quail package PACKAGE to `quail-package-alist'." | |
188 | (let ((pac (quail-package (car package)))) | |
189 | (if pac | |
190 | (setcdr pac (cdr package)) | |
191 | (setq quail-package-alist (cons package quail-package-alist))))) | |
192 | ||
193 | (defun quail-select-package (name) | |
194 | "Select Quail package named NAME as the current Quail package." | |
195 | (let ((package (quail-package name))) | |
196 | (if (null package) | |
197 | (error "No Quail package `%s'" name)) | |
198 | (setq quail-current-package package) | |
199 | (setq-default quail-current-package package) | |
200 | name)) | |
201 | ||
202 | ;;;###autoload | |
203 | (defun quail-use-package (package-name &rest libraries) | |
204 | "Start using Quail package PACKAGE-NAME. | |
205 | The remaining arguments are libraries to be loaded before using the package." | |
ff913e92 KH |
206 | (let ((package (quail-package package-name))) |
207 | (if (null package) | |
208 | ;; Perhaps we have not yet loaded necessary libraries. | |
209 | (while libraries | |
210 | (if (not (load (car libraries) t)) | |
211 | (progn | |
212 | (with-output-to-temp-buffer "*Help*" | |
213 | (princ "Quail package \"") | |
214 | (princ package-name) | |
215 | (princ "\" can't be activated\n because library \"") | |
216 | (princ (car libraries)) | |
217 | (princ "\" is not in `load-path'. | |
4ed46869 KH |
218 | |
219 | The most common case is that you have not yet installed appropriate | |
220 | libraries in LEIM (Libraries of Emacs Input Method) which is | |
221 | distributed separately from Emacs. | |
222 | ||
4ed46869 | 223 | LEIM is available from the same ftp directory as Emacs.")) |
ff913e92 KH |
224 | (error "Can't use the Quail package `%s'" package-name)) |
225 | (setq libraries (cdr libraries)))))) | |
4ed46869 KH |
226 | (quail-select-package package-name) |
227 | (setq current-input-method-title (quail-title)) | |
b58fc490 | 228 | (quail-activate)) |
4ed46869 | 229 | |
d91eafdf | 230 | (defvar quail-translation-keymap |
4ed46869 | 231 | (let ((map (make-keymap)) |
d91eafdf KH |
232 | (i 0)) |
233 | (while (< i ?\ ) | |
234 | (define-key map (char-to-string i) 'quail-other-command) | |
235 | (setq i (1+ i))) | |
4ed46869 KH |
236 | (while (< i 127) |
237 | (define-key map (char-to-string i) 'quail-self-insert-command) | |
238 | (setq i (1+ i))) | |
f5c7c0eb | 239 | (setq i 128) |
094550e6 | 240 | (while (< i 256) |
f5c7c0eb KH |
241 | (define-key map (vector i) 'quail-self-insert-command) |
242 | (setq i (1+ i))) | |
4ed46869 | 243 | (define-key map "\177" 'quail-delete-last-char) |
4ed46869 KH |
244 | (define-key map "\C-f" 'quail-next-translation) |
245 | (define-key map "\C-b" 'quail-prev-translation) | |
246 | (define-key map "\C-n" 'quail-next-translation-block) | |
247 | (define-key map "\C-p" 'quail-prev-translation-block) | |
4afb4ca5 KH |
248 | (define-key map [right] 'quail-next-translation) |
249 | (define-key map [left] 'quail-prev-translation) | |
250 | (define-key map [down] 'quail-next-translation-block) | |
251 | (define-key map [up] 'quail-prev-translation-block) | |
4ed46869 KH |
252 | (define-key map "\C-i" 'quail-completion) |
253 | (define-key map "\C-@" 'quail-select-current) | |
5611ce7c KH |
254 | ;; Following simple.el, Enter key on numeric keypad selects the |
255 | ;; current translation just like `C-SPC', and `mouse-2' chooses | |
256 | ;; any completion visible in the *Quail Completions* buffer. | |
257 | (define-key map [kp-enter] 'quail-select-current) | |
258 | (define-key map [mouse-2] 'quail-mouse-choose-completion) | |
259 | (define-key map [down-mouse-2] nil) | |
4ed46869 | 260 | (define-key map "\C-h" 'quail-translation-help) |
e68e61b5 | 261 | (define-key map [?\C- ] 'quail-select-current) |
4ed46869 KH |
262 | (define-key map [tab] 'quail-completion) |
263 | (define-key map [delete] 'quail-delete-last-char) | |
264 | (define-key map [backspace] 'quail-delete-last-char) | |
e3799a72 | 265 | map) |
57a54470 RS |
266 | "Keymap used processing translation in complex Quail modes. |
267 | Only a few especially complex input methods use this map; | |
268 | most use `quail-simple-translation-keymap' instead. | |
269 | This map is activated while translation region is active.") | |
270 | ||
d91eafdf | 271 | (defvar quail-simple-translation-keymap |
57a54470 | 272 | (let ((map (make-keymap)) |
d91eafdf KH |
273 | (i 0)) |
274 | (while (< i ?\ ) | |
275 | (define-key map (char-to-string i) 'quail-other-command) | |
276 | (setq i (1+ i))) | |
57a54470 RS |
277 | (while (< i 127) |
278 | (define-key map (char-to-string i) 'quail-self-insert-command) | |
279 | (setq i (1+ i))) | |
280 | (define-key map "\177" 'quail-delete-last-char) | |
959096f8 RS |
281 | (define-key map [delete] 'quail-delete-last-char) |
282 | (define-key map [backspace] 'quail-delete-last-char) | |
d91eafdf KH |
283 | ;;(let ((meta-map (make-sparse-keymap))) |
284 | ;;(define-key map (char-to-string meta-prefix-char) meta-map) | |
285 | ;;(define-key map [escape] meta-map)) | |
e3799a72 | 286 | map) |
57a54470 | 287 | "Keymap used while processing translation in simple Quail modes. |
348d1438 | 288 | A few especially complex input methods use `quail-translation-keymap' instead. |
4ed46869 KH |
289 | This map is activated while translation region is active.") |
290 | ||
d91eafdf | 291 | (defvar quail-conversion-keymap |
4ed46869 | 292 | (let ((map (make-keymap)) |
b58fc490 | 293 | (i ?\ )) |
4ed46869 | 294 | (while (< i 127) |
b58fc490 | 295 | (define-key map (char-to-string i) 'quail-self-insert-command) |
4ed46869 | 296 | (setq i (1+ i))) |
f5c7c0eb | 297 | (setq i 128) |
094550e6 | 298 | (while (< i 256) |
b58fc490 | 299 | (define-key map (vector i) 'quail-self-insert-command) |
f5c7c0eb | 300 | (setq i (1+ i))) |
4ed46869 KH |
301 | (define-key map "\C-b" 'quail-conversion-backward-char) |
302 | (define-key map "\C-f" 'quail-conversion-forward-char) | |
303 | (define-key map "\C-a" 'quail-conversion-beginning-of-region) | |
304 | (define-key map "\C-e" 'quail-conversion-end-of-region) | |
305 | (define-key map "\C-d" 'quail-conversion-delete-char) | |
b45d8d64 | 306 | (define-key map "\C-k" 'quail-conversion-delete-tail) |
d91eafdf | 307 | (define-key map "\C-h" 'quail-translation-help) |
4ed46869 KH |
308 | (define-key map "\177" 'quail-conversion-backward-delete-char) |
309 | (define-key map [delete] 'quail-conversion-backward-delete-char) | |
310 | (define-key map [backspace] 'quail-conversion-backward-delete-char) | |
e3799a72 | 311 | map) |
4ed46869 | 312 | "Keymap used for processing conversion in Quail mode. |
cd30a521 | 313 | This map is activated while conversion region is active but translation |
4ed46869 KH |
314 | region is not active.") |
315 | ||
ff913e92 | 316 | ;;;###autoload |
4ed46869 KH |
317 | (defun quail-define-package (name language title |
318 | &optional guidance docstring translation-keys | |
319 | forget-last-selection deterministic | |
320 | kbd-translate show-layout create-decode-map | |
321 | maximum-shortest overlay-plist | |
322 | update-translation-function | |
57a54470 | 323 | conversion-keys simple) |
4ed46869 KH |
324 | "Define NAME as a new Quail package for input LANGUAGE. |
325 | TITLE is a string to be displayed at mode-line to indicate this package. | |
d91eafdf | 326 | Optional arguments are GUIDANCE, DOCSTRING, TRANSLATION-KEYS, |
4ed46869 KH |
327 | FORGET-LAST-SELECTION, DETERMINISTIC, KBD-TRANSLATE, SHOW-LAYOUT, |
328 | CREATE-DECODE-MAP, MAXIMUM-SHORTEST, OVERLAY-PLIST, | |
57a54470 | 329 | UPDATE-TRANSLATION-FUNCTION, CONVERSION-KEYS and SIMPLE. |
4ed46869 KH |
330 | |
331 | GUIDANCE specifies how a guidance string is shown in echo area. | |
332 | If it is t, list of all possible translations for the current key is shown | |
333 | with the currently selected translation being highlighted. | |
334 | If it is an alist, the element has the form (CHAR . STRING). Each character | |
335 | in the current key is searched in the list and the corresponding string is | |
336 | shown. | |
337 | If it is nil, the current key is shown. | |
338 | ||
339 | DOCSTRING is the documentation string of this package. | |
340 | ||
341 | TRANSLATION-KEYS specifies additional key bindings used while translation | |
342 | region is active. It is an alist of single key character vs. corresponding | |
343 | command to be called. | |
344 | ||
345 | FORGET-LAST-SELECTION non-nil means a selected translation is not kept | |
346 | for the future to translate the same key. If this flag is nil, a | |
347 | translation selected for a key is remembered so that it can be the | |
348 | first candidate when the same key is entered later. | |
349 | ||
350 | DETERMINISTIC non-nil means the first candidate of translation is | |
351 | selected automatically without allowing users to select another | |
352 | translation for a key. In this case, unselected translations are of | |
353 | no use for an interactive use of Quail but can be used by some other | |
354 | programs. If this flag is non-nil, FORGET-LAST-SELECTION is also set | |
355 | to t. | |
356 | ||
357 | KBD-TRANSLATE non-nil means input characters are translated from a | |
358 | user's keyboard layout to the standard keyboard layout. See the | |
359 | documentation of `quail-keyboard-layout' and | |
360 | `quail-keyboard-layout-standard' for more detail. | |
361 | ||
362 | SHOW-LAYOUT non-nil means the `quail-help' command should show | |
363 | the user's keyboard layout visually with translated characters. | |
364 | If KBD-TRANSLATE is set, it is desirable to set also this flag unless | |
365 | this package defines no translations for single character keys. | |
366 | ||
367 | CREATE-DECODE-MAP non-nil means decode map is also created. A decode | |
368 | map is an alist of translations and corresponding original keys. | |
369 | Although this map is not used by Quail itself, it can be used by some | |
370 | other programs. For instance, Vietnamese supporting needs this map to | |
371 | convert Vietnamese text to VIQR format which uses only ASCII | |
372 | characters to represent Vietnamese characters. | |
373 | ||
374 | MAXIMUM-SHORTEST non-nil means break key sequence to get maximum | |
375 | length of the shortest sequence. When we don't have a translation of | |
376 | key \"..ABCD\" but have translations of \"..AB\" and \"CD..\", break | |
377 | the key at \"..AB\" and start translation of \"CD..\". Hangul | |
378 | packages, for instance, use this facility. If this flag is nil, we | |
379 | break the key just at \"..ABC\" and start translation of \"D..\". | |
380 | ||
381 | OVERLAY-PLIST if non-nil is a property list put on an overlay which | |
382 | covers Quail translation region. | |
383 | ||
384 | UPDATE-TRANSLATION-FUNCTION if non-nil is a function to call to update | |
cd30a521 KH |
385 | the current translation region according to a new translation data. By |
386 | default, a translated text or a user's key sequence (if no translation | |
4ed46869 KH |
387 | for it) is inserted. |
388 | ||
389 | CONVERSION-KEYS specifies additional key bindings used while | |
390 | conversion region is active. It is an alist of single key character | |
57a54470 RS |
391 | vs. corresponding command to be called. |
392 | ||
393 | If SIMPLE is non-nil, then we do not alter the meanings of | |
394 | commands such as C-f, C-b, C-n, C-p and TAB; they are treated as | |
395 | non-Quail commands." | |
4ed46869 KH |
396 | (let (translation-keymap conversion-keymap) |
397 | (if deterministic (setq forget-last-selection t)) | |
398 | (if translation-keys | |
20110571 | 399 | (progn |
57a54470 RS |
400 | (setq translation-keymap (copy-keymap |
401 | (if simple quail-simple-translation-keymap | |
402 | quail-translation-keymap))) | |
20110571 KH |
403 | (while translation-keys |
404 | (define-key translation-keymap | |
405 | (car (car translation-keys)) (cdr (car translation-keys))) | |
406 | (setq translation-keys (cdr translation-keys)))) | |
57a54470 RS |
407 | (setq translation-keymap |
408 | (if simple quail-simple-translation-keymap | |
409 | quail-translation-keymap))) | |
20110571 KH |
410 | (when conversion-keys |
411 | (setq conversion-keymap (copy-keymap quail-conversion-keymap)) | |
412 | (while conversion-keys | |
413 | (define-key conversion-keymap | |
414 | (car (car conversion-keys)) (cdr (car conversion-keys))) | |
415 | (setq conversion-keys (cdr conversion-keys)))) | |
4ed46869 KH |
416 | (quail-add-package |
417 | (list name title (list nil) guidance (or docstring "") | |
418 | translation-keymap | |
419 | forget-last-selection deterministic kbd-translate show-layout | |
420 | (if create-decode-map (list 'decode-map) nil) | |
421 | maximum-shortest overlay-plist update-translation-function | |
b55ba027 | 422 | conversion-keymap simple)) |
7d842556 KH |
423 | |
424 | ;; Update input-method-alist. | |
425 | (let ((slot (assoc name input-method-alist)) | |
426 | (val (list language 'quail-use-package title docstring))) | |
427 | (if slot (setcdr slot val) | |
428 | (setq input-method-alist (cons (cons name val) input-method-alist))))) | |
429 | ||
4ed46869 KH |
430 | (quail-select-package name)) |
431 | ||
432 | ;; Quail minor mode handlers. | |
433 | ||
434 | ;; Setup overlays used in Quail mode. | |
20110571 | 435 | (defun quail-setup-overlays (conversion-mode) |
4ed46869 KH |
436 | (let ((pos (point))) |
437 | (if (overlayp quail-overlay) | |
438 | (move-overlay quail-overlay pos pos) | |
439 | (setq quail-overlay (make-overlay pos pos nil nil t)) | |
20110571 KH |
440 | (if input-method-highlight-flag |
441 | (overlay-put quail-overlay 'face 'underline)) | |
4ed46869 KH |
442 | (let ((l (quail-overlay-plist))) |
443 | (while l | |
444 | (overlay-put quail-overlay (car l) (car (cdr l))) | |
445 | (setq l (cdr (cdr l)))))) | |
20110571 KH |
446 | (if conversion-mode |
447 | (if (overlayp quail-conv-overlay) | |
448 | (if (not (overlay-start quail-conv-overlay)) | |
449 | (move-overlay quail-conv-overlay pos pos)) | |
450 | (setq quail-conv-overlay (make-overlay pos pos nil nil t)) | |
451 | (if input-method-highlight-flag | |
452 | (overlay-put quail-conv-overlay 'face 'underline)))))) | |
4ed46869 KH |
453 | |
454 | ;; Delete overlays used in Quail mode. | |
455 | (defun quail-delete-overlays () | |
b58fc490 | 456 | (if (and (overlayp quail-overlay) (overlay-start quail-overlay)) |
4ed46869 | 457 | (delete-overlay quail-overlay)) |
b58fc490 | 458 | (if (and (overlayp quail-conv-overlay) (overlay-start quail-conv-overlay)) |
4ed46869 KH |
459 | (delete-overlay quail-conv-overlay))) |
460 | ||
05204016 KH |
461 | ;; Kill Quail guidance buffer. Set in kill-buffer-hook. |
462 | (defun quail-kill-guidance-buf () | |
463 | (if (buffer-live-p quail-guidance-buf) | |
464 | (kill-buffer quail-guidance-buf))) | |
465 | ||
b58fc490 KH |
466 | (defun quail-inactivate () |
467 | "Inactivate Quail input method." | |
468 | (interactive) | |
469 | (quail-activate -1)) | |
470 | ||
471 | (defun quail-activate (&optional arg) | |
472 | "Activate Quail input method. | |
473 | With arg, activate Quail input method if and only if arg is positive. | |
474 | ||
475 | While this input method is active, the variable | |
476 | `input-method-function' is bound to the function `quail-input-method'." | |
477 | (if (and arg | |
478 | (< (prefix-numeric-value arg) 0)) | |
479 | ;; Let's inactivate Quail input method. | |
480 | (unwind-protect | |
481 | (progn | |
482 | (quail-hide-guidance-buf) | |
483 | (quail-delete-overlays) | |
484 | (setq describe-current-input-method-function nil) | |
485 | (run-hooks 'quail-inactivate-hook)) | |
486 | (kill-local-variable 'input-method-function)) | |
487 | ;; Let's active Quail input method. | |
4ed46869 KH |
488 | (if (null quail-current-package) |
489 | ;; Quail package is not yet selected. Select one now. | |
490 | (let (name) | |
491 | (if quail-package-alist | |
492 | (setq name (car (car quail-package-alist))) | |
4ed46869 KH |
493 | (error "No Quail package loaded")) |
494 | (quail-select-package name))) | |
20110571 | 495 | (setq inactivate-current-input-method-function 'quail-inactivate) |
4ed46869 | 496 | (setq describe-current-input-method-function 'quail-help) |
4ed46869 KH |
497 | (quail-delete-overlays) |
498 | (quail-show-guidance-buf) | |
05204016 KH |
499 | ;; If we are in minibuffer, turn off the current input method |
500 | ;; before exiting. | |
4ed46869 KH |
501 | (if (eq (selected-window) (minibuffer-window)) |
502 | (add-hook 'minibuffer-exit-hook 'quail-exit-from-minibuffer)) | |
05204016 KH |
503 | (make-local-hook 'kill-buffer-hook) |
504 | (add-hook 'kill-buffer-hook 'quail-kill-guidance-buf nil t) | |
b58fc490 KH |
505 | (run-hooks 'quail-activate-hook) |
506 | (make-local-variable 'input-method-function) | |
507 | (setq input-method-function 'quail-input-method))) | |
4ed46869 KH |
508 | |
509 | (defun quail-exit-from-minibuffer () | |
05204016 | 510 | (inactivate-input-method) |
4ed46869 KH |
511 | (if (<= (minibuffer-depth) 1) |
512 | (remove-hook 'minibuffer-exit-hook 'quail-exit-from-minibuffer))) | |
513 | ||
4ed46869 KH |
514 | ;; Keyboard layout translation handlers. |
515 | ||
516 | ;; Some Quail packages provide localized keyboard simulation which | |
517 | ;; requires a particular keyboard layout. In this case, what we need | |
518 | ;; is locations of keys the user entered, not character codes | |
519 | ;; generated by those keys. However, for the moment, there's no | |
520 | ;; common way to get such information. So, we ask a user to give | |
521 | ;; information of his own keyboard layout, then translate it to the | |
522 | ;; standard layout which we defined so that all Quail packages depend | |
523 | ;; just on it. | |
524 | ||
525 | (defconst quail-keyboard-layout-standard | |
526 | "\ | |
ea3fb7d2 | 527 | \ |
4ed46869 KH |
528 | 1!2@3#4$5%6^7&8*9(0)-_=+`~ \ |
529 | qQwWeErRtTyYuUiIoOpP[{]} \ | |
530 | aAsSdDfFgGhHjJkKlL;:'\"\\| \ | |
ea3fb7d2 KH |
531 | zZxXcCvVbBnNmM,<.>/? \ |
532 | " | |
4ed46869 KH |
533 | "Standard keyboard layout of printable characters Quail assumes. |
534 | See the documentation of `quail-keyboard-layout' for this format. | |
535 | This layout is almost the same as that of VT100, | |
536 | but the location of key \\ (backslash) is just right of key ' (single-quote), | |
537 | not right of RETURN key.") | |
538 | ||
539 | (defvar quail-keyboard-layout quail-keyboard-layout-standard | |
540 | "A string which represents physical key layout of a particular keyboard. | |
ea3fb7d2 KH |
541 | We assume there are six rows and each row has 15 keys (columns), |
542 | the first row is above the `1' - `0' row, | |
543 | the first column of the second row is left of key `1', | |
544 | the first column of the third row is left of key `q', | |
545 | the first column of the fourth row is left of key `a', | |
546 | the first column of the fifth row is left of key `z', | |
547 | the sixth row is below the `z' - `/' row. | |
4ed46869 KH |
548 | Nth (N is even) and (N+1)th characters in the string are non-shifted |
549 | and shifted characters respectively at the same location. | |
105ef6bf RS |
550 | The location of Nth character is row (N / 30) and column ((N mod 30) / 2). |
551 | The command `quail-set-keyboard-layout' usually sets this variable.") | |
4ed46869 | 552 | |
ea3fb7d2 | 553 | (defconst quail-keyboard-layout-len 180) |
4ed46869 KH |
554 | |
555 | ;; Here we provide several examples of famous keyboard layouts. | |
556 | ||
557 | (defvar quail-keyboard-layout-alist | |
558 | (list | |
559 | '("sun-type3" . "\ | |
ea3fb7d2 | 560 | \ |
4ed46869 KH |
561 | 1!2@3#4$5%6^7&8*9(0)-_=+\\|`~\ |
562 | qQwWeErRtTyYuUiIoOpP[{]} \ | |
563 | aAsSdDfFgGhHjJkKlL;:'\" \ | |
ea3fb7d2 KH |
564 | zZxXcCvVbBnNmM,<.>/? \ |
565 | ") | |
50b190e4 KH |
566 | '("atari-german" . "\ |
567 | \ | |
568 | 1!2\"3\2474$5%6&7/8(9)0=\337?'`#^ \ | |
569 | qQwWeErRtTzZuUiIoOpP\374\334+* \ | |
570 | aAsSdDfFgGhHjJkKlL\366\326\344\304~| \ | |
571 | <>yYxXcCvVbBnNmM,;.:-_ \ | |
572 | ") | |
4ed46869 KH |
573 | (cons "standard" quail-keyboard-layout-standard)) |
574 | "Alist of keyboard names and corresponding layout strings. | |
575 | See the documentation of `quail-keyboard-layout' for the format of | |
576 | the layout string.") | |
577 | ||
44baad62 | 578 | ;;;###autoload |
4ed46869 KH |
579 | (defun quail-set-keyboard-layout (kbd-type) |
580 | "Set the current keyboard layout to the same as keyboard KBD-TYPE. | |
581 | ||
582 | Since some Quail packages depends on a physical layout of keys (not | |
583 | characters generated by them), those are created by assuming the | |
584 | standard layout defined in `quail-keyboard-layout-standard'. This | |
585 | function tells Quail system the layout of your keyboard so that what | |
586 | you type is correctly handled." | |
587 | (interactive | |
588 | (let* ((completing-ignore-case t) | |
589 | (type (completing-read "Keyboard type: " | |
590 | quail-keyboard-layout-alist))) | |
591 | (list type))) | |
592 | (let ((layout (assoc kbd-type quail-keyboard-layout-alist))) | |
593 | (if (null layout) | |
594 | ;; Here, we had better ask a user to define his own keyboard | |
595 | ;; layout interactively. | |
596 | (error "Unknown keyboard type `%s'" kbd-type)) | |
597 | (setq quail-keyboard-layout (cdr layout)))) | |
598 | ||
599 | (defun quail-keyboard-translate (ch) | |
600 | "Translate CHAR according to `quail-keyboard-layout' and return the result." | |
601 | (if (eq quail-keyboard-layout quail-keyboard-layout-standard) | |
50b190e4 KH |
602 | ;; All Quail packages are designed based on |
603 | ;; `quail-keyboard-layout-standard'. | |
4ed46869 KH |
604 | ch |
605 | (let ((i 0)) | |
606 | (while (and (< i quail-keyboard-layout-len) | |
607 | (/= ch (aref quail-keyboard-layout i))) | |
608 | (setq i (1+ i))) | |
609 | (if (= i quail-keyboard-layout-len) | |
50b190e4 KH |
610 | ;; CH is not in quail-keyboard-layout, which means that a |
611 | ;; user typed a key which generated a character code to be | |
612 | ;; handled out of Quail. Just return CH and make | |
613 | ;; quail-execute-non-quail-command handle it correctly. | |
614 | ch | |
615 | (let ((char (aref quail-keyboard-layout-standard i))) | |
616 | (if (= char ?\ ) | |
cd30a521 | 617 | ;; A user typed a key at the location not converted by |
50b190e4 KH |
618 | ;; quail-keyboard-layout-standard. Just return CH as |
619 | ;; well as above. | |
620 | ch | |
621 | char)))))) | |
4ed46869 KH |
622 | |
623 | ;; Quail map | |
624 | ||
625 | (defsubst quail-map-p (object) | |
626 | "Return t if OBJECT is a Quail map. | |
627 | ||
628 | A Quail map holds information how a particular key should be translated. | |
629 | Its format is (TRANSLATION . ALIST). | |
630 | TRANSLATION is either a character, or a cons (INDEX . VECTOR). | |
631 | In the latter case, each element of VECTOR is a candidate for the translation, | |
632 | and INDEX points the currently selected translation. | |
633 | ||
634 | ALIST is normally a list of elements that look like (CHAR . DEFN), | |
635 | where DEFN is another Quail map for a longer key (CHAR added to the | |
636 | current key). It may also be a symbol of a function which returns an | |
637 | alist of the above format. | |
638 | ||
639 | Just after a Quail package is read, TRANSLATION may be a string or a | |
640 | vector. Then each element of the string or vector is a candidate for | |
641 | the translation. These objects are transformed to cons cells in the | |
642 | format \(INDEX . VECTOR), as described above." | |
643 | (and (consp object) | |
644 | (let ((translation (car object))) | |
ff913e92 | 645 | (or (integerp translation) (null translation) |
4ed46869 | 646 | (vectorp translation) (stringp translation) |
ff913e92 KH |
647 | (symbolp translation) |
648 | (and (consp translation) (not (vectorp (cdr translation)))))) | |
4ed46869 | 649 | (let ((alist (cdr object))) |
ff913e92 KH |
650 | (or (and (listp alist) (consp (car alist))) |
651 | (symbolp alist))))) | |
4ed46869 | 652 | |
ff913e92 | 653 | ;;;###autoload |
4ed46869 KH |
654 | (defmacro quail-define-rules (&rest rules) |
655 | "Define translation rules of the current Quail package. | |
656 | Each argument is a list of KEY and TRANSLATION. | |
657 | KEY is a string meaning a sequence of keystrokes to be translated. | |
658 | TRANSLATION is a character, a string, a vector, a Quail map, or a function. | |
659 | It it is a character, it is the sole translation of KEY. | |
660 | If it is a string, each character is a candidate for the translation. | |
661 | If it is a vector, each element (string or character) is a candidate | |
662 | for the translation. | |
663 | In these cases, a key specific Quail map is generated and assigned to KEY. | |
664 | ||
665 | If TRANSLATION is a Quail map or a function symbol which returns a Quail map, | |
666 | it is used to handle KEY." | |
667 | `(quail-install-map | |
668 | ',(let ((l rules) | |
669 | (map (list nil))) | |
670 | (while l | |
171666af | 671 | (quail-defrule-internal (car (car l)) (car (cdr (car l))) map t) |
4ed46869 KH |
672 | (setq l (cdr l))) |
673 | map))) | |
674 | ||
ff913e92 | 675 | ;;;###autoload |
4ed46869 KH |
676 | (defun quail-install-map (map) |
677 | "Install the Quail map MAP in the current Quail package. | |
678 | The installed map can be referred by the function `quail-map'." | |
679 | (if (null quail-current-package) | |
680 | (error "No current Quail package")) | |
681 | (if (null (quail-map-p map)) | |
682 | (error "Invalid Quail map `%s'" map)) | |
683 | (setcar (cdr (cdr quail-current-package)) map)) | |
684 | ||
ff913e92 | 685 | ;;;###autoload |
7b5ebb00 | 686 | (defun quail-defrule (key translation &optional name append) |
4ed46869 KH |
687 | "Add one translation rule, KEY to TRANSLATION, in the current Quail package. |
688 | KEY is a string meaning a sequence of keystrokes to be translated. | |
ff913e92 | 689 | TRANSLATION is a character, a string, a vector, a Quail map, |
7d842556 | 690 | a function, or a cons. |
4ed46869 KH |
691 | It it is a character, it is the sole translation of KEY. |
692 | If it is a string, each character is a candidate for the translation. | |
693 | If it is a vector, each element (string or character) is a candidate | |
7d842556 | 694 | for the translation. |
ff913e92 | 695 | If it is a cons, the car is one of the above and the cdr is a function |
7d842556 KH |
696 | to call when translating KEY (the return value is assigned to the |
697 | variable `quail-current-data'). If the cdr part is not a function, | |
698 | the value itself is assigned to `quail-current-data'. | |
4ed46869 KH |
699 | In these cases, a key specific Quail map is generated and assigned to KEY. |
700 | ||
701 | If TRANSLATION is a Quail map or a function symbol which returns a Quail map, | |
702 | it is used to handle KEY. | |
7b5ebb00 KH |
703 | |
704 | Optional 3rd argument NAME, if specified, says which Quail package | |
4ed46869 | 705 | to define this translation rule in. The default is to define it in the |
7b5ebb00 KH |
706 | current Quail package. |
707 | ||
708 | Optional 4th argument APPEND, if non-nil, appends TRANSLATION | |
709 | to the current translations for KEY instead of replacing them." | |
4ed46869 KH |
710 | (if name |
711 | (let ((package (quail-package name))) | |
712 | (if (null package) | |
713 | (error "No Quail package `%s'" name)) | |
714 | (setq quail-current-package package))) | |
7b5ebb00 | 715 | (quail-defrule-internal key translation (quail-map) append)) |
4ed46869 | 716 | |
ff913e92 | 717 | ;;;###autoload |
171666af | 718 | (defun quail-defrule-internal (key trans map &optional append) |
7d842556 | 719 | "Define KEY as TRANS in a Quail map MAP." |
4ed46869 KH |
720 | (if (null (stringp key)) |
721 | "Invalid Quail key `%s'" key) | |
722 | (if (not (or (numberp trans) (stringp trans) (vectorp trans) | |
ff913e92 | 723 | (consp trans) |
4ed46869 KH |
724 | (symbolp trans) |
725 | (quail-map-p trans))) | |
726 | (error "Invalid Quail translation `%s'" trans)) | |
727 | (if (null (quail-map-p map)) | |
728 | (error "Invalid Quail map `%s'" map)) | |
729 | (let ((len (length key)) | |
730 | (idx 0) | |
731 | ch entry) | |
ff913e92 | 732 | ;; Make a map for registering TRANS if necessary. |
4ed46869 KH |
733 | (while (< idx len) |
734 | (if (null (consp map)) | |
735 | ;; We come here, for example, when we try to define a rule | |
736 | ;; for "ABC" but a rule for "AB" is already defined as a | |
737 | ;; symbol. | |
738 | (error "Quail key %s is too long" key)) | |
739 | (setq ch (aref key idx) | |
740 | entry (assq ch (cdr map))) | |
741 | (if (null entry) | |
742 | (progn | |
743 | (setq entry (cons ch (list nil))) | |
744 | (setcdr map (cons entry (cdr map))))) | |
745 | (setq map (cdr entry)) | |
746 | (setq idx (1+ idx))) | |
747 | (if (symbolp trans) | |
748 | (if (cdr map) | |
749 | ;; We come here, for example, when we try to define a rule | |
750 | ;; for "AB" as a symbol but a rule for "ABC" is already | |
751 | ;; defined. | |
752 | (error "Quail key %s is too short" key) | |
753 | (setcdr entry trans)) | |
754 | (if (quail-map-p trans) | |
755 | (if (not (listp (cdr map))) | |
756 | ;; We come here, for example, when we try to define a rule | |
757 | ;; for "AB" as a symbol but a rule for "ABC" is already | |
758 | ;; defined. | |
759 | (error "Quail key %s is too short" key) | |
760 | (if (not (listp (cdr trans))) | |
761 | (if (cdr map) | |
762 | ;; We come here, for example, when we try to | |
763 | ;; define a rule for "AB" as a symbol but a rule | |
764 | ;; for "ABC" is already defined. | |
765 | (error "Quail key %s is too short" key) | |
766 | (setcdr entry trans)) | |
767 | (setcdr entry (append trans (cdr map))))) | |
7b5ebb00 KH |
768 | (if (and (car map) append) |
769 | (let ((prev (quail-get-translation (car map) key len))) | |
770 | (if (integerp prev) | |
771 | (setq prev (vector prev)) | |
772 | (setq prev (cdr prev))) | |
773 | (if (integerp trans) | |
774 | (setq trans (vector trans)) | |
775 | (if (stringp trans) | |
776 | (setq trans (string-to-vector trans)))) | |
777 | (setq trans | |
778 | (cons (list 0 0 0 0 nil) | |
779 | (vconcat prev trans))))) | |
780 | (setcar map trans))))) | |
4ed46869 | 781 | |
ff913e92 KH |
782 | (defun quail-get-translation (def key len) |
783 | "Return the translation specified as DEF for KEY of length LEN. | |
4ed46869 KH |
784 | The translation is either a character or a cons of the form (INDEX . VECTOR), |
785 | where VECTOR is a vector of candidates (character or string) for | |
786 | the translation, and INDEX points into VECTOR to specify the currently | |
787 | selected translation." | |
ff913e92 KH |
788 | (if (and def (symbolp def)) |
789 | ;; DEF is a symbol of a function which returns valid translation. | |
790 | (setq def (funcall def key len))) | |
791 | (if (and (consp def) (not (vectorp (cdr def)))) | |
792 | (setq def (car def))) | |
793 | ||
794 | (cond | |
795 | ((or (integerp def) (consp def)) | |
796 | def) | |
797 | ||
798 | ((null def) | |
799 | ;; No translation. | |
800 | nil) | |
801 | ||
802 | ((stringp def) | |
803 | ;; Each character in DEF is a candidate of translation. Reform | |
7d842556 | 804 | ;; it as (INDICES . VECTOR). |
ff913e92 KH |
805 | (setq def (string-to-vector def)) |
806 | ;; But if the length is 1, we don't need vector but a single | |
807 | ;; candidate as the translation. | |
808 | (if (= (length def) 1) | |
809 | (aref def 0) | |
7d842556 | 810 | (cons (list 0 0 0 0 nil) def))) |
ff913e92 KH |
811 | |
812 | ((vectorp def) | |
813 | ;; Each element (string or character) in DEF is a candidate of | |
7d842556 KH |
814 | ;; translation. Reform it as (INDICES . VECTOR). |
815 | (cons (list 0 0 0 0 nil) def)) | |
ff913e92 KH |
816 | |
817 | (t | |
818 | (error "Invalid object in Quail map: %s" def)))) | |
4ed46869 | 819 | |
7d842556 | 820 | (defun quail-lookup-key (key &optional len) |
4ed46869 KH |
821 | "Lookup KEY of length LEN in the current Quail map and return the definition. |
822 | The returned value is a Quail map specific to KEY." | |
7d842556 KH |
823 | (or len |
824 | (setq len (length key))) | |
4ed46869 KH |
825 | (let ((idx 0) |
826 | (map (quail-map)) | |
827 | (kbd-translate (quail-kbd-translate)) | |
ff913e92 | 828 | slot ch translation def) |
4ed46869 KH |
829 | (while (and map (< idx len)) |
830 | (setq ch (if kbd-translate (quail-keyboard-translate (aref key idx)) | |
831 | (aref key idx))) | |
832 | (setq idx (1+ idx)) | |
833 | (if (and (cdr map) (symbolp (cdr map))) | |
834 | (setcdr map (funcall (cdr map) key idx))) | |
835 | (setq slot (assq ch (cdr map))) | |
836 | (if (and (cdr slot) (symbolp (cdr slot))) | |
837 | (setcdr slot (funcall (cdr slot) key idx))) | |
838 | (setq map (cdr slot))) | |
ff913e92 | 839 | (setq def (car map)) |
7d842556 | 840 | (setq quail-current-translations nil) |
ff913e92 | 841 | (if (and map (setq translation (quail-get-translation def key len))) |
4ed46869 | 842 | (progn |
ff913e92 KH |
843 | (if (and (consp def) (not (vectorp (cdr def)))) |
844 | (progn | |
845 | (if (not (equal (car def) translation)) | |
846 | ;; We must reflect TRANSLATION to car part of DEF. | |
847 | (setcar def translation)) | |
848 | (setq quail-current-data | |
849 | (if (functionp (cdr def)) | |
850 | (funcall (cdr def)) | |
851 | (cdr def)))) | |
852 | (if (not (equal def translation)) | |
853 | ;; We must reflect TRANSLATION to car part of MAP. | |
854 | (setcar map translation))) | |
855 | (if (and (consp translation) (vectorp (cdr translation))) | |
4ed46869 KH |
856 | (progn |
857 | (setq quail-current-translations translation) | |
858 | (if (quail-forget-last-selection) | |
7d842556 | 859 | (setcar (car quail-current-translations) 0)))) |
4ed46869 KH |
860 | ;; We may have to reform cdr part of MAP. |
861 | (if (and (cdr map) (symbolp (cdr map))) | |
862 | (progn | |
863 | (setcdr map (funcall (cdr map) key len)))) | |
864 | )) | |
865 | map)) | |
866 | ||
b58fc490 KH |
867 | (put 'quail-error 'error-conditions '(quail-error error)) |
868 | (defun quail-error (&rest args) | |
869 | (signal 'quail-error (apply 'format args))) | |
870 | ||
871 | (defvar quail-translating nil) | |
872 | (defvar quail-converting nil) | |
d91eafdf | 873 | (defvar quail-conversion-str nil) |
b58fc490 KH |
874 | |
875 | (defun quail-input-method (key) | |
876 | (if (or buffer-read-only | |
b45d8d64 KH |
877 | overriding-terminal-local-map |
878 | overriding-local-map) | |
b58fc490 KH |
879 | (list key) |
880 | (quail-setup-overlays (quail-conversion-keymap)) | |
d91eafdf KH |
881 | (let ((modified-p (buffer-modified-p)) |
882 | (buffer-undo-list t)) | |
883 | (or (and quail-guidance-win | |
884 | (window-live-p quail-guidance-win) | |
885 | (eq (window-buffer quail-guidance-win) quail-guidance-buf) | |
886 | (not input-method-use-echo-area)) | |
887 | (quail-show-guidance-buf)) | |
b58fc490 KH |
888 | (unwind-protect |
889 | (if (quail-conversion-keymap) | |
890 | (quail-start-conversion key) | |
891 | (quail-start-translation key)) | |
b45d8d64 KH |
892 | (quail-delete-overlays) |
893 | (if (buffer-live-p quail-guidance-buf) | |
894 | (save-excursion | |
895 | (set-buffer quail-guidance-buf) | |
896 | (erase-buffer))) | |
d91eafdf KH |
897 | (if input-method-use-echo-area |
898 | (quail-hide-guidance-buf)) | |
b58fc490 | 899 | (set-buffer-modified-p modified-p) |
b45d8d64 KH |
900 | ;; Run this hook only when the current input method doesn't require |
901 | ;; conversion. When conversion is required, the conversion function | |
902 | ;; should run this hook at a proper timing. | |
903 | (unless (quail-conversion-keymap) | |
904 | (run-hooks 'input-method-after-insert-chunk-hook)))))) | |
b58fc490 KH |
905 | |
906 | (defun quail-overlay-region-events (overlay) | |
907 | (let ((start (overlay-start overlay)) | |
908 | (end (overlay-end overlay))) | |
909 | (if (< start end) | |
910 | (prog1 | |
911 | (string-to-list (buffer-substring start end)) | |
912 | (delete-region start end))))) | |
913 | ||
d91eafdf KH |
914 | (defsubst quail-delete-region () |
915 | "Delete the text in the current translation region of Quail." | |
916 | (if (overlay-start quail-overlay) | |
917 | (delete-region (overlay-start quail-overlay) | |
918 | (overlay-end quail-overlay)))) | |
919 | ||
b58fc490 KH |
920 | (defun quail-start-translation (key) |
921 | "Start translation of the typed character KEY by the current Quail package." | |
922 | ;; Check the possibility of translating KEY. | |
d91eafdf KH |
923 | ;; If KEY is nil, we can anyway start translation. |
924 | (if (or (and (integerp key) | |
925 | (assq (if (quail-kbd-translate) | |
926 | (quail-keyboard-translate key) key) | |
927 | (cdr (quail-map)))) | |
928 | (null key)) | |
cd30a521 | 929 | ;; OK, we can start translation. |
d91eafdf KH |
930 | (let* ((echo-keystrokes 0) |
931 | (help-char nil) | |
932 | (overriding-terminal-local-map (quail-translation-keymap)) | |
b58fc490 KH |
933 | (generated-events nil) |
934 | (input-method-function nil)) | |
935 | (setq quail-current-key "" | |
d91eafdf KH |
936 | quail-current-str "" |
937 | quail-translating t) | |
938 | (if key | |
939 | (setq unread-command-events (cons key unread-command-events))) | |
b58fc490 | 940 | (while quail-translating |
d91eafdf KH |
941 | (let* ((keyseq (read-key-sequence |
942 | (and input-method-use-echo-area | |
943 | (concat input-method-previous-message | |
944 | quail-current-str)))) | |
945 | (cmd (lookup-key (quail-translation-keymap) keyseq))) | |
946 | (if (if key | |
947 | (and (commandp cmd) (not (eq cmd 'quail-other-command))) | |
948 | (eq cmd 'quail-self-insert-command)) | |
b58fc490 | 949 | (progn |
d91eafdf KH |
950 | (setq key t) |
951 | (setq last-command-event (aref keyseq (1- (length keyseq))) | |
b45d8d64 KH |
952 | last-command this-command |
953 | this-command cmd) | |
b58fc490 KH |
954 | (condition-case err |
955 | (call-interactively cmd) | |
956 | (quail-error (message "%s" (cdr err)) (beep)))) | |
957 | ;; KEYSEQ is not defined in the translation keymap. | |
958 | ;; Let's return the event(s) to the caller. | |
d91eafdf KH |
959 | (setq generated-events |
960 | (string-to-list (this-single-command-raw-keys))) | |
961 | (setq quail-translating nil)))) | |
962 | (quail-delete-region) | |
963 | (if (and quail-current-str (> (length quail-current-str) 0)) | |
348d1438 | 964 | (setq generated-events |
f6a0db10 KH |
965 | (append (string-to-list |
966 | (if enable-multibyte-characters | |
967 | quail-current-str | |
968 | (string-make-unibyte quail-current-str))) | |
969 | generated-events))) | |
d91eafdf KH |
970 | (if (and input-method-exit-on-first-char generated-events) |
971 | (list (car generated-events)) | |
972 | generated-events)) | |
b58fc490 KH |
973 | |
974 | ;; Since KEY doesn't start any translation, just return it. | |
975 | (list key))) | |
976 | ||
977 | (defun quail-start-conversion (key) | |
978 | "Start conversion of the typed character KEY by the current Quail package." | |
979 | ;; Check the possibility of translating KEY. | |
d91eafdf KH |
980 | ;; If KEY is nil, we can anyway start translation. |
981 | (if (or (and (integerp key) | |
982 | (assq (if (quail-kbd-translate) | |
983 | (quail-keyboard-translate key) key) | |
984 | (cdr (quail-map)))) | |
985 | (null key)) | |
b58fc490 | 986 | ;; Ok, we can start translation and conversion. |
d91eafdf KH |
987 | (let* ((echo-keystrokes 0) |
988 | (help-char nil) | |
989 | (overriding-terminal-local-map (quail-conversion-keymap)) | |
b58fc490 KH |
990 | (generated-events nil) |
991 | (input-method-function nil)) | |
992 | (setq quail-current-key "" | |
d91eafdf | 993 | quail-current-str "" |
b58fc490 | 994 | quail-translating t |
d91eafdf KH |
995 | quail-converting t |
996 | quail-conversion-str "") | |
997 | (if key | |
998 | (setq unread-command-events (cons key unread-command-events))) | |
b58fc490 KH |
999 | (while quail-converting |
1000 | (or quail-translating | |
1001 | (progn | |
1002 | (setq quail-current-key "" | |
d91eafdf | 1003 | quail-current-str "" |
b58fc490 KH |
1004 | quail-translating t) |
1005 | (quail-setup-overlays nil))) | |
d91eafdf KH |
1006 | (let* ((keyseq (read-key-sequence |
1007 | (and input-method-use-echo-area | |
1008 | (concat input-method-previous-message | |
1009 | quail-conversion-str | |
1010 | quail-current-str)))) | |
1011 | (cmd (lookup-key (quail-conversion-keymap) keyseq))) | |
1012 | (if (if key (commandp cmd) (eq cmd 'quail-self-insert-command)) | |
b58fc490 | 1013 | (progn |
d91eafdf KH |
1014 | (setq key t) |
1015 | (setq last-command-event (aref keyseq (1- (length keyseq))) | |
b45d8d64 KH |
1016 | last-command this-command |
1017 | this-command cmd) | |
b58fc490 KH |
1018 | (condition-case err |
1019 | (call-interactively cmd) | |
d91eafdf KH |
1020 | (quail-error (message "%s" (cdr err)) (beep))) |
1021 | (or quail-translating | |
1022 | (progn | |
1023 | (if quail-current-str | |
1024 | (setq quail-conversion-str | |
1025 | (concat quail-conversion-str | |
1026 | (if (stringp quail-current-str) | |
1027 | quail-current-str | |
1028 | (char-to-string quail-current-str))))) | |
1029 | (if input-method-exit-on-first-char | |
1030 | (setq quail-converting nil))))) | |
b58fc490 KH |
1031 | ;; KEYSEQ is not defined in the conversion keymap. |
1032 | ;; Let's return the event(s) to the caller. | |
d91eafdf KH |
1033 | (setq generated-events |
1034 | (string-to-list (this-single-command-raw-keys))) | |
1035 | (setq quail-converting nil)))) | |
348d1438 | 1036 | (if (overlay-start quail-conv-overlay) |
d91eafdf KH |
1037 | (delete-region (overlay-start quail-conv-overlay) |
1038 | (overlay-end quail-conv-overlay))) | |
1039 | (if (> (length quail-conversion-str) 0) | |
348d1438 | 1040 | (setq generated-events |
f6a0db10 KH |
1041 | (append (string-to-list |
1042 | (if enable-multibyte-characters | |
1043 | quail-conversion-str | |
1044 | (string-make-unibyte quail-conversion-str))) | |
348d1438 | 1045 | generated-events))) |
d91eafdf KH |
1046 | (if (and input-method-exit-on-first-char generated-events) |
1047 | (list (car generated-events)) | |
1048 | generated-events)) | |
b58fc490 KH |
1049 | |
1050 | ;; Since KEY doesn't start any translation, just return it. | |
1051 | (list key))) | |
4ed46869 KH |
1052 | |
1053 | (defun quail-terminate-translation () | |
ce9395a9 | 1054 | "Terminate the translation of the current key." |
b58fc490 | 1055 | (setq quail-translating nil) |
4ed46869 KH |
1056 | (if (buffer-live-p quail-guidance-buf) |
1057 | (save-excursion | |
1058 | (set-buffer quail-guidance-buf) | |
b58fc490 | 1059 | (erase-buffer)))) |
4ed46869 | 1060 | |
4ed46869 KH |
1061 | (defun quail-select-current () |
1062 | "Select the current text shown in Quail translation region." | |
1063 | (interactive) | |
1064 | (quail-terminate-translation)) | |
1065 | ||
1066 | ;; Update the current translation status according to CONTROL-FLAG. | |
1067 | ;; If CONTROL-FLAG is integer value, it is the number of keys in the | |
1068 | ;; head quail-current-key which can be translated. The remaining keys | |
d91eafdf KH |
1069 | ;; are put back to unread-command-events to be handled again. If |
1070 | ;; CONTROL-FLAG is t, terminate the translation for the whole keys in | |
1071 | ;; quail-current-key. If CONTROL-FLAG is nil, proceed the translation | |
1072 | ;; with more keys. | |
4ed46869 KH |
1073 | |
1074 | (defun quail-update-translation (control-flag) | |
4ed46869 KH |
1075 | (let ((func (quail-update-translation-function))) |
1076 | (if func | |
d91eafdf | 1077 | (setq control-flag (funcall func control-flag)) |
4ed46869 KH |
1078 | (if (numberp control-flag) |
1079 | (let ((len (length quail-current-key))) | |
d91eafdf KH |
1080 | (if (= len 1) |
1081 | (setq control-flag t | |
1082 | quail-current-str quail-current-key) | |
bd21f930 KH |
1083 | (if input-method-exit-on-first-char |
1084 | (setq len control-flag) | |
1085 | (while (> len control-flag) | |
1086 | (setq len (1- len)) | |
1087 | (setq unread-command-events | |
1088 | (cons (aref quail-current-key len) | |
1089 | unread-command-events)))) | |
d91eafdf KH |
1090 | (if quail-current-str |
1091 | (if input-method-exit-on-first-char | |
1092 | (setq control-flag t)) | |
1093 | (setq quail-current-str | |
df765be4 | 1094 | (substring quail-current-key 0 len))))) |
d91eafdf | 1095 | (if quail-current-str |
bd21f930 KH |
1096 | (if (and input-method-exit-on-first-char |
1097 | (quail-simple)) | |
d91eafdf | 1098 | (setq control-flag t)) |
bd21f930 KH |
1099 | (setq quail-current-str quail-current-key))))) |
1100 | (or input-method-use-echo-area | |
1101 | (progn | |
1102 | (quail-delete-region) | |
1103 | (insert quail-current-str))) | |
1104 | (let (quail-current-str) | |
1105 | (quail-update-guidance)) | |
d91eafdf KH |
1106 | (or (stringp quail-current-str) |
1107 | (setq quail-current-str (char-to-string quail-current-str))) | |
05204016 KH |
1108 | (if control-flag |
1109 | (quail-terminate-translation))) | |
4ed46869 KH |
1110 | |
1111 | (defun quail-self-insert-command () | |
1112 | "Add the typed character to the key for translation." | |
1113 | (interactive "*") | |
1114 | (setq quail-current-key | |
1115 | (concat quail-current-key (char-to-string last-command-event))) | |
d91eafdf KH |
1116 | (or (catch 'quail-tag |
1117 | (quail-update-translation (quail-translate-key)) | |
1118 | t) | |
1119 | ;; If someone throws for `quail-tag' by value nil, we exit from | |
1120 | ;; translation mode. | |
1121 | (setq quail-translating nil))) | |
4ed46869 | 1122 | |
7d842556 KH |
1123 | ;; Return the actual definition part of Quail map MAP. |
1124 | (defun quail-map-definition (map) | |
1125 | (let ((def (car map))) | |
1126 | (if (and (consp def) (not (vectorp (cdr def)))) | |
1127 | (setq def (car def))) | |
1128 | def)) | |
1129 | ||
1130 | ;; Return a string to be shown as the current translation of key | |
1131 | ;; sequence of length LEN. DEF is a definition part of Quail map for | |
1132 | ;; the sequence. | |
1133 | (defun quail-get-current-str (len def) | |
1134 | (or (and (consp def) (aref (cdr def) (car (car def)))) | |
1135 | def | |
1136 | (and (> len 1) | |
1137 | (let ((str (quail-get-current-str | |
1138 | (1- len) | |
1139 | (quail-map-definition (quail-lookup-key | |
1140 | quail-current-key (1- len)))))) | |
1141 | (if str | |
1142 | (concat (if (stringp str) str (char-to-string str)) | |
1143 | (substring quail-current-key (1- len) len))))))) | |
1144 | ||
1145 | (defvar quail-guidance-translations-starting-column 20) | |
1146 | ||
1147 | ;; Update `quail-current-translations' to make RELATIVE-INDEX the | |
1148 | ;; current translation. | |
1149 | (defun quail-update-current-translations (&optional relative-index) | |
1150 | (let* ((indices (car quail-current-translations)) | |
1151 | (cur (car indices)) | |
1152 | (start (nth 1 indices)) | |
1153 | (end (nth 2 indices))) | |
1154 | ;; Validate the index number of current translation. | |
1155 | (if (< cur 0) | |
1156 | (setcar indices (setq cur 0)) | |
1157 | (if (>= cur (length (cdr quail-current-translations))) | |
1158 | (setcar indices | |
1159 | (setq cur (1- (length (cdr quail-current-translations))))))) | |
1160 | ||
1161 | (if (or (null end) ; We have not yet calculated END. | |
1162 | (< cur start) ; We moved to the previous block. | |
1163 | (>= cur end)) ; We moved to the next block. | |
1164 | (let ((len (length (cdr quail-current-translations))) | |
1165 | (maxcol (- (window-width quail-guidance-win) | |
1166 | quail-guidance-translations-starting-column)) | |
1167 | (block (nth 3 indices)) | |
1168 | col idx width trans num-items blocks) | |
1169 | (if (< cur start) | |
1170 | ;; We must calculate from the head. | |
1171 | (setq start 0 block 0) | |
1172 | (if end ; i.e. (>= cur end) | |
1173 | (setq start end))) | |
1174 | (setq idx start col 0 end start num-items 0) | |
1175 | ;; Loop until we hit the tail, or reach the block of CUR. | |
1176 | (while (and (< idx len) (>= cur end)) | |
1177 | (if (= num-items 0) | |
1178 | (setq start idx col 0 block (1+ block))) | |
1179 | (setq trans (aref (cdr quail-current-translations) idx)) | |
1180 | (setq width (if (integerp trans) (char-width trans) | |
1181 | (string-width trans))) | |
1182 | (setq col (+ col width 3) num-items (1+ num-items)) | |
1183 | (if (and (> num-items 0) | |
1184 | (or (>= col maxcol) (> num-items 10))) | |
1185 | (setq end idx num-items 0) | |
1186 | (setq idx (1+ idx)))) | |
1187 | (setcar (nthcdr 3 indices) block) | |
1188 | (if (>= idx len) | |
1189 | (progn | |
1190 | ;; We hit the tail before reaching MAXCOL. | |
1191 | (setq end idx) | |
1192 | (setcar (nthcdr 4 indices) block))) | |
1193 | (setcar (cdr indices) start) | |
1194 | (setcar (nthcdr 2 indices) end))) | |
1195 | (if relative-index | |
1196 | (if (>= (+ start relative-index) end) | |
1197 | (setcar indices end) | |
1198 | (setcar indices (+ start relative-index)))) | |
1199 | (setq quail-current-str | |
d91eafdf KH |
1200 | (aref (cdr quail-current-translations) (car indices))) |
1201 | (or (stringp quail-current-str) | |
1202 | (setq quail-current-str (char-to-string quail-current-str))))) | |
7d842556 | 1203 | |
4ed46869 KH |
1204 | (defun quail-translate-key () |
1205 | "Translate the current key sequence according to the current Quail map. | |
1206 | Return t if we can terminate the translation. | |
1207 | Return nil if the current key sequence may be followed by more keys. | |
1208 | Return number if we can't find any translation for the current key | |
1209 | sequence. The number is the count of valid keys in the current | |
1210 | sequence counting from the head." | |
1211 | (let* ((len (length quail-current-key)) | |
1212 | (map (quail-lookup-key quail-current-key len)) | |
1213 | def ch) | |
1214 | (if map | |
7d842556 KH |
1215 | (let ((def (quail-map-definition map))) |
1216 | (setq quail-current-str (quail-get-current-str len def)) | |
4ed46869 KH |
1217 | ;; Return t only if we can terminate the current translation. |
1218 | (and | |
1219 | ;; No alternative translations. | |
1220 | (or (null (consp def)) (= (length (cdr def)) 1)) | |
1221 | ;; No translation for the longer key. | |
1222 | (null (cdr map)) | |
1223 | ;; No shorter breaking point. | |
1224 | (or (null (quail-maximum-shortest)) | |
1225 | (< len 3) | |
1226 | (null (quail-lookup-key quail-current-key (1- len))) | |
1227 | (null (quail-lookup-key | |
1228 | (substring quail-current-key -2 -1) 1))))) | |
1229 | ||
1230 | ;; There's no translation for the current key sequence. Before | |
1231 | ;; giving up, we must check two possibilities. | |
1232 | (cond ((and | |
1233 | (quail-maximum-shortest) | |
1234 | (>= len 4) | |
7d842556 KH |
1235 | (setq def (quail-map-definition |
1236 | (quail-lookup-key quail-current-key (- len 2)))) | |
4ed46869 KH |
1237 | (quail-lookup-key (substring quail-current-key -2) 2)) |
1238 | ;; Now the sequence is "...ABCD", which can be split into | |
1239 | ;; "...AB" and "CD..." to get valid translation. | |
1240 | ;; At first, get translation of "...AB". | |
7d842556 | 1241 | (setq quail-current-str (quail-get-current-str (- len 2) def)) |
4ed46869 KH |
1242 | ;; Then, return the length of "...AB". |
1243 | (- len 2)) | |
1244 | ||
55e30181 KH |
1245 | ((and (> len 0) |
1246 | (quail-lookup-key (substring quail-current-key 0 -1)) | |
1247 | quail-current-translations | |
4ed46869 KH |
1248 | (not (quail-deterministic)) |
1249 | (setq ch (aref quail-current-key (1- len))) | |
1250 | (>= ch ?0) (<= ch ?9)) | |
1251 | ;; A numeric key is entered to select a desirable translation. | |
1252 | (setq quail-current-key (substring quail-current-key 0 -1)) | |
7d842556 KH |
1253 | ;; We treat key 1,2..,9,0 as specifying 0,1,..8,9. |
1254 | (setq ch (if (= ch ?0) 9 (- ch ?1))) | |
1255 | (quail-update-current-translations ch) | |
4ed46869 KH |
1256 | ;; And, we can terminate the current translation. |
1257 | t) | |
1258 | ||
1259 | (t | |
1260 | ;; No way to handle the last character in this context. | |
1261 | (1- len)))))) | |
1262 | ||
1263 | (defun quail-next-translation () | |
1264 | "Select next translation in the current batch of candidates." | |
1265 | (interactive) | |
1266 | (if quail-current-translations | |
7d842556 KH |
1267 | (let ((indices (car quail-current-translations))) |
1268 | (if (= (1+ (car indices)) (length (cdr quail-current-translations))) | |
5871092a | 1269 | ;; We are already at the tail. |
7d842556 KH |
1270 | (beep) |
1271 | (setcar indices (1+ (car indices))) | |
1272 | (quail-update-current-translations) | |
1273 | (quail-update-translation nil))) | |
b58fc490 KH |
1274 | (setq unread-command-events |
1275 | (cons last-command-event unread-command-events)) | |
1276 | (quail-terminate-translation))) | |
4ed46869 KH |
1277 | |
1278 | (defun quail-prev-translation () | |
1279 | "Select previous translation in the current batch of candidates." | |
1280 | (interactive) | |
1281 | (if quail-current-translations | |
7d842556 KH |
1282 | (let ((indices (car quail-current-translations))) |
1283 | (if (= (car indices) 0) | |
1284 | ;; We are already at the head. | |
1285 | (beep) | |
1286 | (setcar indices (1- (car indices))) | |
1287 | (quail-update-current-translations) | |
1288 | (quail-update-translation nil))) | |
b58fc490 KH |
1289 | (setq unread-command-events |
1290 | (cons last-command-event unread-command-events)) | |
1291 | (quail-terminate-translation))) | |
4ed46869 KH |
1292 | |
1293 | (defun quail-next-translation-block () | |
7d842556 | 1294 | "Select from the next block of translations." |
4ed46869 KH |
1295 | (interactive) |
1296 | (if quail-current-translations | |
7d842556 KH |
1297 | (let* ((indices (car quail-current-translations)) |
1298 | (offset (- (car indices) (nth 1 indices)))) | |
1299 | (if (>= (nth 2 indices) (length (cdr quail-current-translations))) | |
1300 | ;; We are already at the last block. | |
1301 | (beep) | |
1302 | (setcar indices (+ (nth 2 indices) offset)) | |
1303 | (quail-update-current-translations) | |
1304 | (quail-update-translation nil))) | |
b58fc490 | 1305 | (setq unread-command-events |
d91eafdf | 1306 | (cons last-command-event unread-command-events)) |
b58fc490 | 1307 | (quail-terminate-translation))) |
4ed46869 KH |
1308 | |
1309 | (defun quail-prev-translation-block () | |
1310 | "Select the previous batch of 10 translation candidates." | |
1311 | (interactive) | |
7d842556 KH |
1312 | (if quail-current-translations |
1313 | (let* ((indices (car quail-current-translations)) | |
1314 | (offset (- (car indices) (nth 1 indices)))) | |
1315 | (if (= (nth 1 indices) 0) | |
1316 | ;; We are already at the first block. | |
1317 | (beep) | |
1318 | (setcar indices (1- (nth 1 indices))) | |
1319 | (quail-update-current-translations) | |
1320 | (if (< (+ (nth 1 indices) offset) (nth 2 indices)) | |
1321 | (progn | |
1322 | (setcar indices (+ (nth 1 indices) offset)) | |
1323 | (quail-update-current-translations))) | |
1324 | (quail-update-translation nil))) | |
b58fc490 KH |
1325 | (setq unread-command-events |
1326 | (cons last-command-event unread-command-events)) | |
1327 | (quail-terminate-translation))) | |
4ed46869 | 1328 | |
4ed46869 KH |
1329 | (defun quail-abort-translation () |
1330 | "Abort translation and delete the current Quail key sequence." | |
1331 | (interactive) | |
1332 | (quail-delete-region) | |
d91eafdf | 1333 | (setq quail-current-str nil) |
4ed46869 KH |
1334 | (quail-terminate-translation)) |
1335 | ||
1336 | (defun quail-delete-last-char () | |
1337 | "Delete the last input character from the current Quail key sequence." | |
1338 | (interactive) | |
1339 | (if (= (length quail-current-key) 1) | |
1340 | (quail-abort-translation) | |
1341 | (setq quail-current-key (substring quail-current-key 0 -1)) | |
1342 | (quail-update-translation (quail-translate-key)))) | |
1343 | ||
1344 | ;; For conversion mode. | |
1345 | ||
1346 | (defun quail-conversion-backward-char () | |
1347 | (interactive) | |
1348 | (if (<= (point) (overlay-start quail-conv-overlay)) | |
b58fc490 KH |
1349 | (quail-error "Beginning of conversion region")) |
1350 | (setq quail-translating nil) | |
4ed46869 KH |
1351 | (forward-char -1)) |
1352 | ||
1353 | (defun quail-conversion-forward-char () | |
1354 | (interactive) | |
1355 | (if (>= (point) (overlay-end quail-conv-overlay)) | |
b58fc490 KH |
1356 | (quail-error "End of conversion region")) |
1357 | (setq quail-translating nil) | |
4ed46869 KH |
1358 | (forward-char 1)) |
1359 | ||
1360 | (defun quail-conversion-beginning-of-region () | |
1361 | (interactive) | |
b45d8d64 | 1362 | (setq quail-translating nil) |
4ed46869 KH |
1363 | (goto-char (overlay-start quail-conv-overlay))) |
1364 | ||
1365 | (defun quail-conversion-end-of-region () | |
1366 | (interactive) | |
b45d8d64 | 1367 | (setq quail-translating nil) |
4ed46869 KH |
1368 | (goto-char (overlay-end quail-conv-overlay))) |
1369 | ||
1370 | (defun quail-conversion-delete-char () | |
1371 | (interactive) | |
b45d8d64 | 1372 | (setq quail-translating nil) |
4ed46869 | 1373 | (if (>= (point) (overlay-end quail-conv-overlay)) |
b58fc490 | 1374 | (quail-error "End of conversion region")) |
4ed46869 | 1375 | (delete-char 1) |
d91eafdf KH |
1376 | (let ((start (overlay-start quail-conv-overlay)) |
1377 | (end (overlay-end quail-conv-overlay))) | |
1378 | (setq quail-conversion-str (buffer-substring start end)) | |
1379 | (if (= start end) | |
1380 | (setq quail-converting nil)))) | |
4ed46869 | 1381 | |
b45d8d64 KH |
1382 | (defun quail-conversion-delete-tail () |
1383 | (interactive) | |
1384 | (if (>= (point) (overlay-end quail-conv-overlay)) | |
1385 | (quail-error "End of conversion region")) | |
1386 | (delete-region (point) (overlay-end quail-conv-overlay)) | |
d91eafdf KH |
1387 | (let ((start (overlay-start quail-conv-overlay)) |
1388 | (end (overlay-end quail-conv-overlay))) | |
1389 | (setq quail-conversion-str (buffer-substring start end)) | |
1390 | (if (= start end) | |
1391 | (setq quail-converting nil)))) | |
b45d8d64 | 1392 | |
4ed46869 KH |
1393 | (defun quail-conversion-backward-delete-char () |
1394 | (interactive) | |
1395 | (if (<= (point) (overlay-start quail-conv-overlay)) | |
b58fc490 | 1396 | (quail-error "Beginning of conversion region")) |
4ed46869 | 1397 | (delete-char -1) |
d91eafdf KH |
1398 | (let ((start (overlay-start quail-conv-overlay)) |
1399 | (end (overlay-end quail-conv-overlay))) | |
1400 | (setq quail-conversion-str (buffer-substring start end)) | |
1401 | (if (= start end) | |
1402 | (setq quail-converting nil)))) | |
4ed46869 KH |
1403 | |
1404 | (defun quail-do-conversion (func &rest args) | |
1405 | "Call FUNC to convert text in the current conversion region of Quail. | |
1406 | Remaining args are for FUNC." | |
1407 | (delete-overlay quail-overlay) | |
1408 | (apply func args)) | |
1409 | ||
1410 | (defun quail-no-conversion () | |
1411 | "Do no conversion of the current conversion region of Quail." | |
1412 | (interactive) | |
b45d8d64 | 1413 | (setq quail-converting nil)) |
4ed46869 KH |
1414 | |
1415 | ;; Guidance, Completion, and Help buffer handlers. | |
1416 | ||
7d842556 KH |
1417 | ;; Make a new one-line frame for Quail guidance buffer. |
1418 | (defun quail-make-guidance-frame (buf) | |
1419 | (let* ((fparam (frame-parameters)) | |
1420 | (top (cdr (assq 'top fparam))) | |
1421 | (border (cdr (assq 'border-width fparam))) | |
1422 | (internal-border (cdr (assq 'internal-border-width fparam))) | |
1423 | (newtop (- top | |
1424 | (frame-char-height) (* internal-border 2) (* border 2)))) | |
1425 | (if (< newtop 0) | |
1426 | (setq newtop (+ top (frame-pixel-height)))) | |
1427 | (let* ((frame (make-frame (append '((user-position . t) (height . 1) | |
1428 | (minibuffer) (menu-bar-lines . 0)) | |
1429 | (cons (cons 'top newtop) fparam)))) | |
1430 | (win (frame-first-window frame))) | |
1431 | (set-window-buffer win buf) | |
e3799a72 RS |
1432 | ;;(set-window-dedicated-p win t) |
1433 | ))) | |
7d842556 | 1434 | |
05204016 KH |
1435 | ;; Setup Quail completion buffer. |
1436 | (defun quail-setup-completion-buf () | |
1437 | (unless (buffer-live-p quail-completion-buf) | |
1438 | (setq quail-completion-buf (get-buffer-create "*Quail Completions*")) | |
1439 | (save-excursion | |
1440 | (set-buffer quail-completion-buf) | |
1441 | (setq quail-overlay (make-overlay 1 1)) | |
1442 | (overlay-put quail-overlay 'face 'highlight)))) | |
1443 | ||
b55ba027 KH |
1444 | ;; Return t iff the current Quail package requires showing guidance |
1445 | ;; buffer. | |
1446 | (defun quail-require-guidance-buf () | |
1447 | (and input-method-verbose-flag | |
9a0eac6e KH |
1448 | (if (eq input-method-verbose-flag 'default) |
1449 | (not (and (eq (selected-window) (minibuffer-window)) | |
1450 | (quail-simple))) | |
1451 | (if (eq input-method-verbose-flag 'complex-only) | |
1452 | (not (quail-simple)) | |
1453 | t)))) | |
b55ba027 | 1454 | |
4ed46869 | 1455 | (defun quail-show-guidance-buf () |
7d842556 | 1456 | "Display a guidance buffer for Quail input method in some window. |
4ed46869 | 1457 | Create the buffer if it does not exist yet. |
7d842556 KH |
1458 | The buffer is normally displayed at the echo area, |
1459 | but if the current buffer is a minibuffer, it is shown in | |
1460 | the bottom-most ordinary window of the same frame, | |
1461 | or in a newly created frame (if the selected frame has no other windows)." | |
b55ba027 | 1462 | (when (quail-require-guidance-buf) |
7d842556 KH |
1463 | ;; At first, setup a guidance buffer. |
1464 | (or (buffer-live-p quail-guidance-buf) | |
1465 | (setq quail-guidance-buf (generate-new-buffer " *Quail-guidance*"))) | |
1466 | (let ((title (quail-title))) | |
1467 | (save-excursion | |
1468 | (set-buffer quail-guidance-buf) | |
1469 | ;; To show the title of Quail package. | |
1470 | (setq current-input-method t | |
1471 | current-input-method-title title) | |
1472 | (erase-buffer) | |
1473 | (or (overlayp quail-overlay) | |
1474 | (progn | |
1475 | (setq quail-overlay (make-overlay 1 1)) | |
1476 | (overlay-put quail-overlay 'face 'highlight))) | |
1477 | (delete-overlay quail-overlay) | |
1478 | (set-buffer-modified-p nil))) | |
1479 | (bury-buffer quail-guidance-buf) | |
1480 | ||
1481 | ;; Then, display it in an appropriate window. | |
1482 | (let ((win (minibuffer-window))) | |
d91eafdf KH |
1483 | (if (or (eq (selected-window) win) |
1484 | input-method-use-echo-area) | |
7d842556 KH |
1485 | ;; Since we are in minibuffer, we can't use it for guidance. |
1486 | (if (eq win (frame-root-window)) | |
1487 | ;; Create a frame. It is sure that we are using some | |
1488 | ;; window system. | |
1489 | (quail-make-guidance-frame quail-guidance-buf) | |
1490 | ;; Find the bottom window and split it if necessary. | |
1491 | (let (height) | |
1492 | (setq win (window-at 0 (- (frame-height) 2))) | |
1493 | (setq height (window-height win)) | |
1494 | ;; If WIN is tall enough, split it vertically and use | |
1495 | ;; the lower one. | |
1496 | (if (>= height 4) | |
1497 | (let ((window-min-height 2)) | |
1498 | ;; Here, `split-window' returns a lower window | |
1499 | ;; which is what we wanted. | |
1500 | (setq win (split-window win (- height 2))))) | |
1501 | (set-window-buffer win quail-guidance-buf) | |
e3799a72 RS |
1502 | ;;(set-window-dedicated-p win t) |
1503 | )) | |
7d842556 KH |
1504 | (set-window-buffer win quail-guidance-buf)) |
1505 | (setq quail-guidance-win win))) | |
4ed46869 KH |
1506 | |
1507 | ;; And, create a buffer for completion. | |
05204016 | 1508 | (quail-setup-completion-buf) |
4ed46869 KH |
1509 | (bury-buffer quail-completion-buf)) |
1510 | ||
1511 | (defun quail-hide-guidance-buf () | |
1512 | "Hide the Quail guidance buffer." | |
7d842556 KH |
1513 | (if (buffer-live-p quail-guidance-buf) |
1514 | (let ((win-list (get-buffer-window-list quail-guidance-buf t t)) | |
1515 | win) | |
1516 | (while win-list | |
1517 | (setq win (car win-list) win-list (cdr win-list)) | |
1518 | (if (eq win (minibuffer-window)) | |
1519 | ;; We are using echo area for the guidance buffer. | |
1520 | ;; Vacate it to the deepest minibuffer. | |
1521 | (set-window-buffer win | |
1522 | (format " *Minibuf-%d*" (minibuffer-depth))) | |
1523 | (if (eq win (frame-root-window (window-frame win))) | |
1524 | (progn | |
1525 | ;; We are using a separate frame for guidance buffer. | |
1526 | ;;(set-window-dedicated-p win nil) | |
1527 | (delete-frame (window-frame win))) | |
e3799a72 | 1528 | ;;(set-window-dedicated-p win nil) |
7d842556 | 1529 | (delete-window win))))))) |
4ed46869 KH |
1530 | |
1531 | (defun quail-update-guidance () | |
1532 | "Update the Quail guidance buffer and completion buffer (if displayed now)." | |
1533 | ;; Update guidance buffer. | |
b55ba027 | 1534 | (if (quail-require-guidance-buf) |
4ed46869 | 1535 | (let ((guidance (quail-guidance))) |
b8cd1360 | 1536 | (cond ((or (eq guidance t) |
bd21f930 | 1537 | (consp guidance)) |
4ed46869 KH |
1538 | ;; Show the current possible translations. |
1539 | (quail-show-translations)) | |
1540 | ((null guidance) | |
1541 | ;; Show the current input keys. | |
1542 | (let ((key quail-current-key)) | |
1543 | (save-excursion | |
1544 | (set-buffer quail-guidance-buf) | |
1545 | (erase-buffer) | |
b8cd1360 | 1546 | (insert key))))))) |
4ed46869 KH |
1547 | |
1548 | ;; Update completion buffer if displayed now. We highlight the | |
1549 | ;; selected candidate string in *Completion* buffer if any. | |
1550 | (let ((win (get-buffer-window quail-completion-buf)) | |
1551 | key str pos) | |
1552 | (if win | |
1553 | (save-excursion | |
1554 | (setq str (if (stringp quail-current-str) | |
1555 | quail-current-str | |
1556 | (if (numberp quail-current-str) | |
1557 | (char-to-string quail-current-str))) | |
1558 | key quail-current-key) | |
1559 | (set-buffer quail-completion-buf) | |
1560 | (goto-char (point-min)) | |
1561 | (if (null (search-forward (concat " " key ":") nil t)) | |
1562 | (delete-overlay quail-overlay) | |
1563 | (setq pos (point)) | |
1564 | (if (and str (search-forward (concat "." str) nil t)) | |
1565 | (move-overlay quail-overlay (1+ (match-beginning 0)) (point)) | |
1566 | (move-overlay quail-overlay (match-beginning 0) (point))) | |
1567 | ;; Now POS points end of KEY and (point) points end of STR. | |
1568 | (if (pos-visible-in-window-p (point) win) | |
1569 | ;; STR is already visible. | |
1570 | nil | |
1571 | ;; We want to make both KEY and STR visible, but if the | |
1572 | ;; window is too short, make at least STR visible. | |
1573 | (setq pos (progn (point) (goto-char pos))) | |
1574 | (beginning-of-line) | |
1575 | (set-window-start win (point)) | |
1576 | (if (not (pos-visible-in-window-p pos win)) | |
1577 | (set-window-start win pos)) | |
1578 | )))))) | |
1579 | ||
1580 | (defun quail-show-translations () | |
1581 | "Show the current possible translations." | |
ff913e92 | 1582 | (let* ((key quail-current-key) |
d91eafdf KH |
1583 | (map (quail-lookup-key quail-current-key)) |
1584 | (current-translations quail-current-translations)) | |
7d842556 KH |
1585 | (if quail-current-translations |
1586 | (quail-update-current-translations)) | |
4ed46869 KH |
1587 | (save-excursion |
1588 | (set-buffer quail-guidance-buf) | |
1589 | (erase-buffer) | |
1590 | ||
1591 | ;; Show the current key. | |
b8cd1360 KH |
1592 | (let ((guidance (quail-guidance))) |
1593 | (if (listp guidance) | |
1594 | ;; We must show the specified PROMPTKEY instead of the | |
1595 | ;; actual typed keys. | |
1596 | (let ((i 0) | |
1597 | (len (length key)) | |
1598 | prompt-key) | |
1599 | (while (< i len) | |
1600 | (setq prompt-key (cdr (assoc (aref key i) guidance))) | |
1601 | (insert (or prompt-key (aref key i))) | |
1602 | (setq i (1+ i)))) | |
1603 | (insert key))) | |
4ed46869 | 1604 | |
7d842556 | 1605 | ;; Show followable keys. |
d91eafdf | 1606 | (if (and (> (length key) 0) (cdr map)) |
e953b368 KH |
1607 | (let ((keys (mapcar (function (lambda (x) (car x))) |
1608 | (cdr map)))) | |
1609 | (setq keys (sort keys '<)) | |
4ed46869 | 1610 | (insert "[") |
e953b368 KH |
1611 | (while keys |
1612 | (insert (car keys)) | |
1613 | (setq keys (cdr keys))) | |
4ed46869 KH |
1614 | (insert "]"))) |
1615 | ||
1616 | ;; Show list of translations. | |
d91eafdf KH |
1617 | (if current-translations |
1618 | (let* ((indices (car current-translations)) | |
7d842556 KH |
1619 | (cur (car indices)) |
1620 | (start (nth 1 indices)) | |
1621 | (end (nth 2 indices)) | |
1622 | (idx start)) | |
1623 | (indent-to (- quail-guidance-translations-starting-column 7)) | |
1624 | (insert (format "(%02d/"(nth 3 indices)) | |
1625 | (if (nth 4 indices) | |
1626 | (format "%02d)" (nth 4 indices)) | |
1627 | "??)")) | |
1628 | (while (< idx end) | |
1629 | (insert (format " %d." (if (= (- idx start) 9) 0 | |
1630 | (1+ (- idx start))))) | |
4ed46869 | 1631 | (let ((pos (point))) |
d91eafdf | 1632 | (insert (aref (cdr current-translations) idx)) |
7d842556 | 1633 | (if (= idx cur) |
4ed46869 | 1634 | (move-overlay quail-overlay pos (point)))) |
7d842556 | 1635 | (setq idx (1+ idx))))) |
4ed46869 KH |
1636 | ))) |
1637 | ||
1638 | (defun quail-completion () | |
1639 | "List all completions for the current key. | |
1640 | All possible translations of the current key and whole possible longer keys | |
1641 | are shown." | |
1642 | (interactive) | |
05204016 | 1643 | (quail-setup-completion-buf) |
0548a7fd KH |
1644 | (let ((win (get-buffer-window quail-completion-buf 'visible)) |
1645 | (key quail-current-key) | |
1646 | (map (quail-lookup-key quail-current-key)) | |
1647 | (require-update nil)) | |
4ed46869 KH |
1648 | (save-excursion |
1649 | (set-buffer quail-completion-buf) | |
0548a7fd KH |
1650 | (if (and win |
1651 | (equal key quail-current-key) | |
1652 | (eq last-command 'quail-completion)) | |
1653 | ;; The window for Quail completion buffer has already been | |
1654 | ;; shown. We just scroll it appropriately. | |
1655 | (if (pos-visible-in-window-p (point-max) win) | |
1656 | (set-window-start win (point-min)) | |
1657 | (let ((other-window-scroll-buffer quail-completion-buf)) | |
1658 | (scroll-other-window))) | |
1659 | (setq quail-current-key key) | |
1660 | (erase-buffer) | |
1661 | (insert "Possible completion and corresponding translations are:\n") | |
1662 | (quail-completion-1 key map 1) | |
1663 | (goto-char (point-min)) | |
1664 | (display-buffer (current-buffer)) | |
1665 | (setq require-update t))) | |
1666 | (if require-update | |
1667 | (quail-update-guidance))) | |
1668 | (setq this-command 'quail-completion)) | |
4ed46869 KH |
1669 | |
1670 | ;; List all completions of KEY in MAP with indentation INDENT. | |
1671 | (defun quail-completion-1 (key map indent) | |
1672 | (let ((len (length key))) | |
1673 | (indent-to indent) | |
1674 | (insert key ":") | |
1675 | (if (and (symbolp map) (fboundp map)) | |
1676 | (setq map (funcall map key len))) | |
1677 | (if (car map) | |
1678 | (quail-completion-list-translations map key (+ indent len 1)) | |
1679 | (insert " -\n")) | |
1680 | (setq indent (+ indent 2)) | |
1681 | (if (cdr map) | |
1682 | (let ((l (cdr map)) | |
1683 | (newkey (make-string (1+ len) 0)) | |
1684 | (i 0)) | |
1685 | ;; Set KEY in the first LEN characters of NEWKEY. | |
1686 | (while (< i len) | |
1687 | (aset newkey i (aref key i)) | |
1688 | (setq i (1+ i))) | |
1689 | (while l ; L = ((CHAR . DEFN) ....) ; | |
1690 | (aset newkey len (car (car l))) | |
1691 | (quail-completion-1 newkey (cdr (car l)) indent) | |
1692 | (setq l (cdr l))))))) | |
1693 | ||
1694 | ;; List all possible translations of KEY in Quail map MAP with | |
7e22bdd8 | 1695 | ;; indentation INDENT. |
4ed46869 | 1696 | (defun quail-completion-list-translations (map key indent) |
5611ce7c | 1697 | (let (beg (translations |
ff913e92 | 1698 | (quail-get-translation (car map) key (length key)))) |
4ed46869 | 1699 | (if (integerp translations) |
5611ce7c KH |
1700 | (progn |
1701 | (insert "(1/1) 1.") | |
1702 | ;; Endow the character `translations' with `mouse-face' text | |
1703 | ;; property to enable `mouse-2' completion. | |
1704 | (setq beg (point)) | |
1705 | (insert translations) | |
1706 | (put-text-property beg (point) 'mouse-face 'highlight) | |
1707 | (insert "\n")) | |
4ed46869 KH |
1708 | ;; We need only vector part. |
1709 | (setq translations (cdr translations)) | |
1710 | ;; Insert every 10 elements with indices in a line. | |
1711 | (let ((len (length translations)) | |
1712 | (i 0) | |
4ed46869 KH |
1713 | num) |
1714 | (while (< i len) | |
8c14aa22 RS |
1715 | (when (zerop (% i 10)) |
1716 | (when (>= i 10) | |
5611ce7c | 1717 | (insert "\n") |
8c14aa22 RS |
1718 | (indent-to indent)) |
1719 | (insert (format "(%d/%d)" (1+ (/ i 10)) (1+ (/ len 10))))) | |
4ed46869 KH |
1720 | ;; We show the last digit of FROM while converting |
1721 | ;; 0,1,..,9 to 1,2,..,0. | |
8c14aa22 | 1722 | (insert (format " %d." (% (1+ i) 10))) |
5611ce7c | 1723 | (setq beg (point)) |
4ed46869 | 1724 | (insert (aref translations i)) |
5611ce7c KH |
1725 | ;; Passing the mouse over a character will highlight. |
1726 | (put-text-property beg (point) 'mouse-face 'highlight) | |
4ed46869 | 1727 | (setq i (1+ i))) |
5611ce7c KH |
1728 | (insert "\n"))))) |
1729 | ||
1730 | ;; Choose a completion in *Quail Completions* buffer with mouse-2. | |
1731 | ||
1732 | (defun quail-mouse-choose-completion (event) | |
1733 | "Click on an alternative in the `*Quail Completions*' buffer to choose it." | |
1734 | (interactive "e") | |
1735 | ;; This function is an exact copy of the mouse.el function | |
1736 | ;; `mouse-choose-completion' except that we: | |
1737 | ;; 1) add two lines from `choose-completion' in simple.el to give | |
1738 | ;; the `mouse-2' click a little more leeway. | |
1739 | ;; 2) don't bury *Quail Completions* buffer so comment a section, and | |
1740 | ;; 3) delete/terminate the current quail selection here. | |
1741 | ;; Give temporary modes such as isearch a chance to turn off. | |
1742 | (run-hooks 'mouse-leave-buffer-hook) | |
1743 | (let ((buffer (window-buffer)) | |
1744 | choice | |
1745 | base-size) | |
1746 | (save-excursion | |
1747 | (set-buffer (window-buffer (posn-window (event-start event)))) | |
1748 | (if completion-reference-buffer | |
1749 | (setq buffer completion-reference-buffer)) | |
1750 | (setq base-size completion-base-size) | |
1751 | (save-excursion | |
1752 | (goto-char (posn-point (event-start event))) | |
1753 | (let (beg end) | |
1754 | (if (and (not (eobp)) (get-text-property (point) 'mouse-face)) | |
1755 | (setq end (point) beg (1+ (point)))) | |
1756 | (if (and (not (bobp)) (get-text-property (1- (point)) 'mouse-face)) | |
1757 | (setq end (1- (point)) beg (point))) | |
1758 | (if (null beg) | |
b58fc490 | 1759 | (quail-error "No completion here")) |
5611ce7c KH |
1760 | (setq beg (previous-single-property-change beg 'mouse-face)) |
1761 | (setq end (or (next-single-property-change end 'mouse-face) | |
1762 | (point-max))) | |
1763 | (setq choice (buffer-substring beg end))))) | |
1764 | ; (let ((owindow (selected-window))) | |
1765 | ; (select-window (posn-window (event-start event))) | |
1766 | ; (if (and (one-window-p t 'selected-frame) | |
1767 | ; (window-dedicated-p (selected-window))) | |
1768 | ; ;; This is a special buffer's frame | |
1769 | ; (iconify-frame (selected-frame)) | |
1770 | ; (or (window-dedicated-p (selected-window)) | |
1771 | ; (bury-buffer))) | |
1772 | ; (select-window owindow)) | |
1773 | (quail-delete-region) | |
1774 | (quail-choose-completion-string choice buffer base-size) | |
1775 | (quail-terminate-translation))) | |
1776 | ||
1777 | ;; Modify the simple.el function `choose-completion-string', because | |
1778 | ;; the simple.el function `choose-completion-delete-max-match' breaks | |
1779 | ;; on Mule data, since the semantics of `forward-char' have changed. | |
1780 | ||
1781 | (defun quail-choose-completion-string (choice &optional buffer base-size) | |
1782 | (let ((buffer (or buffer completion-reference-buffer))) | |
1783 | ;; If BUFFER is a minibuffer, barf unless it's the currently | |
1784 | ;; active minibuffer. | |
1785 | (if (and (string-match "\\` \\*Minibuf-[0-9]+\\*\\'" (buffer-name buffer)) | |
1786 | (or (not (active-minibuffer-window)) | |
1787 | (not (equal buffer | |
1788 | (window-buffer (active-minibuffer-window)))))) | |
b58fc490 | 1789 | (quail-error "Minibuffer is not active for completion") |
2d4e1e6e KH |
1790 | ;; Store the completion in `quail-current-str', which will later |
1791 | ;; be converted to a character event list, then inserted into | |
1792 | ;; the buffer where completion was requested. | |
5611ce7c KH |
1793 | (set-buffer buffer) |
1794 | ; (if base-size | |
1795 | ; (delete-region (+ base-size (point-min)) (point)) | |
1796 | ; (choose-completion-delete-max-match choice)) | |
2d4e1e6e | 1797 | (setq quail-current-str choice) |
5611ce7c KH |
1798 | ;; Update point in the window that BUFFER is showing in. |
1799 | (let ((window (get-buffer-window buffer t))) | |
1800 | (set-window-point window (point))) | |
1801 | ;; If completing for the minibuffer, exit it with this choice. | |
1802 | (and (not completion-no-auto-exit) | |
1803 | (equal buffer (window-buffer (minibuffer-window))) | |
1804 | minibuffer-completion-table | |
1805 | ;; If this is reading a file name, and the file name chosen | |
1806 | ;; is a directory, don't exit the minibuffer. | |
1807 | (if (and (eq minibuffer-completion-table 'read-file-name-internal) | |
1808 | (file-directory-p (buffer-string))) | |
1809 | (select-window (active-minibuffer-window)) | |
1810 | (exit-minibuffer)))))) | |
4ed46869 KH |
1811 | |
1812 | (defun quail-help () | |
1813 | "Show brief description of the current Quail package." | |
1814 | (interactive) | |
9a6428f8 KH |
1815 | (let ((package quail-current-package)) |
1816 | (with-output-to-temp-buffer "*Quail-Help*" | |
1817 | (save-excursion | |
1818 | (set-buffer standard-output) | |
1819 | (let ((quail-current-package package)) | |
1820 | (insert "Quail input method (name:" | |
1821 | (quail-name) | |
1822 | ", mode line indicator:[" | |
1823 | (quail-title) | |
1824 | "])\n---- Documentation ----\n" | |
1825 | (quail-docstring)) | |
1826 | (newline) | |
1827 | (if (quail-show-layout) (quail-show-kbd-layout)) | |
9a6428f8 KH |
1828 | (quail-help-insert-keymap-description |
1829 | (quail-translation-keymap) | |
1830 | "--- Key bindings (while translating) --- | |
4ed46869 KH |
1831 | key binding |
1832 | --- -------\n") | |
9a6428f8 KH |
1833 | (if (quail-conversion-keymap) |
1834 | (quail-help-insert-keymap-description | |
1835 | (quail-conversion-keymap) | |
1836 | "--- Key bindings (while converting) --- | |
4ed46869 KH |
1837 | key binding |
1838 | --- -------\n")) | |
9a6428f8 KH |
1839 | (help-mode)))))) |
1840 | ||
4ed46869 KH |
1841 | (defun quail-help-insert-keymap-description (keymap &optional header) |
1842 | (let (from to) | |
1843 | (if header | |
1844 | (insert header)) | |
1845 | (save-excursion | |
1846 | (save-window-excursion | |
20110571 | 1847 | (let ((overriding-terminal-local-map keymap)) |
4ed46869 KH |
1848 | (describe-bindings)) |
1849 | (set-buffer "*Help*") | |
1850 | (goto-char (point-min)) | |
1851 | (forward-line 4) | |
1852 | (setq from (point)) | |
1853 | (search-forward "Global Bindings:" nil 'move) | |
1854 | (beginning-of-line) | |
1855 | (setq to (point)))) | |
1856 | (insert-buffer-substring "*Help*" from to))) | |
1857 | ||
1858 | (defun quail-show-kbd-layout () | |
1859 | "Show keyboard layout with key tops of multilingual characters." | |
1860 | (insert "--- Keyboard layout ---\n") | |
1861 | (let* ((i 0) ch) | |
1862 | (while (< i quail-keyboard-layout-len) | |
1863 | (if (= (% i 30) 0) | |
1864 | (progn | |
1865 | (newline) | |
1866 | (indent-to (/ i 30))) | |
1867 | (if (= (% i 2) 0) | |
1868 | (insert " "))) | |
1869 | (setq ch (aref quail-keyboard-layout i)) | |
50b190e4 KH |
1870 | (when (and (quail-kbd-translate) |
1871 | (/= ch ?\ )) | |
1872 | ;; This is the case that the current input method simulates | |
1873 | ;; some keyboard layout (which means it requires keyboard | |
1874 | ;; translation) and a key at location `i' exists on users | |
1875 | ;; keyboard. We must translate that key by | |
1876 | ;; `quail-keyboard-layout-standard'. But if if there's no | |
1877 | ;; corresponding key in that standard layout, we must simulate | |
1878 | ;; what is inserted if that key is pressed by setting CH a | |
1879 | ;; minus value. | |
1880 | (setq ch (aref quail-keyboard-layout-standard i)) | |
1881 | (if (= ch ?\ ) | |
1882 | (setq ch (- (aref quail-keyboard-layout i))))) | |
1883 | (if (< ch 0) | |
1884 | (let ((last-command-event (- ch))) | |
1885 | (self-insert-command 1)) | |
1886 | (if (= ch ?\ ) | |
1887 | (insert ch) | |
1888 | (let* ((map (cdr (assq ch (cdr (quail-map))))) | |
1889 | (translation (and map (quail-get-translation | |
1890 | (car map) (char-to-string ch) 1)))) | |
1891 | (if (integerp translation) | |
1892 | (insert translation) | |
1893 | (if (consp translation) | |
f9222bef | 1894 | (insert (aref (cdr translation) (car (car translation)))) |
50b190e4 KH |
1895 | (let ((last-command-event ch)) |
1896 | (self-insert-command 1))))))) | |
4ed46869 KH |
1897 | (setq i (1+ i)))) |
1898 | (newline)) | |
1899 | ||
1900 | (defun quail-translation-help () | |
d91eafdf | 1901 | "Show help message while translating in Quail input method." |
4ed46869 | 1902 | (interactive) |
d91eafdf KH |
1903 | (if (not (eq this-command last-command)) |
1904 | (let (state-msg keymap) | |
1905 | (if (and quail-converting (= (length quail-current-key) 0)) | |
1906 | (setq state-msg | |
1907 | (format "Converting string %S by input method %S.\n" | |
1908 | quail-conversion-str (quail-name)) | |
1909 | keymap (quail-conversion-keymap)) | |
1910 | (setq state-msg | |
1911 | (format "Translating key sequence %S by input method %S.\n" | |
1912 | quail-current-key (quail-name)) | |
1913 | keymap (quail-translation-keymap))) | |
1914 | (with-output-to-temp-buffer "*Quail-Help*" | |
1915 | (save-excursion | |
1916 | (set-buffer standard-output) | |
1917 | (insert state-msg) | |
1918 | (quail-help-insert-keymap-description | |
1919 | keymap | |
1920 | "----------------------- | |
4ed46869 | 1921 | key binding |
d91eafdf KH |
1922 | --- -------\n") |
1923 | (help-mode))))) | |
1924 | (let (scroll-help) | |
1925 | (save-selected-window | |
1926 | (select-window (get-buffer-window "*Quail-Help*")) | |
1927 | (if (eq this-command last-command) | |
1928 | (if (< (window-end) (point-max)) | |
1929 | (scroll-up) | |
1930 | (if (> (window-start) (point-min)) | |
1931 | (set-window-start (selected-window) (point-min))))) | |
1932 | (setq scroll-help | |
1933 | (if (< (window-end (selected-window) 'up-to-date) (point-max)) | |
1934 | "Type \\[quail-translation-help] to scroll up the help" | |
1935 | (if (> (window-start) (point-min)) | |
1936 | "Type \\[quail-translation-help] to see the head of help")))) | |
1937 | (if scroll-help | |
1938 | (progn | |
1939 | (message "%s" (substitute-command-keys scroll-help)) | |
1940 | (sit-for 1) | |
1941 | (message nil) | |
1942 | (quail-update-guidance) | |
1943 | )))) | |
4ed46869 | 1944 | |
ff913e92 KH |
1945 | \f |
1946 | (defvar quail-directory-name "quail" | |
cd30a521 | 1947 | "Name of Quail directory which contains Quail packages. |
ff913e92 KH |
1948 | This is a sub-directory of LEIM directory.") |
1949 | ||
1950 | ;;;###autoload | |
70fd2661 KH |
1951 | (defun quail-update-leim-list-file (dirname &rest dirnames) |
1952 | "Update entries for Quail packages in `LEIM' list file in directory DIRNAME. | |
1953 | DIRNAME is a directory containing Emacs input methods; | |
8cbe9074 | 1954 | normally, it should specify the `leim' subdirectory |
70fd2661 KH |
1955 | of the Emacs source tree. |
1956 | ||
1957 | It searches for Quail packages under `quail' subdirectory of DIRNAME, | |
1958 | and update the file \"leim-list.el\" in DIRNAME. | |
ff913e92 | 1959 | |
70fd2661 KH |
1960 | When called from a program, the remaining arguments are additional |
1961 | directory names to search for Quail packages under `quail' subdirectory | |
1962 | of each directory." | |
1963 | (interactive "FDirectory of LEIM: ") | |
1964 | (setq dirname (expand-file-name dirname)) | |
1965 | (let ((leim-list (expand-file-name leim-list-file-name dirname)) | |
1966 | quail-dirs list-buf pkg-list pkg-buf pos) | |
1967 | (if (not (file-writable-p leim-list)) | |
1968 | (error "Can't write to file \"%s\"" leim-list)) | |
1969 | (message "Updating %s ..." leim-list) | |
1970 | (setq list-buf (find-file-noselect leim-list)) | |
1971 | ||
1972 | ;; At first, clean up the file. | |
1973 | (save-excursion | |
1974 | (set-buffer list-buf) | |
1975 | (goto-char 1) | |
1976 | ||
1977 | ;; Insert the correct header. | |
1978 | (if (looking-at (regexp-quote leim-list-header)) | |
1979 | (goto-char (match-end 0)) | |
1980 | (insert leim-list-header)) | |
1981 | (setq pos (point)) | |
1982 | (if (not (re-search-forward leim-list-entry-regexp nil t)) | |
1983 | nil | |
1984 | ||
1985 | ;; Remove garbages after the header. | |
1986 | (goto-char (match-beginning 0)) | |
1987 | (if (< pos (point)) | |
1988 | (delete-region pos (point))) | |
1989 | ||
1990 | ;; Remove all entries for Quail. | |
1991 | (while (re-search-forward leim-list-entry-regexp nil 'move) | |
1992 | (goto-char (match-beginning 0)) | |
1993 | (setq pos (point)) | |
1994 | (condition-case nil | |
1995 | (let ((form (read list-buf))) | |
1996 | (when (equal (nth 3 form) ''quail-use-package) | |
1997 | (if (eolp) (forward-line 1)) | |
1998 | (delete-region pos (point)))) | |
1999 | (error | |
2000 | ;; Delete the remaining contents because it seems that | |
2001 | ;; this file is broken. | |
4be9beaf | 2002 | (message "Garbage in %s deleted" leim-list) |
70fd2661 KH |
2003 | (delete-region pos (point-max))))))) |
2004 | ||
cd30a521 | 2005 | ;; Search for `quail' subdirectory under each DIRNAMES. |
70fd2661 KH |
2006 | (setq dirnames (cons dirname dirnames)) |
2007 | (let ((l dirnames)) | |
2008 | (while l | |
2009 | (setcar l (expand-file-name (car l))) | |
2010 | (setq dirname (expand-file-name quail-directory-name (car l))) | |
2011 | (if (file-readable-p dirname) | |
2012 | (setq quail-dirs (cons dirname quail-dirs)) | |
4be9beaf | 2013 | (message "%s doesn't have `%s' subdirectory, just ignored" |
70fd2661 KH |
2014 | (car l) quail-directory-name) |
2015 | (setq quail-dirs (cons nil quail-dirs))) | |
2016 | (setq l (cdr l))) | |
2017 | (setq quail-dirs (nreverse quail-dirs))) | |
2018 | ||
2019 | ;; Insert input method registering forms. | |
2020 | (while quail-dirs | |
2021 | (setq dirname (car quail-dirs)) | |
2022 | (when dirname | |
2023 | (setq pkg-list (directory-files dirname 'full "\\.el$" 'nosort)) | |
2024 | (while pkg-list | |
2025 | (message "Checking %s ..." (car pkg-list)) | |
2026 | (with-temp-buffer | |
2027 | (insert-file-contents (car pkg-list)) | |
2028 | (goto-char (point-min)) | |
2029 | (while (search-forward "(quail-define-package" nil t) | |
ff913e92 | 2030 | (goto-char (match-beginning 0)) |
70fd2661 KH |
2031 | (condition-case nil |
2032 | (let ((form (read (current-buffer)))) | |
2033 | (save-excursion | |
2034 | (set-buffer list-buf) | |
2035 | (insert | |
2036 | (format "(register-input-method | |
ff913e92 KH |
2037 | %S %S '%s |
2038 | %S %S | |
8cbe9074 | 2039 | %S)\n" |
70fd2661 KH |
2040 | (nth 1 form) ; PACKAGE-NAME |
2041 | (nth 2 form) ; LANGUAGE | |
2042 | 'quail-use-package ; ACTIVATE-FUNC | |
2043 | (nth 3 form) ; PACKAGE-TITLE | |
2044 | (progn ; PACKAGE-DESCRIPTION (one line) | |
2045 | (string-match ".*" (nth 5 form)) | |
2046 | (match-string 0 (nth 5 form))) | |
2047 | (file-relative-name ; PACKAGE-FILENAME | |
2048 | (file-name-sans-extension (car pkg-list)) | |
2049 | (car dirnames)))))) | |
2050 | (error | |
2051 | ;; Ignore the remaining contents of this file. | |
2052 | (goto-char (point-max)) | |
2053 | (message "Some part of \"%s\" is broken" dirname))))) | |
2054 | (setq pkg-list (cdr pkg-list))) | |
2055 | (setq quail-dirs (cdr quail-dirs) dirnames (cdr dirnames)))) | |
2056 | ||
2057 | ;; At last, write out LEIM list file. | |
2058 | (save-excursion | |
2059 | (set-buffer list-buf) | |
2060 | (setq buffer-file-coding-system 'iso-2022-7bit) | |
2061 | (save-buffer 0)) | |
2062 | (kill-buffer list-buf) | |
2063 | (message "Updating %s ... done" leim-list))) | |
4ed46869 KH |
2064 | ;; |
2065 | (provide 'quail) | |
2066 | ||
2067 | ;;; quail.el ends here |