(tags-loop-revert-buffers): New variable.
[bpt/emacs.git] / lisp / international / quail.el
CommitLineData
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
52See 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.
89Indices is a list of (CURRENT START END BLOCK BLOCKS), where
90CURRENT is an index of the current translation,
91START and END are indices of the start and end of the current block,
92BLOCK is the current block index,
93BLOCKS 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.
98When a key sequence is mapped to TRANS and TRANS is a cons
cd30a521 99of actual translation and some Lisp object to be referred
ff913e92
KH
100for translating the longer key sequence, this variable is set
101to 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.
108A 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
114QUAIL-MAP is a data structure to map key strings to translations. For
115the format, see the documentation of `quail-map-p'.
116
117DECODE-MAP is an alist of translations and corresponding keys.
118
119See 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.
134See 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.
141Translation 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.
145See 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.
149See 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.
153See 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.
157See 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.
161It 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.
165See 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.
175Conversion 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.
205The 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
219The most common case is that you have not yet installed appropriate
220libraries in LEIM (Libraries of Emacs Input Method) which is
221distributed separately from Emacs.
222
4ed46869 223LEIM 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.
267Only a few especially complex input methods use this map;
268most use `quail-simple-translation-keymap' instead.
269This 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 288A few especially complex input methods use `quail-translation-keymap' instead.
4ed46869
KH
289This 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 313This map is activated while conversion region is active but translation
4ed46869
KH
314region 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.
325TITLE is a string to be displayed at mode-line to indicate this package.
d91eafdf 326Optional 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
331GUIDANCE specifies how a guidance string is shown in echo area.
332If it is t, list of all possible translations for the current key is shown
333 with the currently selected translation being highlighted.
334If 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.
337If it is nil, the current key is shown.
338
339DOCSTRING is the documentation string of this package.
340
341TRANSLATION-KEYS specifies additional key bindings used while translation
342region is active. It is an alist of single key character vs. corresponding
343command to be called.
344
345FORGET-LAST-SELECTION non-nil means a selected translation is not kept
346for the future to translate the same key. If this flag is nil, a
347translation selected for a key is remembered so that it can be the
348first candidate when the same key is entered later.
349
350DETERMINISTIC non-nil means the first candidate of translation is
351selected automatically without allowing users to select another
352translation for a key. In this case, unselected translations are of
353no use for an interactive use of Quail but can be used by some other
354programs. If this flag is non-nil, FORGET-LAST-SELECTION is also set
355to t.
356
357KBD-TRANSLATE non-nil means input characters are translated from a
358user's keyboard layout to the standard keyboard layout. See the
359documentation of `quail-keyboard-layout' and
360`quail-keyboard-layout-standard' for more detail.
361
362SHOW-LAYOUT non-nil means the `quail-help' command should show
363the user's keyboard layout visually with translated characters.
364If KBD-TRANSLATE is set, it is desirable to set also this flag unless
365this package defines no translations for single character keys.
366
367CREATE-DECODE-MAP non-nil means decode map is also created. A decode
368map is an alist of translations and corresponding original keys.
369Although this map is not used by Quail itself, it can be used by some
370other programs. For instance, Vietnamese supporting needs this map to
371convert Vietnamese text to VIQR format which uses only ASCII
372characters to represent Vietnamese characters.
373
374MAXIMUM-SHORTEST non-nil means break key sequence to get maximum
375length of the shortest sequence. When we don't have a translation of
376key \"..ABCD\" but have translations of \"..AB\" and \"CD..\", break
377the key at \"..AB\" and start translation of \"CD..\". Hangul
378packages, for instance, use this facility. If this flag is nil, we
379break the key just at \"..ABC\" and start translation of \"D..\".
380
381OVERLAY-PLIST if non-nil is a property list put on an overlay which
382covers Quail translation region.
383
384UPDATE-TRANSLATION-FUNCTION if non-nil is a function to call to update
cd30a521
KH
385the current translation region according to a new translation data. By
386default, a translated text or a user's key sequence (if no translation
4ed46869
KH
387for it) is inserted.
388
389CONVERSION-KEYS specifies additional key bindings used while
390conversion region is active. It is an alist of single key character
57a54470
RS
391vs. corresponding command to be called.
392
393If SIMPLE is non-nil, then we do not alter the meanings of
394commands such as C-f, C-b, C-n, C-p and TAB; they are treated as
395non-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.
473With arg, activate Quail input method if and only if arg is positive.
474
475While 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.
534See the documentation of `quail-keyboard-layout' for this format.
535This 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
541We 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
548Nth (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
550The location of Nth character is row (N / 30) and column ((N mod 30) / 2).
551The 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.
575See 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
582Since some Quail packages depends on a physical layout of keys (not
583characters generated by them), those are created by assuming the
584standard layout defined in `quail-keyboard-layout-standard'. This
585function tells Quail system the layout of your keyboard so that what
586you 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
628A Quail map holds information how a particular key should be translated.
629Its format is (TRANSLATION . ALIST).
630TRANSLATION is either a character, or a cons (INDEX . VECTOR).
631In the latter case, each element of VECTOR is a candidate for the translation,
632and INDEX points the currently selected translation.
633
634ALIST is normally a list of elements that look like (CHAR . DEFN),
635where DEFN is another Quail map for a longer key (CHAR added to the
636current key). It may also be a symbol of a function which returns an
637alist of the above format.
638
639Just after a Quail package is read, TRANSLATION may be a string or a
640vector. Then each element of the string or vector is a candidate for
641the translation. These objects are transformed to cons cells in the
642format \(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.
656Each argument is a list of KEY and TRANSLATION.
657KEY is a string meaning a sequence of keystrokes to be translated.
658TRANSLATION is a character, a string, a vector, a Quail map, or a function.
659It it is a character, it is the sole translation of KEY.
660If it is a string, each character is a candidate for the translation.
661If it is a vector, each element (string or character) is a candidate
662 for the translation.
663In these cases, a key specific Quail map is generated and assigned to KEY.
664
665If 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.
678The 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.
688KEY is a string meaning a sequence of keystrokes to be translated.
ff913e92 689TRANSLATION is a character, a string, a vector, a Quail map,
7d842556 690 a function, or a cons.
4ed46869
KH
691It it is a character, it is the sole translation of KEY.
692If it is a string, each character is a candidate for the translation.
693If it is a vector, each element (string or character) is a candidate
7d842556 694 for the translation.
ff913e92 695If 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
699In these cases, a key specific Quail map is generated and assigned to KEY.
700
701If TRANSLATION is a Quail map or a function symbol which returns a Quail map,
702 it is used to handle KEY.
7b5ebb00
KH
703
704Optional 3rd argument NAME, if specified, says which Quail package
4ed46869 705to define this translation rule in. The default is to define it in the
7b5ebb00
KH
706current Quail package.
707
708Optional 4th argument APPEND, if non-nil, appends TRANSLATION
709to 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
784The translation is either a character or a cons of the form (INDEX . VECTOR),
785where VECTOR is a vector of candidates (character or string) for
786the translation, and INDEX points into VECTOR to specify the currently
787selected 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.
822The 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.
1206Return t if we can terminate the translation.
1207Return nil if the current key sequence may be followed by more keys.
1208Return number if we can't find any translation for the current key
1209sequence. The number is the count of valid keys in the current
1210sequence 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.
1406Remaining 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 1457Create the buffer if it does not exist yet.
7d842556
KH
1458The buffer is normally displayed at the echo area,
1459but if the current buffer is a minibuffer, it is shown in
1460the bottom-most ordinary window of the same frame,
1461or 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.
1640All 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
1831key 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
1837key 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 1921key 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
1948This 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.
1953DIRNAME is a directory containing Emacs input methods;
8cbe9074 1954normally, it should specify the `leim' subdirectory
70fd2661
KH
1955of the Emacs source tree.
1956
1957It searches for Quail packages under `quail' subdirectory of DIRNAME,
1958and update the file \"leim-list.el\" in DIRNAME.
ff913e92 1959
70fd2661
KH
1960When called from a program, the remaining arguments are additional
1961directory names to search for Quail packages under `quail' subdirectory
1962of 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