(set-default-coding-systems): Set
[bpt/emacs.git] / lisp / international / mule-cmds.el
... / ...
CommitLineData
1;;; mule-cmds.el --- Commands for mulitilingual environment
2
3;; Copyright (C) 1995 Electrotechnical Laboratory, JAPAN.
4;; Licensed to the Free Software Foundation.
5
6;; Keywords: mule, multilingual
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
24
25;;; Code:
26
27;;; MULE related key bindings and menus.
28
29(defvar mule-keymap (make-sparse-keymap)
30 "Keymap for MULE (Multilingual environment) specific commands.")
31
32;; Keep "C-x C-m ..." for mule specific commands.
33(define-key ctl-x-map "\C-m" mule-keymap)
34
35(define-key mule-keymap "f" 'set-buffer-file-coding-system)
36(define-key mule-keymap "t" 'set-terminal-coding-system)
37(define-key mule-keymap "k" 'set-keyboard-coding-system)
38(define-key mule-keymap "p" 'set-buffer-process-coding-system)
39(define-key mule-keymap "\C-\\" 'set-input-method)
40(define-key mule-keymap "c" 'universal-coding-system-argument)
41(define-key mule-keymap "l" 'set-language-environment)
42
43(define-key help-map "\C-L" 'describe-language-environment)
44(define-key help-map "L" 'describe-language-environment)
45(define-key help-map "\C-\\" 'describe-input-method)
46(define-key help-map "I" 'describe-input-method)
47(define-key help-map "C" 'describe-coding-system)
48(define-key help-map "h" 'view-hello-file)
49
50(defvar mule-menu-keymap (make-sparse-keymap "Mule")
51 "Keymap for MULE (Multilingual environment) menu specific commands.")
52
53(define-key global-map [menu-bar mule] (cons "Mule" mule-menu-keymap))
54
55(setq menu-bar-final-items (cons 'mule menu-bar-final-items))
56
57(defvar describe-language-environment-map nil)
58(define-prefix-command 'describe-language-environment-map)
59
60(defvar setup-language-environment-map nil)
61(define-prefix-command 'setup-language-environment-map)
62
63(defvar set-coding-system-map nil)
64(define-prefix-command 'set-coding-system-map)
65
66(define-key-after mule-menu-keymap [describe-language-environment]
67 '("Describe Language Environment" . describe-language-environment-map)
68 t)
69(define-key-after mule-menu-keymap [set-language-environment]
70 '("Set Language Environment" . setup-language-environment-map)
71 t)
72(define-key-after mule-menu-keymap [mouse-set-font]
73 '("Set Font/Fontset" . mouse-set-font)
74 t)
75(define-key-after mule-menu-keymap [separator-mule]
76 '("--")
77 t)
78(define-key-after mule-menu-keymap [toggle-input-method]
79 '("Toggle Input Method" . toggle-input-method)
80 t)
81(define-key-after mule-menu-keymap [set-input-method]
82 '("Select Input Method" . set-input-method)
83 t)
84(define-key-after mule-menu-keymap [describe-input-method]
85 '("Describe Input Method" . describe-input-method)
86 t)
87(define-key-after mule-menu-keymap [separator-input-method]
88 '("--")
89 t)
90(define-key-after mule-menu-keymap [describe-coding-system]
91 '("Describe Coding Systems" . describe-coding-system)
92 t)
93(define-key-after mule-menu-keymap [set-various-coding-system]
94 '("Set Coding System" . set-coding-system-map)
95 t)
96(define-key-after mule-menu-keymap [separator-coding-system]
97 '("--")
98 t)
99(define-key-after mule-menu-keymap [mule-diag]
100 '("Show All of MULE Status" . mule-diag)
101 t)
102(define-key-after mule-menu-keymap [view-hello-file]
103 '("Show Script Examples" . view-hello-file)
104 t)
105
106(define-key-after set-coding-system-map [set-buffer-file-coding-system]
107 '("Buffer File" . set-buffer-file-coding-system)
108 t)
109(define-key-after set-coding-system-map [universal-coding-system-argument]
110 '("Next Command" . universal-coding-system-argument)
111 t)
112(define-key-after set-coding-system-map [set-terminal-coding-system]
113 '("Terminal" . set-terminal-coding-system)
114 t)
115(define-key-after set-coding-system-map [set-keyboard-coding-system]
116 '("Keyboard" . set-keyboard-coding-system)
117 t)
118(define-key-after set-coding-system-map [set-buffer-process-coding-system]
119 '("Buffer Process" . set-buffer-process-coding-system)
120 t)
121
122(define-key setup-language-environment-map
123 [Default] '("Default" . setup-specified-language-environment))
124
125;; These are meaningless when running under X.
126(put 'set-terminal-coding-system 'menu-enable
127 '(not (eq window-system 'x)))
128(put 'set-keyboard-coding-system 'menu-enable
129 '(not (eq window-system 'x)))
130;; This is meaningless when the current buffer has no process.
131(put 'set-buffer-process-coding-system 'menu-enable
132 '(get-buffer-process (current-buffer)))
133
134;; This should be a single character key binding because users use it
135;; very frequently while editing multilingual text. Now we can use
136;; only two such keys: "\C-\\" and "\C-^", but the latter is not
137;; convenient because it requires shifting on most keyboards. An
138;; alternative is "\C-\]" which is now bound to `abort-recursive-edit'
139;; but it won't be used that frequently.
140(define-key global-map "\C-\\" 'toggle-input-method)
141
142;;; This is no good because people often type Shift-SPC
143;;; meaning to type SPC. -- rms.
144;;; ;; Here's an alternative key binding for X users (Shift-SPACE).
145;;; (define-key global-map [?\S- ] 'toggle-input-method)
146
147(defun toggle-enable-multibyte-characters (&optional arg)
148 "Change whether this buffer uses multibyte characters.
149With arg, use multibyte characters if the arg is positive.
150
151Note that this command does not convert the byte contents of
152the buffer; it only changes the way those bytes are interpreted.
153In general, therefore, this command *changes* the sequence of
154characters that the current buffer contains.
155
156We suggest you avoid using use this command unless you know what you
157are doing. If you use it by mistake, and the buffer is now displayed
158wrong, use this command again to toggle back to the right mode."
159 (interactive "P")
160 (let ((new-flag
161 (if (null arg) (null enable-multibyte-characters)
162 (> (prefix-numeric-value arg) 0))))
163 (set-buffer-multibyte new-flag))
164 (force-mode-line-update))
165
166(defun view-hello-file ()
167 "Display the HELLO file which list up many languages and characters."
168 (interactive)
169 ;; We have to decode the file in any environment.
170 (let ((default-enable-multibyte-characters t)
171 (coding-system-for-read 'iso-2022-7bit))
172 (find-file-read-only (expand-file-name "HELLO" data-directory))))
173
174(defun universal-coding-system-argument ()
175 "Execute an I/O command using the specified coding system."
176 (interactive)
177 (let* ((coding-system (read-coding-system "Coding system for following command: "))
178 (keyseq (read-key-sequence
179 (format "Command to execute with %s:" coding-system)))
180 (cmd (key-binding keyseq)))
181 (let ((coding-system-for-read coding-system)
182 (coding-system-for-write coding-system))
183 (message "")
184 (call-interactively cmd))))
185
186(defun set-default-coding-systems (coding-system)
187 "Set default value of various coding systems to CODING-SYSTEM.
188This sets the following coding systems:
189 o coding system of a newly created buffer
190 o default coding system for subprocess I/O
191This also sets the following values:
192 o default value used as file-name-coding-system for converting file names.
193 o default value for the command `set-terminal-coding-system'
194 o default value for the command `set-keyboard-coding-system'"
195 (check-coding-system coding-system)
196 (setq-default buffer-file-coding-system coding-system)
197 (setq default-file-name-coding-system coding-system)
198 (setq default-terminal-coding-system coding-system)
199 (setq default-keyboard-coding-system coding-system)
200 (setq default-process-coding-system (cons coding-system coding-system)))
201
202(defun prefer-coding-system (coding-system)
203 "Add CODING-SYSTEM at the front of the priority list for automatic detection.
204This also sets the following coding systems:
205 o coding system of a newly created buffer
206 o default coding system for subprocess I/O
207This also sets the following values:
208 o default value used as file-name-coding-system for converting file names.
209 o default value for the command `set-terminal-coding-system'
210 o default value for the command `set-keyboard-coding-system'"
211 (interactive "zPrefer coding system: ")
212 (if (not (and coding-system (coding-system-p coding-system)))
213 (error "Invalid coding system `%s'" coding-system))
214 (let ((coding-category (coding-system-category coding-system))
215 (base (coding-system-base coding-system)))
216 (if (not coding-category)
217 ;; CODING-SYSTEM is no-conversion or undecided.
218 (error "Can't prefer the coding system `%s'" coding-system))
219 (set coding-category (or base coding-system))
220 (update-iso-coding-systems)
221 (if (not (eq coding-category (car coding-category-list)))
222 ;; We must change the order.
223 (setq coding-category-list
224 (cons coding-category
225 (delq coding-category coding-category-list))))
226 (if (and base (interactive-p))
227 (message "Highest priority is set to %s (base of %s)"
228 base coding-system))
229 (set-default-coding-systems (or base coding-system))))
230
231(defun find-safe-coding-system-list-subset-p (list1 list2)
232 "Return non-nil if all elements in LIST1 are included in LIST2.
233Comparison done with EQ."
234 (catch 'tag
235 (while list1
236 (or (memq (car list1) list2)
237 (throw 'tag nil))
238 (setq list1 (cdr list1)))
239 t))
240
241(defun find-safe-coding-system (from to)
242 "Return a list of proper coding systems to encode a text between FROM and TO.
243All coding systems in the list can safely encode any multibyte characters
244in the text.
245
246If the text contains no multibyte charcters, return a list of a single
247element `undecided'.
248
249Kludgy feature: if FROM is a string, the string is the target text,
250and TO is ignored."
251 (let ((charset-list (if (stringp from) (find-charset-string from)
252 (find-charset-region from to))))
253 (if (or (null charset-list)
254 (and (= (length charset-list) 1)
255 (eq 'ascii (car charset-list))))
256 '(undecided)
257 (let ((l coding-system-list)
258 (prefered-codings
259 (mapcar (function
260 (lambda (x)
261 (get-charset-property x 'prefered-coding-system)))
262 charset-list))
263 codings coding safe)
264 (while l
265 (setq coding (car l) l (cdr l))
266 (if (and (eq coding (coding-system-base coding))
267 (setq safe (coding-system-get coding 'safe-charsets))
268 (or (eq safe t)
269 (find-safe-coding-system-list-subset-p
270 charset-list safe)))
271 ;; We put the higher priority to coding systems included
272 ;; in PREFERED-CODINGS, and within them, put the higher
273 ;; priority to coding systems which support smaller
274 ;; number of charsets.
275 (let ((priority
276 (logior (if (coding-system-get coding 'mime-charset)
277 256 0)
278 (if (memq coding prefered-codings) 128 0)
279 (if (> (coding-system-type coding) 0) 64 0)
280 (if (consp safe) (- 64 (length safe)) 0))))
281 (setq codings (cons (cons priority coding) codings)))))
282 (mapcar 'cdr
283 (sort codings (function (lambda (x y) (> (car x) (car y))))))
284 ))))
285
286(defun select-safe-coding-system (from to &optional default-coding-system)
287 "Ask a user to select a safe coding system from candidates.
288The candidates of coding systems which can safely encode a text
289between FROM and TO are shown in a popup window.
290
291Optional arg DEFAULT-CODING-SYSTEM specifies a coding system to be
292checked at first. If omitted, buffer-file-coding-system of the
293current buffer is used.
294
295If the text can be encoded safely by DEFAULT-CODING-SYSTEM, it is
296returned without any user interaction.
297
298Kludgy feature: if FROM is a string, the string is the target text,
299and TO is ignored."
300 (or default-coding-system
301 (setq default-coding-system buffer-file-coding-system))
302 (let ((safe-coding-systems (find-safe-coding-system from to)))
303 (if (or (eq (car safe-coding-systems) 'undecided)
304 (and default-coding-system
305 (memq (coding-system-base default-coding-system)
306 safe-coding-systems)))
307 default-coding-system
308
309 ;; Ask a user to select a proper coding system.
310 (save-window-excursion
311 ;; At first, show a helpful message.
312 (with-output-to-temp-buffer "*Warning*"
313 (save-excursion
314 (set-buffer standard-output)
315 (insert (format "\
316The target text contains a multibyte character which can't be
317encoded safely by the coding system %s.
318
319Please select one from the following safe coding systems:\n"
320 default-coding-system))
321 (let ((pos (point))
322 (fill-prefix " "))
323 (mapcar (function (lambda (x) (princ " ") (princ x)))
324 safe-coding-systems)
325 (fill-region-as-paragraph pos (point)))))
326
327 ;; Read a coding system.
328 (let* ((safe-names (mapcar (lambda (x) (list (symbol-name x)))
329 safe-coding-systems))
330 (name (completing-read
331 (format "Select coding system (default %s): "
332 (car safe-coding-systems))
333 safe-names nil t nil nil (car (car safe-names)))))
334 (kill-buffer "*Warning*")
335 (intern name))))))
336
337(setq select-safe-coding-system-function 'select-safe-coding-system)
338
339\f
340;;; Language support staffs.
341
342(defvar language-info-alist nil
343 "Alist of language names vs the corresponding information of various kind.
344Each element looks like:
345 (LANGUAGE-NAME . ((KEY . INFO) ...))
346where LANGUAGE-NAME is a string,
347KEY is a symbol denoting the kind of information,
348INFO is any Lisp object which contains the actual information related
349to KEY.")
350
351(defun get-language-info (language-name key)
352 "Return the information for LANGUAGE-NAME of the kind KEY.
353KEY is a symbol denoting the kind of required information."
354 (if (symbolp language-name)
355 (setq language-name (symbol-name language-name)))
356 (let ((lang-slot (assoc-ignore-case language-name language-info-alist)))
357 (if lang-slot
358 (cdr (assq key (cdr lang-slot))))))
359
360(defun set-language-info (language-name key info
361 &optional describe-map setup-map)
362 "Set for LANGUAGE-NAME the information INFO under KEY.
363KEY is a symbol denoting the kind of information.
364INFO is any Lisp object which contains the actual information specific
365 to LANGUAGE-NAME.
366
367Currently, the following KEYs are used by Emacs:
368
369charset: list of charsets.
370
371coding-system: list of coding systems.
372
373coding-priority: list of coding systems ordered by priority.
374
375tutorial: a tutorial file name written in the language.
376
377sample-text: one line short text containing characters of the language.
378
379documentation: t or a string describing how Emacs supports the language.
380 If a string is specified, it is shown before any other information
381 of the language by the command `describe-language-environment'.
382
383setup-function: a function to call for setting up environment
384 convenient for a user of the language.
385
386We will define more KEYs in the future. To avoid conflict,
387if you want to use your own KEY values, make them start with `user-'.
388
389Optional 4th and 5th args DESCRIBE-MAP and SETUP-MAP are keymaps to
390register LANGUAGE-NAME in the menu of `Mule'->`Describe Language
391Environment' and `Mule'->`Setup Language Environment' respectively."
392 (if (symbolp language-name)
393 (setq language-name (symbol-name language-name)))
394 (let (lang-slot key-slot)
395 (setq lang-slot (assoc language-name language-info-alist))
396 (if (null lang-slot) ; If no slot for the language, add it.
397 (setq lang-slot (list language-name)
398 language-info-alist (cons lang-slot language-info-alist)))
399 (setq key-slot (assq key lang-slot))
400 (if (null key-slot) ; If no slot for the key, add it.
401 (progn
402 (setq key-slot (list key))
403 (setcdr lang-slot (cons key-slot (cdr lang-slot)))))
404 ;; Setup menu.
405 (cond ((eq key 'documentation)
406 (define-key-after describe-map (vector (intern language-name))
407 (cons language-name 'describe-specified-language-support) t))
408 ((eq key 'setup-function)
409 (define-key-after setup-map (vector (intern language-name))
410 (cons language-name 'setup-specified-language-environment) t)))
411
412 (setcdr key-slot info)
413 ))
414
415(defun set-language-info-alist (language-name alist &optional parents)
416 "Set for LANGUAGE-NAME the information in ALIST.
417ALIST is an alist of KEY and INFO. See the documentation of
418`set-langauge-info' for the meanings of KEY and INFO.
419
420Optional arg PARENTS is a list of parent language environments ordered
421from the highest to the lower. If it is nil, we make LANGUAGE-NAME
422the top level language environment."
423 (if (symbolp language-name)
424 (setq language-name (symbol-name language-name)))
425 (let ((describe-map describe-language-environment-map)
426 (setup-map setup-language-environment-map))
427 (if parents
428 (let ((l parents)
429 map parent-symbol parent)
430 (while l
431 (if (symbolp (setq parent-symbol (car l)))
432 (setq parent (symbol-name parent))
433 (setq parent parent-symbol parent-symbol (intern parent)))
434 (setq map (lookup-key describe-map (vector parent-symbol)))
435 (if (not map)
436 (progn
437 (setq map (intern (format "describe-%s-environment-map"
438 (downcase parent))))
439 (define-prefix-command map)
440 (define-key-after describe-map (vector parent-symbol)
441 (cons parent map) t)))
442 (setq describe-map (symbol-value map))
443 (setq map (lookup-key setup-map (vector parent-symbol)))
444 (if (not map)
445 (progn
446 (setq map (intern (format "setup-%s-environment-map"
447 (downcase parent))))
448 (define-prefix-command map)
449 (define-key-after setup-map (vector parent-symbol)
450 (cons parent map) t)))
451 (setq setup-map (symbol-value map))
452 (setq l (cdr l)))))
453 (while alist
454 (set-language-info language-name (car (car alist)) (cdr (car alist))
455 describe-map setup-map)
456 (setq alist (cdr alist)))))
457
458(defun read-language-name (key prompt &optional default)
459 "Read language name which has information for KEY, prompting with PROMPT.
460DEFAULT is the default choice of language.
461This returns a language name as a string."
462 (let* ((completion-ignore-case t)
463 (name (completing-read prompt
464 language-info-alist
465 (function (lambda (elm) (assq key elm)))
466 t nil nil default)))
467 (if (and (> (length name) 0)
468 (get-language-info name key))
469 name)))
470\f
471;;; Multilingual input methods.
472
473(defconst leim-list-file-name "leim-list.el"
474 "Name of LEIM list file.
475This file contains a list of libraries of Emacs input methods (LEIM)
476in the format of Lisp expression for registering each input method.
477Emacs loads this file at startup time.")
478
479(defvar leim-list-header (format "\
480;;; %s -- list of LEIM (Library of Emacs Input Method)
481;;
482;; This file contains a list of LEIM (Library of Emacs Input Method)
483;; in the same directory as this file. Loading this file registeres
484;; the whole input methods in Emacs.
485;;
486;; Each entry has the form:
487;; (register-input-method
488;; INPUT-METHOD LANGUAGE-NAME ACTIVATE-FUNC
489;; TITLE DESCRIPTION
490;; ARG ...)
491;; See the function `register-input-method' for the meanings of arguments.
492;;
493;; If this directory is included in load-path, Emacs automatically
494;; loads this file at startup time.
495
496"
497 leim-list-file-name)
498 "Header to be inserted in LEIM list file.")
499
500(defvar leim-list-entry-regexp "^(register-input-method"
501 "Regexp matching head of each entry in LEIM list file.
502See also the variable `leim-list-header'")
503
504(defvar update-leim-list-functions
505 '(quail-update-leim-list-file)
506 "List of functions to call to update LEIM list file.
507Each function is called with one arg, LEIM directory name.")
508
509(defun update-leim-list-file (&rest dirs)
510 "Update LEIM list file in directories DIRS."
511 (let ((functions update-leim-list-functions))
512 (while functions
513 (apply (car functions) dirs)
514 (setq functions (cdr functions)))))
515
516(defvar current-input-method nil
517 "The current input method for multilingual text.
518If nil, that means no input method is activated now.")
519(make-variable-buffer-local 'current-input-method)
520(put 'current-input-method 'permanent-local t)
521
522(defvar current-input-method-title nil
523 "Title string of the current input method shown in mode line.")
524(make-variable-buffer-local 'current-input-method-title)
525(put 'current-input-method-title 'permanent-local t)
526
527(defcustom default-input-method nil
528 "*Default input method for multilingual text.
529This is the input method activated automatically by the command
530`toggle-input-method' (\\[toggle-input-method])."
531 :group 'mule)
532
533(defvar input-method-history nil
534 "History list for some commands that read input methods.")
535(make-variable-buffer-local 'input-method-history)
536(put 'input-method-history 'permanent-local t)
537
538(defvar inactivate-current-input-method-function nil
539 "Function to call for inactivating the current input method.
540Every input method should set this to an appropriate value when activated.
541This function is called with no argument.
542
543This function should never change the value of `current-input-method'.
544It is set to nil by the function `inactivate-input-method'.")
545(make-variable-buffer-local 'inactivate-current-input-method-function)
546(put 'inactivate-current-input-method-function 'permanent-local t)
547
548(defvar describe-current-input-method-function nil
549 "Function to call for describing the current input method.
550This function is called with no argument.")
551(make-variable-buffer-local 'describe-current-input-method-function)
552(put 'describe-current-input-method-function 'permanent-local t)
553
554(defvar input-method-alist nil
555 "Alist of input method names vs the corresponding information to use it.
556Each element has the form:
557 (INPUT-METHOD LANGUAGE-NAME ACTIVATE-FUNC TITLE DESCRIPTION ...)
558See the function `register-input-method' for the meanings of each elements.")
559
560(defun register-input-method (input-method language-name &rest args)
561 "Register INPUT-METHOD as an input method for LANGUAGE-NAME.
562INPUT-METHOD and LANGUAGE-NAME are symbols or strings.
563The remaining arguments are:
564 ACTIVATE-FUNC, TITLE, DESCRIPTION, and ARG ...
565 where,
566ACTIVATE-FUNC is a function to call for activating this method.
567TITLE is a string shown in mode-line while this method is active,
568DESCRIPTION is a string describing about this method,
569Arguments to ACTIVATE-FUNC are INPUT-METHOD and ARGs."
570 (if (symbolp language-name)
571 (setq language-name (symbol-name language-name)))
572 (if (symbolp input-method)
573 (setq input-method (symbol-name input-method)))
574 (let ((info (cons language-name args))
575 (slot (assoc input-method input-method-alist)))
576 (if slot
577 (setcdr slot info)
578 (setq slot (cons input-method info))
579 (setq input-method-alist (cons slot input-method-alist)))))
580
581(defun read-input-method-name (prompt &optional default inhibit-null)
582 "Read a name of input method from a minibuffer prompting with PROMPT.
583If DEFAULT is non-nil, use that as the default,
584 and substitute it into PROMPT at the first `%s'.
585If INHIBIT-NULL is non-nil, null input signals an error.
586
587The return value is a string."
588 (if default
589 (setq prompt (format prompt default)))
590 (let* ((completion-ignore-case t)
591 ;; This binding is necessary because input-method-history is
592 ;; buffer local.
593 (input-method (completing-read prompt input-method-alist
594 nil t nil 'input-method-history
595 default)))
596 (if (> (length input-method) 0)
597 input-method
598 (if inhibit-null
599 (error "No valid input method is specified")))))
600
601(defun activate-input-method (input-method)
602 "Turn INPUT-METHOD on.
603If some input method is already on, turn it off at first."
604 (if (symbolp input-method)
605 (setq input-method (symbol-name input-method)))
606 (if (and current-input-method
607 (not (string= current-input-method input-method)))
608 (inactivate-input-method))
609 (unless current-input-method
610 (let ((slot (assoc input-method input-method-alist)))
611 (if (null slot)
612 (error "Can't activate input method `%s'" input-method))
613 (let ((func (nth 2 slot)))
614 (if (functionp func)
615 (apply (nth 2 slot) input-method (nthcdr 5 slot))
616 (if (and (consp func) (symbolp (car func)) (symbolp (cdr func)))
617 (progn
618 (require (cdr func))
619 (apply (car func) input-method (nthcdr 5 slot)))
620 (error "Can't activate input method `%s'" input-method))))
621 (setq current-input-method input-method)
622 (setq current-input-method-title (nth 3 slot))
623 (run-hooks 'input-method-activate-hook))))
624
625(defun inactivate-input-method ()
626 "Turn off the current input method."
627 (when current-input-method
628 (if input-method-history
629 (unless (string= current-input-method (car input-method-history))
630 (setq input-method-history
631 (cons current-input-method
632 (delete current-input-method input-method-history))))
633 (setq input-method-history (list current-input-method)))
634 (unwind-protect
635 (funcall inactivate-current-input-method-function)
636 (unwind-protect
637 (run-hooks 'input-method-inactivate-hook)
638 (setq current-input-method nil
639 current-input-method-title nil)))))
640
641(defun set-input-method (input-method)
642 "Select and turn on INPUT-METHOD.
643This sets the default input method to what you specify,
644and turn it on for the current buffer."
645 (interactive
646 (let* ((default (or (car input-method-history) default-input-method)))
647 (list (read-input-method-name
648 (if default "Select input method (default %s): " "Select input method: ")
649 default t))))
650 (activate-input-method input-method)
651 (setq default-input-method input-method))
652
653(defun toggle-input-method (&optional arg)
654 "Turn on or off a multilingual text input method for the current buffer.
655
656With arg, read an input method from minibuffer and turn it on.
657
658Without arg, if some input method is currently activated, turn it off,
659else turn on an input method selected last time
660or the default input method (see `default-input-method').
661
662When there's no input method to turn on, turn on what read from minibuffer."
663 (interactive "P")
664 (let* ((default (or (car input-method-history) default-input-method)))
665 (if (and current-input-method (not arg))
666 (inactivate-input-method)
667 (activate-input-method
668 (if (or arg (not default))
669 (read-input-method-name
670 (if default "Input method (default %s): " "Input method: " )
671 default t)
672 default))
673 (or default-input-method
674 (setq default-input-method current-input-method)))))
675
676(defun describe-input-method (input-method)
677 "Describe input method INPUT-METHOD."
678 (interactive
679 (list (read-input-method-name
680 "Describe input method (default, current choice): ")))
681 (if (and input-method (symbolp input-method))
682 (setq input-method (symbol-name input-method)))
683 (if (null input-method)
684 (describe-current-input-method)
685 (with-output-to-temp-buffer "*Help*"
686 (let ((elt (assoc input-method input-method-alist)))
687 (princ (format "Input method: %s (`%s' in mode line) for %s\n %s\n"
688 input-method (nth 3 elt) (nth 1 elt) (nth 4 elt)))))))
689
690(defun describe-current-input-method ()
691 "Describe the input method currently in use."
692 (if current-input-method
693 (if (and (symbolp describe-current-input-method-function)
694 (fboundp describe-current-input-method-function))
695 (funcall describe-current-input-method-function)
696 (message "No way to describe the current input method `%s'"
697 (cdr current-input-method))
698 (ding))
699 (error "No input method is activated now")))
700
701(defun read-multilingual-string (prompt &optional initial-input input-method)
702 "Read a multilingual string from minibuffer, prompting with string PROMPT.
703The input method selected last time is activated in minibuffer.
704If optional second arg INITIAL-INPUT is non-nil, insert it in the minibuffer
705initially.
706Optional 3rd argument INPUT-METHOD specifies the input method
707to be activated instead of the one selected last time. It is a symbol
708or a string."
709 (setq input-method
710 (or input-method
711 current-input-method
712 default-input-method
713 (read-input-method-name "Input method: " nil t)))
714 (if (and input-method (symbolp input-method))
715 (setq input-method (symbol-name input-method)))
716 (let ((previous-input-method current-input-method))
717 (unwind-protect
718 (progn
719 (activate-input-method input-method)
720 (read-string prompt initial-input nil nil t))
721 (if previous-input-method
722 (activate-input-method previous-input-method)
723 (inactivate-input-method)))))
724
725;; Variables to control behavior of input methods. All input methods
726;; should react to these variables.
727
728(defcustom input-method-verbose-flag 'default
729 "*A flag to control extra guidance given by input methods.
730The value should be nil, t, `complex-only', or `default'.
731
732The extra guidance is done by showing list of available keys in echo
733area. When you use the input method in the minibuffer, the guidance
734is shown at the bottom short window (split from the existing window).
735
736If the value is t, extra guidance is always given, if the value is
737nil, extra guidance is always suppressed.
738
739If the value is `complex-only', only complex input methods such as
740`chinese-py' and `japanese' give extra guidance.
741
742If the value is `default', complex input methods always give extra
743guidance, but simple input methods give it only when you are not in
744the minibuffer.
745
746See also the variable `input-method-highlight-flag'."
747 :type '(choice (const t) (const nil) (const complex-only) (const default))
748 :group 'mule)
749
750(defcustom input-method-highlight-flag t
751 "*If this flag is non-nil, input methods highlight partially-entered text.
752For instance, while you are in the middle of a Quail input method sequence,
753the text inserted so far is temporarily underlined.
754The underlining goes away when you finish or abort the input method sequence.
755See also the variable `input-method-verbose-flag'."
756 :type 'boolean
757 :group 'mule)
758
759(defvar input-method-activate-hook nil
760 "Normal hook run just after an input method is activated.
761
762The variable `current-input-method' keeps the input method name
763just activated.")
764
765(defvar input-method-inactivate-hook nil
766 "Normal hook run just after an input method is inactivated.
767
768The variable `current-input-method' still keeps the input method name
769just inactivated.")
770
771(defvar input-method-after-insert-chunk-hook nil
772 "Normal hook run just after an input method insert some chunk of text.")
773
774(defvar input-method-exit-on-invalid-key nil
775 "This flag controls the behaviour of an input method on invalid key input.
776Usually, when a user types a key which doesn't start any character
777handled by the input method, the key is handled by turning off the
778input method temporalily. After the key is handled, the input method is
779back on.
780But, if this flag is non-nil, the input method is never back on.")
781
782\f
783(defvar set-language-environment-hook nil
784 "Normal hook run after some language environment is set.
785
786When you set some hook function here, that effect usually should not
787be inherited to another language environment. So, you had better set
788another function in `exit-language-environment-hook' (which see) to
789cancel the effect.")
790
791(defvar exit-language-environment-hook nil
792 "Normal hook run after exiting from some language environment.
793When this hook is run, the variable `current-language-environment'
794is still bound to the language environment being exited.
795
796This hook is mainly used for cancelling the effect of
797`set-language-environment-hook' (which-see).")
798
799(defun setup-specified-language-environment ()
800 "Set up multi-lingual environment convenient for the specified language."
801 (interactive)
802 (let (language-name)
803 (if (and (symbolp last-command-event)
804 (or (not (eq last-command-event 'Default))
805 (setq last-command-event 'English))
806 (setq language-name (symbol-name last-command-event)))
807 (set-language-environment language-name)
808 (error "Bogus calling sequence"))))
809
810(defvar current-language-environment "English"
811 "The last language environment specified with `set-language-environment'.")
812
813(defun set-language-environment (language-name)
814 "Set up multi-lingual environment for using LANGUAGE-NAME.
815This sets the coding system priority and the default input method
816and sometimes other things."
817 (interactive (list (read-language-name
818 'setup-function
819 "Set language environment (default, English): ")))
820 (if language-name
821 (if (symbolp language-name)
822 (setq language-name (symbol-name language-name)))
823 (setq language-name "English"))
824 (if (null (get-language-info language-name 'setup-function))
825 (error "Language environment not defined: %S" language-name))
826 (if current-language-environment
827 (let ((func (get-language-info current-language-environment
828 'exit-function)))
829 (run-hooks 'exit-language-environment-hook)
830 (if (fboundp func) (funcall func))))
831 (setq current-language-environment language-name)
832 (funcall (get-language-info language-name 'setup-function))
833 (run-hooks 'set-language-environment-hook)
834 (force-mode-line-update t))
835
836(defun set-language-environment-coding-systems (language-name)
837 "Do various coding system setups for language environment LANGUAGE-NAME."
838 (let* ((priority (get-language-info language-name 'coding-priority))
839 (default-coding (car priority)))
840 (if priority
841 (let ((categories (mapcar 'coding-system-category priority)))
842 (set-default-coding-systems default-coding)
843 (set-coding-priority categories)
844 (while priority
845 (set (car categories) (car priority))
846 (setq priority (cdr priority) categories (cdr categories)))
847 (update-iso-coding-systems)))))
848
849;; Print all arguments with `princ', then print "\n".
850(defsubst princ-list (&rest args)
851 (while args (princ (car args)) (setq args (cdr args)))
852 (princ "\n"))
853
854;; Print a language specific information such as input methods,
855;; charsets, and coding systems. This function is intended to be
856;; called from the menu:
857;; [menu-bar mule describe-language-environment LANGUAGE]
858;; and should not run it by `M-x describe-current-input-method-function'.
859(defun describe-specified-language-support ()
860 "Describe how Emacs supports the specified language environment."
861 (interactive)
862 (let (language-name)
863 (if (not (and (symbolp last-command-event)
864 (setq language-name (symbol-name last-command-event))))
865 (error "Bogus calling sequence"))
866 (describe-language-environment language-name)))
867
868(defun describe-language-environment (language-name)
869 "Describe how Emacs supports language environment LANGUAGE-NAME."
870 (interactive
871 (list (read-language-name
872 'documentation
873 "Describe language environment (default, current choice): ")))
874 (if (null language-name)
875 (setq language-name current-language-environment))
876 (if (or (null language-name)
877 (null (get-language-info language-name 'documentation)))
878 (error "No documentation for the specified language"))
879 (if (symbolp language-name)
880 (setq language-name (symbol-name language-name)))
881 (let ((doc (get-language-info language-name 'documentation)))
882 (with-output-to-temp-buffer "*Help*"
883 (if (stringp doc)
884 (progn
885 (princ-list doc)
886 (terpri)))
887 (let ((str (get-language-info language-name 'sample-text)))
888 (if (stringp str)
889 (progn
890 (princ "Sample text:\n")
891 (princ-list " " str)
892 (terpri))))
893 (princ "Input methods:\n")
894 (let ((l input-method-alist))
895 (while l
896 (if (string= language-name (nth 1 (car l)))
897 (princ-list " " (car (car l))
898 (format " (`%s' in mode line)" (nth 3 (car l)))))
899 (setq l (cdr l))))
900 (terpri)
901 (princ "Character sets:\n")
902 (let ((l (get-language-info language-name 'charset)))
903 (if (null l)
904 (princ-list " nothing specific to " language-name)
905 (while l
906 (princ-list " " (car l) ": "
907 (charset-description (car l)))
908 (setq l (cdr l)))))
909 (terpri)
910 (princ "Coding systems:\n")
911 (let ((l (get-language-info language-name 'coding-system)))
912 (if (null l)
913 (princ-list " nothing specific to " language-name)
914 (while l
915 (princ (format " %s (`%c' in mode line):\n\t%s\n"
916 (car l)
917 (coding-system-mnemonic (car l))
918 (coding-system-doc-string (car l))))
919 (let ((aliases (coding-system-get (car l) 'alias-coding-systems)))
920 (when aliases
921 (princ "\t")
922 (princ (cons 'alias: (cdr aliases)))
923 (terpri)))
924 (setq l (cdr l))))))))
925\f
926;;; Charset property
927
928(defsubst get-charset-property (charset propname)
929 "Return the value of CHARSET's PROPNAME property.
930This is the last value stored with
931 (put-charset-property CHARSET PROPNAME VALUE)."
932 (plist-get (charset-plist charset) propname))
933
934(defsubst put-charset-property (charset propname value)
935 "Store CHARSETS's PROPNAME property with value VALUE.
936It can be retrieved with `(get-charset-property CHARSET PROPNAME)'."
937 (set-charset-plist charset
938 (plist-put (charset-plist charset) propname value)))
939
940;;; Character code property
941(put 'char-code-property-table 'char-table-extra-slots 0)
942
943(defvar char-code-property-table
944 (make-char-table 'char-code-property-table)
945 "Char-table containing a property list of each character code.
946
947See also the documentation of `get-char-code-property' and
948`put-char-code-property'.")
949
950(defun get-char-code-property (char propname)
951 "Return the value of CHAR's PROPNAME property in `char-code-property-table'."
952 (let ((plist (aref char-code-property-table char)))
953 (if (listp plist)
954 (car (cdr (memq propname plist))))))
955
956(defun put-char-code-property (char propname value)
957 "Store CHAR's PROPNAME property with VALUE in `char-code-property-table'.
958It can be retrieved with `(get-char-code-property CHAR PROPNAME)'."
959 (let ((plist (aref char-code-property-table char)))
960 (if plist
961 (let ((slot (memq propname plist)))
962 (if slot
963 (setcar (cdr slot) value)
964 (nconc plist (list propname value))))
965 (aset char-code-property-table char (list propname value)))))
966
967;;; mule-cmds.el ends here