tamago-4.0.2
[elisp/tamago.git] / egg-cnv.el
1 ;;; egg-cnv.el --- Conversion Backend in Egg Input Method Architecture
2
3 ;; Copyright (C) 1999,2000 PFU LIMITED
4
5 ;; Author: NIIBE Yutaka <gniibe@chroot.org>
6 ;;         KATAYAMA Yoshio <kate@pfu.co.jp>
7
8 ;; Maintainer: TOMURA Satoru <tomura@etl.go.jp>
9
10 ;; Keywords: mule, multilingual, input method
11
12 ;; This file is part of EGG.
13
14 ;; EGG is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; any later version.
18
19 ;; EGG is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 ;; GNU General Public License for more details.
23
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
26 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27 ;; Boston, MA 02111-1307, USA.
28
29 ;;; Commentary:
30
31
32 ;;; Code:
33
34 (require 'egg-edep)
35
36 (defgroup egg-conv nil
37   "Conversion backend Interface of Tamagotchy"
38   :group 'egg)
39
40 (defcustom egg-conversion-wrap-select nil
41   "*Candidate selection wraps around to first candidate, if non-NIL.
42 Otherwise stop at the last candidate."
43   :group 'egg-conv :type 'boolean)
44
45 (defcustom egg-conversion-auto-candidate-menu 0
46   "*Automatically enter the candidate selectionmenu mode at N times
47 next/previous-candidate, if positive number N."
48   :group 'egg-conv :type 'integer)
49
50 (defcustom egg-conversion-fence-invisible nil
51   "*Make fence marks invisible, if non-NIL."
52   :group 'egg-conv :type 'boolean)
53
54 (defcustom egg-conversion-fence-open "|"
55   "*String of conversion fence start mark. (should not be null string)"
56   :group 'egg-conv :type '(string :valid-regexp ".+"))
57
58 (defcustom egg-conversion-fence-close "|"
59   "*String of conversion fence end mark. (should not be null string)"
60   :group 'egg-conv :type '(string :valid-regexp ".+"))
61
62 (defcustom egg-conversion-face nil
63   "*Face (or alist of languages and faces) of text in conversion fences."
64   :group 'egg-conv
65   :type '(choice face
66                  (repeat :tag "Language-Face alist"
67                          (cons :tag "Language-Face"
68                                (choice :tag "Language"
69                                        (const Japanese)
70                                        (const Chinese-GB)
71                                        (const Chinese-CNS)
72                                        (const Korean)
73                                        (const :tag "Default" t)
74                                        (symbol :tag "Other"))
75                                face))))
76
77 (defcustom egg-conversion-major-separator " "
78   "*Major clause seperator"
79   :group 'egg-conv :type 'string)
80
81 (defcustom egg-conversion-minor-separator "-"
82   "*Minor clause seperator"
83   :group 'egg-conv :type 'string)
84
85 (defcustom egg-startup-file ".eggrc"
86   "*Egg startup file name."
87   :group 'egg-conv :type 'string)
88
89 (defcustom egg-startup-file-search-path '("~")
90   "*List of directories to search for egg-startup-file (default .eggrc)."
91   :group 'egg-conv :type '(repeat string))
92
93 (egg-add-message
94  '((nil
95     (no-rcfile     "no egg-startup-file on %S")
96     (rcfile-error  "error occured in egg-startup-file")
97     (candidate     "candidates:")
98     (register-str  "Chinese character:")
99     (register-yomi "word registration ``%s''  pronunciation:")
100     (registered    "dictionary entry ``%s''(%s: %s) is registerd at %s"))
101    (Japanese
102     (no-rcfile     "%S \e$B>e$K\e(B egg-startup-file \e$B$,$"$j$^$;$s\e(B")
103     (rcfile-error  "egg-startup-file \e$B$G%(%i!<$,$"$j$^$7$?\e(B")
104     (candidate     "\e$B8uJd\e(B:")
105     (register-str  "\e$B4A;z\e(B:")
106     (register-yomi "\e$B<-=qEPO?!X\e(B%s\e$B!Y\e(B  \e$BFI$_\e(B:")
107     (registered    "\e$B<-=q9`L\!X\e(B%s\e$B!Y\e(B(%s: %s)\e$B$r\e(B %s \e$B$KEPO?$7$^$7$?\e(B"))
108    (Chinese-GB
109     (no-rcfile     "\e$ATZ\e(B %S \e$AIOC;SP\e(B egg-startup-file")
110     (rcfile-error  "\e$ATZ6AH!\e(B egg-startup-file \e$AJ1#,SP3v4m7"IzAK\e(B")
111     (candidate     "\e$A:r29\e(B:")
112     (register-str  "\e$A::WV\e(B:")
113     (register-yomi "\e$A4G5d5GB<!:\e(B%s\e$A!;\e(B \e$A6A7(\e(B:")
114     (registered    "\e$A4G5dOnD?!:\e(B%s\e$A!;\e(B(%s: %s)\e$ARQ1;5GB<5=\e(B %s \e$AVPAK\e(B"))
115    (Chinese-CNS
116     (no-rcfile     "\e$(GGc\e(B %S \e$(GD8JtH4\e(B egg-startup-file")
117     (rcfile-error  "\e$(GGc{tL=\e(B egg-startup-file \e$(GUk!"H4Exrc`uFmD'\e(B")
118     (register-str  "\e$(GiGGs\e(B:")
119     (candidate     "\e$(GT7fP\e(B:")
120     (register-yomi "\e$(Gy0L(`trg!Z\e(B%s\e$(G![\e(B  \e$(G{tNN\e(B:")
121     (registered    "\e$(Gy0L(bzFx!Z\e(B%s\e$(G![\e(B(%s: %s)\e$(GDX]7`trgL/\e(B %s \e$(GDcD'\e(B"))
122    (Korean
123     (no-rcfile     "%S \e$(C?!\e(B egg-startup-file \e$(C@L\e(B \e$(C>x@>4O4Y\e(B")
124     (rcfile-error  "egg-startup-file \e$(C?!\e(B \e$(C?!7/0!\e(B \e$(C9_;}G_@>4O4Y\e(B")
125     (candidate     "\e$(CHD:8\e(B:")
126     (register-str  "\e$(CGQ@Z\e(B:")
127     (register-yomi "\e$(C;g@|5n7O!:\e(B%s\e$(C!;\e(B  \e$(C569}\e(B:")
128     (registered    "\e$(C;g@|GW8q!:\e(B%s\e$(C!;\e(B(%s: %s)\e$(C@;\e(B %s\e$(C?!\e(B \e$(C5n7OG_@>4O4Y\e(B"))))
129
130 ;;
131 ;; <backend-alist> ::= ( ( <language> ( <stage>... )... )... )
132 ;; <stage> ::= ( <backend> <backend-for-reconvert>... )
133 ;; <backend-for-reconvert> ::= <backend>
134 ;; <backend> ::= symbol
135 ;;
136
137 (defvar egg-conversion-backend-alist nil)
138 (make-variable-buffer-local 'egg-conversion-backend-alist)
139 (put 'egg-conversion-backend-alist 'permanent-local t)
140
141 (defun egg-set-conversion-backend (backend-alist &optional force)
142   (let (pair lang backend-set)
143     (while backend-alist
144       (setq lang (caar backend-alist)
145             backend-set (cdar backend-alist)
146             backend-alist (cdr backend-alist)
147             pair (assq lang egg-conversion-backend-alist))
148       (cond
149        ((null pair)
150         (setq egg-conversion-backend-alist 
151               (cons (cons lang backend-set) egg-conversion-backend-alist)))
152        (force
153         (setcdr pair backend-set))))))
154
155 (defun egg-get-conversion-backend (language n use-default)
156   (let (backend)
157     (cond ((null n) (setq n 0))
158           ((null (integerp n)) (setq n 1)))
159     (setq backend (nth (1+ n) (assq language egg-conversion-backend-alist)))
160     (if backend
161         (and backend (cons 0 (mapcar 'copy-sequence backend)))
162       (and use-default (cons 0 egg-default-conversion-backend)))))
163
164 (defsubst egg-default-conversion-backend-p (backend)
165   (eq (cdr backend) egg-default-conversion-backend))
166
167 (defsubst egg-get-current-backend (backend)
168   (car (nth (car backend) (cdr backend))))
169
170 (defsubst egg-get-reconvert-backend (backend &optional n)
171   (cond ((null n) (setq n 0))
172         ((null (integerp n)) (setq n 1)))
173   (nth (1+ n) (nth (car backend) (cdr backend))))
174
175 (defmacro egg-bunsetsu-info () ''intangible)
176
177 (defsubst egg-get-bunsetsu-info (p &optional object)
178   (get-text-property p (egg-bunsetsu-info) object))
179
180 (defsubst egg-get-backend (p &optional object)
181   (get-text-property p 'egg-backend object))
182
183 (defsubst egg-get-language (p &optional object)
184   (get-text-property p 'egg-lang object))
185
186 (defsubst egg-get-bunsetsu-last (p &optional object)
187   (get-text-property p 'egg-bunsetsu-last object))
188
189 (defsubst egg-get-major-continue (p &optional object)
190   (get-text-property p 'egg-major-continue object))
191
192 (defsubst egg-get-char-size (p &optional object)
193   (get-text-property p 'egg-char-size object))
194
195 ;; <bunsetsu-info> ::= ( <backend> . <backend-dependent-info> )
196
197 (defsubst egg-bunsetsu-create (backend info)
198   (cons backend info))
199
200 (defsubst egg-bunsetsu-get-backend (bunsetsu)
201   (car bunsetsu))
202 (defsubst egg-bunsetsu-set-backend (bunsetsu backend)
203   (setcar bunsetsu backend))
204
205 (defsubst egg-bunsetsu-get-info (bunsetsu)
206   (cdr bunsetsu))
207 (defsubst egg-bunsetsu-set-info (bunsetsu info)
208   (setcdr bunsetsu info))
209
210 (defvar egg-finalize-backend-list nil)
211
212 (defun egg-set-finalize-backend (func-list)
213   (mapcar (lambda (func)
214             (if (and func
215                      (null (memq func egg-finalize-backend-list)))
216                 (setq egg-finalize-backend-list
217                       (cons func egg-finalize-backend-list))))
218           func-list))
219
220 (defmacro egg-define-backend-functions (list)
221   (cons 'progn
222         (mapcar
223          (lambda (def)
224            (let* ((func (car def))
225                   (args (nth 1 def))
226                   (backend (car args)))
227              (cond ((eq backend 'bunsetsu)
228                     (setq backend `(egg-bunsetsu-get-backend ,backend)))
229                    ((eq backend 'bunsetsu-list)
230                     (setq backend `(egg-bunsetsu-get-backend (car ,backend)))))
231              `(defun ,func ,args
232                 (let ((func (get ,backend ',func)))
233                   (and func
234                        (funcall func ,@args))))))
235          list)))
236
237 (egg-define-backend-functions
238  ((egg-start-conversion (backend source-string context))
239   (egg-get-bunsetsu-source (bunsetsu))
240   (egg-get-bunsetsu-converted (bunsetsu))
241   (egg-get-source-language (bunsetsu))
242   (egg-get-converted-language (bunsetsu))
243   (egg-major-bunsetsu-continue-p (bunsetsu))
244   (egg-list-candidates (bunsetsu-list prev-b next-b major))
245   (egg-decide-candidate (bunsetsu-list candidate-pos prev-b next-b))
246   (egg-change-bunsetsu-length (bunsetsu-list prev-b next-b length major))
247   (egg-bunsetsu-combinable-p (bunsetsu next-b)) 
248   (egg-end-conversion (bunsetsu-list abort))
249   (egg-word-inspection (bunsetsu))
250   (egg-word-registration (backend source converted))))
251
252 (defun egg-finalize-backend ()
253   (run-hooks 'egg-finalize-backend-list))
254
255 (setplist 'egg-conversion-backend-noconv
256           '(egg-start-conversion          egg-start-conversion-noconv
257             egg-get-bunsetsu-source       egg-get-bunsetsu-source-noconv
258             egg-get-bunsetsu-converted    egg-get-bunsetsu-converted-noconv
259             egg-get-source-language       egg-get-source-language-noconv
260             egg-get-converted-language    egg-get-converted-language-noconv
261             egg-end-conversion            egg-end-conversion-noconv))
262
263 (defun egg-start-conversion-noconv (backend yomi-string context)
264   (let ((string (copy-sequence yomi-string))
265         (language (egg-get-language 0 yomi-string)))
266     (set-text-properties 0 (length string) nil string)
267     (list (egg-bunsetsu-create backend (vector string language)))))
268
269 (defun egg-get-bunsetsu-source-noconv (bunsetsu)
270   (aref (egg-bunsetsu-get-info bunsetsu) 0))
271 (defun egg-get-bunsetsu-converted-noconv (bunsetsu)
272   (aref (egg-bunsetsu-get-info bunsetsu) 0))
273 (defun egg-get-source-language-noconv (bunsetsu)
274   (aref (egg-bunsetsu-get-info bunsetsu) 1))
275 (defun egg-get-converted-language-noconv (bunsetsu)
276   (aref (egg-bunsetsu-get-info bunsetsu) 1))
277 (defun egg-end-conversion-noconv (bunsetsu-list abort)
278   nil)
279
280 (defconst egg-default-conversion-backend '((egg-conversion-backend-noconv)))
281 \f
282 (defun egg-convert-region (start end &optional context nth-backend)
283   (interactive "r\ni\nP")
284   (let ((source (buffer-substring start end))
285         backend backend-source-list converted converted-list
286         lang len s success abort)
287     (if (>= start end)
288         ;; nothing to do
289         nil
290       (delete-region start end)
291       (let ((inhibit-read-only t))
292         (its-define-select-keys egg-conversion-map)
293         (goto-char start)
294         (setq s (copy-sequence egg-conversion-fence-open)
295               len (length s)
296               start (+ start len)
297               end (+ end len))
298         (set-text-properties 0 len (list 'read-only t
299                                          'egg-start t
300                                          'egg-source source)
301                              s)
302         (if context
303             (put-text-property 0 len 'egg-context context s))
304         (if egg-conversion-fence-invisible
305             (put-text-property 0 len 'invisible t s))
306         (insert s)
307         (setq s (copy-sequence egg-conversion-fence-close)
308               len (length s))
309         (set-text-properties 0 len '(read-only t rear-nonsticky t egg-end t) s)
310         (if egg-conversion-fence-invisible
311             (put-text-property 0 len 'invisible t s))
312         (insert s)
313         (goto-char start)
314         (insert source)
315         (goto-char start)
316         (setq source (copy-sequence source))
317         (egg-separate-languages source)
318         (setq backend-source-list (egg-assign-backend source nth-backend))
319         (while (and (null abort) backend-source-list)
320           (setq backend (car (car backend-source-list))
321                 lang (nth 1 (car backend-source-list))
322                 source (nth 2 (car backend-source-list))
323                 backend-source-list (cdr backend-source-list))
324           (condition-case error
325               (progn
326                 (setq converted (egg-start-conversion
327                                  (egg-get-current-backend backend)
328                                  source context))
329                 (if (null converted)
330                     (egg-error "no conversion result"))
331                 (setq converted-list (nconc converted-list
332                                             (list (cons backend converted)))
333                       context 'continued)
334                 (or (egg-default-conversion-backend-p backend)
335                     (setq success t)))
336             ((egg-error quit)
337              (cond
338               ((null (or success
339                          (delq t (mapcar (lambda (s)
340                                            (egg-default-conversion-backend-p
341                                             (cdr (car s))))
342                                          backend-source-list))))
343                (message "egg %s backend: %s"
344                         (if (cdr lang) lang (car lang))
345                         (nth (if (eq (car error) 'quit) 0 1) error))
346                (ding)
347                (setq abort t))
348               ((condition-case err
349                    (y-or-n-p
350                     (format "egg %s backend %s: continue? "
351                             lang (nth (if (eq (car error) 'quit) 0 1) error)))
352                  ((error quit) nil))
353                (setq backend (egg-get-conversion-backend nil 0 t)
354                      converted (egg-start-conversion
355                                 (egg-get-current-backend backend)
356                                 source context)
357                      converted-list (nconc converted-list
358                                            (list (cons backend converted)))
359                      context 'continued))
360               (t
361                (setq abort t))))))
362         (delete-region start end)
363         (while converted-list
364           (egg-insert-bunsetsu-list (caar converted-list) (cdar converted-list)
365                                     (or (null (cdr converted-list)) 'continue))
366           (setq converted-list (cdr converted-list)))
367         (goto-char start)
368         (cond (abort
369                (egg-abort-conversion))
370               ((null success)
371                (egg-exit-conversion)))))))
372
373 (defun egg-separate-languages (str &optional last-lang)
374   (let (lang last-chinese
375         (len (length str)) i j l)
376     ;; 1st pass -- mark undefined Chinese part
377     (if (or (eq last-lang 'Chinese-GB) (eq last-lang 'Chinese-CNS))
378         (setq last-chinese last-lang))
379     (setq i 0)
380     (while (< i len)
381       (setq j (egg-next-single-property-change i 'egg-lang str len))
382       (if (null (egg-get-language i str))
383           (progn
384             (setq c (egg-string-to-char-at str i)
385                   cset (char-charset c))
386             (cond
387              ((eq cset 'chinese-sisheng)
388               (egg-string-match-charset 'chinese-sisheng str i)
389               (setq l (match-end 0)
390                     j (min j l)
391                     lang 'Chinese))
392              ((setq l (egg-chinese-syllable str i))
393               (setq j (+ i l)
394                     lang 'Chinese))
395              ((eq cset 'ascii)
396               (if (eq (string-match "[\0-\177\240-\377]+" str (1+ i)) (1+ i))
397                   (setq j (match-end 0))
398                 (setq j (1+ i)))
399               (if (and (< j len)
400                        (eq (char-charset (egg-string-to-char-at str j))
401                            'chinese-sisheng))
402                   (setq j (max (1+ i) (- j 6))))
403               (setq lang nil))
404              ((eq cset 'composition)
405               (setq j (+ i (egg-char-bytes c))
406                     lang (egg-charset-to-language
407                           (char-charset
408                            (car (decompose-composite-char c 'list))))))
409              (t
410               (egg-string-match-charset cset str i)
411               (setq j (match-end 0)
412                     lang (egg-charset-to-language cset))))
413             (if lang
414                 (put-text-property i j 'egg-lang lang str))))
415       (setq i j))
416     ;; 2nd pass -- set language property
417     (setq i 0)
418     (while (< i len)
419       (setq lang (egg-get-language i str))
420       (cond
421        ((null lang)
422         (setq lang (or last-lang
423                        (egg-next-part-lang str i))))
424        ((equal lang 'Chinese)
425         (setq lang (or last-chinese
426                        (egg-next-chinese-lang str i)))))
427       (setq last-lang lang)
428       (if (or (eq lang 'Chinese-GB) (eq lang 'Chinese-CNS))
429           (setq last-chinese lang))
430       (setq j i
431             i (egg-next-single-property-change i 'egg-lang str len))
432       (set-text-properties j i (list 'egg-lang lang) str))))
433
434 ;;; Should think again the interface to language-info-alist
435 (defun egg-charset-to-language (charset)
436   (let ((list language-info-alist))
437     (while (and list
438                 (null (memq charset (assq 'charset (car list)))))
439       (setq list (cdr list)))
440     (if list
441         (intern (car (car list))))))
442
443 (defun egg-next-part-lang (str pos)
444   (let ((lang (get-text-property
445                (egg-next-single-property-change pos 'egg-lang str (length str))
446                'egg-lang str)))
447     (if (eq lang 'Chinese)
448         (egg-next-chinese-lang str pos)
449       (or lang
450           its-current-language
451           egg-default-language))))
452
453 (defun egg-next-chinese-lang (str pos)
454   (let ((len (length str)) lang)
455     (while (and (< pos len) (null lang))
456       (setq pos (egg-next-single-property-change pos 'egg-lang str len)
457             lang (egg-get-language pos str))
458       (if (null (or (eq lang 'Chinese-GB)
459                     (eq lang 'Chinese-CNS)))
460           (setq lang nil)))
461     (cond
462      (lang lang)
463      ((eq its-current-language 'Chinese-GB)  'Chinese-GB)
464      ((eq its-current-language 'Chinese-CNS) 'Chinese-CNS)
465      ((eq egg-default-language 'Chinese-GB)  'Chinese-GB)
466      ((eq egg-default-language 'Chinese-CNS) 'Chinese-CNS)
467      (t 'Chinese-GB))))
468
469 ;;
470 ;; return value ::= ( (<backend> ( <lang>... ) <source string> )... )
471 ;;
472 (defun egg-assign-backend (source n)
473   (let ((len (length source))
474         (i 0)
475         j s lang backend retval)
476     (while (< i len)
477       (setq j (egg-next-single-property-change i 'egg-lang source len)
478             s (substring source i j)
479             lang (egg-get-language 0 s)
480             backend (egg-get-conversion-backend lang n t))
481       (set-text-properties 0 (- j i) (list 'egg-lang lang) s)
482       (setq retval (nconc retval (list (list backend (list lang) s)))
483             i j))
484     (prog1
485         retval
486       (while retval
487         (if (or (egg-default-conversion-backend-p (car (car retval)))
488                 (null (equal (car (car retval)) (car (nth 1 retval)))))
489             (setq retval (cdr retval))
490           (nconc (nth 1 (car retval)) (nth 1 (nth 1 retval)))
491           (setcar (nthcdr 2 (car retval))
492                   (concat (nth 2 (car retval)) (nth 2 (nth 1 retval))))
493           (setcdr retval (cddr retval)))))))
494
495 (defun egg-search-file (filename path)
496   (let (file)
497     (if (file-name-directory filename)
498         (setq file (substitute-in-file-name (expand-file-name filename))
499               file (and (file-readable-p file) file))
500       (while (and (null file) path)
501         (if (stringp (car path))
502             (setq file (substitute-in-file-name 
503                         (expand-file-name filename (car path)))
504                   file (and (file-exists-p file) file)))
505         (setq path (cdr path)))
506       file)))
507
508 (defvar egg-default-startup-file "eggrc"
509   "Egg startup file name (system default)")
510
511 (defun egg-load-startup-file (backend lang)
512   (let ((eggrc (or (egg-search-file egg-startup-file
513                                     egg-startup-file-search-path)
514                    (egg-search-file egg-default-startup-file load-path))))
515     (if eggrc
516         (condition-case error
517             (let ((egg-backend-type backend) (egg-language lang))
518               (load-file eggrc))
519           (error
520            (message "%s: %s" (car error)
521                     (mapconcat (lambda (s) (format "%S" s)) (cdr error) ", "))
522            (egg-error 'rcfile-error))
523           (quit
524            (egg-error 'rcfile-error)))
525       (egg-error 'no-rcfile egg-startup-file-search-path))))
526
527 (defun egg-get-conversion-face (lang)
528   (if (null (consp egg-conversion-face))
529       egg-conversion-face
530     (cdr (or (assq lang egg-conversion-face)
531              (assq t egg-conversion-face)))))
532 \f
533 (defvar egg-conversion-map
534   (let ((map (make-sparse-keymap))
535         (i 33))
536     (while (< i 127)
537       (define-key map (vector i) 'egg-exit-conversion-unread-char)
538       (setq i (1+ i)))
539     (define-key map "\C-@"   'egg-decide-first-char)
540     (define-key map [?\C-\ ] 'egg-decide-first-char)
541     (define-key map "\C-a"   'egg-beginning-of-conversion-buffer)
542     (define-key map "\C-b"   'egg-backward-bunsetsu)
543     (define-key map "\C-c"   'egg-abort-conversion)
544     (define-key map "\C-e"   'egg-end-of-conversion-buffer)
545     (define-key map "\C-f"   'egg-forward-bunsetsu)
546     (define-key map "\C-h"   'egg-help-command)
547     (define-key map "\C-i"   'egg-shrink-bunsetsu-major)
548     (define-key map "\C-k"   'egg-decide-before-point)
549 ;;    (define-key map "\C-l"   'egg-exit-conversion)  ; Don't override C-L
550     (define-key map "\C-m"   'egg-exit-conversion)
551     (define-key map "\C-n"   'egg-next-candidate-major)
552     (define-key map "\C-o"   'egg-enlarge-bunsetsu-major)
553     (define-key map "\C-p"   'egg-previous-candidate-major)
554     (define-key map "\C-r"   'egg-reconvert-bunsetsu)
555     (define-key map "\C-t"   'egg-toroku-bunsetsu)
556     (define-key map "\C-v"   'egg-inspect-bunsetsu)
557     (define-key map "\M-i"   'egg-shrink-bunsetsu-minor)
558     (define-key map "\M-n"   'egg-next-candidate-minor)
559     (define-key map "\M-o"   'egg-enlarge-bunsetsu-minor)
560     (define-key map "\M-p"   'egg-previous-candidate-minor)
561     (define-key map "\M-r"   'egg-reconvert-bunsetsu-from-source)
562     (define-key map "\M-s"   'egg-select-candidate-major)
563     (define-key map "\M-v"   'egg-toggle-inspect-mode)
564     (define-key map "\M-z"   'egg-select-candidate-minor)
565     (define-key map "\e\C-s" 'egg-select-candidate-list-all-major)
566     (define-key map "\e\C-z" 'egg-select-candidate-list-all-minor)
567     (define-key map [return] 'egg-exit-conversion)
568     (define-key map [right]  'egg-forward-bunsetsu)
569     (define-key map [left]   'egg-backward-bunsetsu)
570     (define-key map " "      'egg-next-candidate)
571     (define-key map "/"      'egg-exit-conversion)
572     map)
573   "Keymap for EGG Conversion mode.")
574
575 (fset 'egg-conversion-map egg-conversion-map)
576
577 (defun egg-exit-conversion-unread-char ()
578   (interactive)
579   (setq unread-command-events (list last-command-event)
580         this-command 'egg-use-context)
581   (setq egg-context (egg-exit-conversion)))
582
583 (defun egg-make-bunsetsu (backend bunsetsu last)
584   (let* ((converted (copy-sequence (egg-get-bunsetsu-converted bunsetsu)))
585          (language (egg-get-converted-language bunsetsu))
586          (continue (and (null last) (egg-major-bunsetsu-continue-p bunsetsu)))
587          (face (egg-get-conversion-face language))
588          len len1)
589     (setq len1 (length converted))
590     (or (eq last t)
591         (setq converted (concat converted
592                                 (if continue
593                                     egg-conversion-minor-separator
594                                   egg-conversion-major-separator))))
595     (setq len (length converted))
596     (set-text-properties 0 len
597                          (list 'read-only          t
598                                (egg-bunsetsu-info) bunsetsu
599                                'egg-backend        backend
600                                'egg-lang           language
601                                'egg-bunsetsu-last  last
602                                'egg-major-continue continue
603                                'local-map          'egg-conversion-map)
604                          converted)
605     (if face
606         (egg-set-face 0 len1 face converted))
607     converted))
608
609 (defun egg-insert-bunsetsu-list (backend bunsetsu-list &optional last)
610   (let ((len (length bunsetsu-list)))
611     (insert
612      (mapconcat
613       (lambda (b)
614         (setq len (1- len))
615         (egg-make-bunsetsu backend b (and (= len 0) last)))
616       bunsetsu-list ""))))
617
618 (defun egg-beginning-of-conversion-buffer (n)
619   (interactive "p")
620   (cond
621    ((<= n 0)
622     (egg-end-of-conversion-buffer 1))
623    ((null (get-text-property (1- (point)) 'egg-start))
624     (goto-char (previous-single-property-change (point) 'egg-start)))))
625
626 (defun egg-end-of-conversion-buffer(n)
627   (interactive "p")
628   (cond
629    ((<= n 0)
630     (egg-beginning-of-conversion-buffer 1))
631    (t
632     (goto-char (next-single-property-change (point) 'egg-end))
633     (backward-char))))
634
635 (defun egg-backward-bunsetsu (n)
636   (interactive "p")
637   (while (and (> n 0)
638               (null (get-text-property (1- (point)) 'egg-start)))
639     (backward-char)
640     (setq n (1- n)))
641   (if (> n 0)
642       (signal 'beginning-of-buffer nil)))
643
644 (defun egg-forward-bunsetsu (n)
645   (interactive "p")
646   (while (and (>= n 0)
647               (null (get-text-property (point) 'egg-end)))
648     (forward-char)
649     (setq n (1- n)))
650   (backward-char)
651   (if (>= n 0)
652       (signal 'end-of-buffer nil)))
653 \f
654 (defun egg-get-bunsetsu-tail (b)
655   (nth (1- (length b)) b))
656
657 (defun egg-previous-bunsetsu-point (p &optional n obj lim)
658   (or n (setq n 1))
659   (while (> n 0)
660     (setq p (previous-single-property-change p (egg-bunsetsu-info) obj lim)
661           n (1- n)))
662   p)
663
664 (defun egg-next-bunsetsu-point (p &optional n obj lim)
665   (or n (setq n 1))
666   (while (> n 0)
667     (setq p (egg-next-single-property-change p (egg-bunsetsu-info) obj lim)
668           n (1- n)))
669   p)
670
671 (defun egg-get-previous-bunsetsu (p)
672   (and (null (egg-get-bunsetsu-last (1- p)))
673        (egg-get-bunsetsu-info (1- p))))
674
675 (defun egg-get-previous-major-bunsetsu (p)
676   (let ((p (point))
677         (prev (egg-get-previous-bunsetsu p))
678         bunsetsu)
679     (while prev
680       (setq bunsetsu (cons prev bunsetsu)
681             p (egg-previous-bunsetsu-point p)
682             prev (and (egg-get-major-continue (1- p))
683                       (egg-get-bunsetsu-info (1- p)))))
684     bunsetsu))
685
686 (defun egg-get-next-bunsetsu (p)
687   (and (null (egg-get-bunsetsu-last p))
688        (egg-get-bunsetsu-info (egg-next-bunsetsu-point p))))
689
690 (defun egg-get-major-bunsetsu (p)
691   (let ((next (egg-get-bunsetsu-info p))
692         bunsetsu)
693     (while next
694       (setq bunsetsu (cons next bunsetsu)
695             p (egg-next-bunsetsu-point p)
696             next (and (egg-get-major-continue (1- p))
697                       (egg-get-bunsetsu-info p))))
698     (nreverse bunsetsu)))
699
700 (defsubst egg-get-major-bunsetsu-source (list)
701   (mapconcat (lambda (b) (egg-get-bunsetsu-source b)) list ""))
702
703 (defvar egg-inspect-mode nil
704   "*Display clause information on candidate selection, if non-NIL.")
705
706 (defun egg-toggle-inspect-mode ()
707   (interactive)
708   (if (setq egg-inspect-mode (not egg-inspect-mode))
709       (egg-inspect-bunsetsu t)))
710
711 (defun egg-inspect-bunsetsu (&optional quiet)
712   (interactive)
713   (or (egg-word-inspection (egg-get-bunsetsu-info (point)))
714       quiet
715       (beep)))
716
717 (defvar egg-candidate-selection-info nil)
718 (make-variable-buffer-local 'egg-candidate-selection-info)
719
720 (defvar egg-candidate-selection-major t)
721 (make-variable-buffer-local 'egg-candidate-selection-major)
722
723 (defsubst egg-set-candsel-info (b prev-b next-b major)
724   (setq egg-candidate-selection-info (list b prev-b next-b major)))
725
726 (defsubst egg-candsel-last-bunsetsu () (car egg-candidate-selection-info))
727 (defsubst egg-candsel-last-prev-b () (nth 1 egg-candidate-selection-info))
728 (defsubst egg-candsel-last-next-b () (nth 2 egg-candidate-selection-info))
729 (defsubst egg-candsel-last-major () (nth 3 egg-candidate-selection-info))
730
731 (defun egg-major-bunsetsu-head-p (head bunsetsu)
732   (while (and head (eq (car head) (car bunsetsu)))
733     (setq head (cdr head)
734           bunsetsu (cdr bunsetsu)))
735   (null head))
736
737 (defun egg-major-bunsetsu-tail-p (tail bunsetsu)
738   (egg-major-bunsetsu-head-p
739    tail (nthcdr (- (length bunsetsu) (length tail)) bunsetsu)))
740
741 (defun egg-get-candsel-target-major ()
742   (let ((bunsetsu (egg-get-major-bunsetsu (point)))
743         next-b prev-b next)
744     (setq prev-b (egg-get-previous-major-bunsetsu (point))
745           next (egg-next-bunsetsu-point (point) (length bunsetsu)))
746     (cond
747      ((and (egg-candsel-last-major)
748            (egg-major-bunsetsu-tail-p (egg-candsel-last-prev-b) prev-b)
749            (egg-major-bunsetsu-head-p (append (egg-candsel-last-bunsetsu)
750                                               (egg-candsel-last-next-b))
751                                       bunsetsu))
752       (setq bunsetsu (egg-candsel-last-bunsetsu)
753             prev-b (egg-candsel-last-prev-b)
754             next-b (egg-candsel-last-next-b))
755       (setq next (egg-next-bunsetsu-point (point) (length bunsetsu))))
756      ((null (egg-get-bunsetsu-last (1- next)))
757       (setq next-b (egg-get-major-bunsetsu next))))
758     (setq egg-candidate-selection-major t)
759     (list bunsetsu prev-b next-b next t)))
760
761 (defun egg-get-candsel-target-minor ()
762   (let* ((bunsetsu (list (egg-get-bunsetsu-info (point))))
763          (prev-b (egg-get-previous-bunsetsu (point)))
764          (next-b (egg-get-next-bunsetsu (point))))
765     (and prev-b (setq prev-b (list prev-b)))
766     (and next-b (setq next-b (list next-b)))
767     (setq egg-candidate-selection-major nil)
768     (list bunsetsu prev-b next-b (egg-next-bunsetsu-point (point)) nil)))
769
770 (defun egg-insert-new-bunsetsu (b prev-b next-b next end)
771   (let ((backend (egg-get-backend (point)))
772         start last)
773     (setq start (egg-previous-bunsetsu-point (point) (length prev-b)))
774     (setq end (or end (egg-next-bunsetsu-point next (length next-b))))
775     (setq last (egg-get-bunsetsu-last (1- end)))
776     (delete-region start end)
777     (egg-insert-bunsetsu-list backend (append prev-b (append b next-b)) last)
778     (goto-char (egg-next-bunsetsu-point start (length prev-b)))
779     (if egg-inspect-mode
780         (egg-inspect-bunsetsu t))))
781
782 (defun egg-next-candidate (n)
783   (interactive "p")
784   (if egg-candidate-selection-major
785       (egg-next-candidate-major n)
786     (egg-next-candidate-minor n)))
787
788 (defun egg-next-candidate-major (n)
789   (interactive "p")
790   (apply 'egg-next-candidate-internal n (egg-get-candsel-target-major)))
791
792 (defun egg-next-candidate-minor (n)
793   (interactive "p")
794   (apply 'egg-next-candidate-internal n (egg-get-candsel-target-minor)))
795
796 (defun egg-previous-candidate (n)
797   (interactive "p")
798   (if egg-candidate-selection-major
799       (egg-previous-candidate-major n)
800     (egg-previous-candidate-minor n)))
801
802 (defun egg-previous-candidate-major (n)
803   (interactive "p")
804   (apply 'egg-next-candidate-internal (- n) (egg-get-candsel-target-major)))
805
806 (defun egg-previous-candidate-minor (n)
807   (interactive "p")
808   (apply 'egg-next-candidate-internal (- n) (egg-get-candsel-target-minor)))
809
810 (defvar egg-candidate-select-counter 1)
811
812 (defun egg-next-candidate-internal (n b prev-b next-b next major)
813   (if (eq last-command (if major 'egg-candidate-major 'egg-candidate-minor))
814       (setq egg-candidate-select-counter (1+ egg-candidate-select-counter))
815     (setq egg-candidate-select-counter 1))
816   (if (= egg-candidate-select-counter egg-conversion-auto-candidate-menu)
817       (egg-select-candidate-internal nil b prev-b next-b next major)
818     (setq this-command (if major 'egg-candidate-major 'egg-candidate-minor))
819     (let ((inhibit-read-only t)
820           candidates nitem i beep)
821       (setq candidates (egg-list-candidates b prev-b next-b major))
822       (if (null candidates)
823           (setq beep t)
824         (setq i (+ n (car candidates))
825               nitem (length (cdr candidates)))
826         (cond
827          ((< i 0)                       ; go backward as if it is ring
828           (while (< i 0)
829             (setq i (+ i nitem))))
830          ((< i nitem))                  ; OK
831          (egg-conversion-wrap-select    ; go backward as if it is ring
832           (while (>= i nitem)
833             (setq i (- i nitem))))
834          (t                             ; don't go forward 
835           (setq i (1- nitem)
836                 beep t)))
837         (setq b (egg-decide-candidate b i prev-b next-b)
838               prev-b (nth 1 b)
839               next-b (nth 2 b)
840               b (car b))
841         (egg-set-candsel-info b prev-b next-b major)
842         (egg-insert-new-bunsetsu b prev-b next-b next nil))
843       (if beep
844           (ding)))))
845
846 (defun egg-numbering-item (list)
847   (let ((n -1))
848     (mapcar (lambda (item) (cons item (setq n (1+ n)))) list)))
849
850 (defun egg-select-candidate-major ()
851   (interactive)
852   (apply 'egg-select-candidate-internal nil (egg-get-candsel-target-major)))
853
854 (defun egg-select-candidate-minor ()
855   (interactive)
856   (apply 'egg-select-candidate-internal nil (egg-get-candsel-target-minor)))
857
858 (defun egg-select-candidate-list-all-major ()
859   (interactive)
860   (apply 'egg-select-candidate-internal t (egg-get-candsel-target-major)))
861
862 (defun egg-select-candidate-list-all-minor ()
863   (interactive)
864   (apply 'egg-select-candidate-internal t (egg-get-candsel-target-minor)))
865
866 (defun egg-select-candidate-internal (all b prev-b next-b next major)
867   (let ((inhibit-read-only t)
868         (prompt (egg-get-message 'candidate))
869         candidates item-list new i)
870     (setq candidates (egg-list-candidates b prev-b next-b major))
871     (if (null candidates)
872         (ding)
873       (setq all (and all '(menudiag-list-all))
874             item-list (egg-numbering-item (cdr candidates))
875             i (menudiag-select (list 'menu prompt item-list)
876                                (cons (nth (car candidates) item-list) all))
877             new (egg-decide-candidate b i prev-b next-b)
878             prev-b (nth 1 new)
879             next-b (nth 2 new)
880             new (car new))
881       (egg-set-candsel-info new prev-b next-b major)
882       (egg-insert-new-bunsetsu new prev-b next-b next nil))))
883
884 (defun egg-separate-characters (str)
885   (let* ((v (egg-string-to-vector str))
886          (len (length v))
887          (i 0) (j 0) m n (nchar 0))
888     (while (< i len)
889       (if (setq n (egg-chinese-syllable str j))
890           (setq m (egg-chars-in-period str j n))
891         (setq m 1 n (egg-char-bytes (aref v i))))
892       (put-text-property j (+ j n) 'egg-char-size n str)
893       (setq nchar (1+ nchar) i (+ i m) j (+ j n)))
894     nchar))
895
896 (defun egg-enlarge-bunsetsu-major (n)
897   (interactive "p")
898   (egg-enlarge-bunsetsu-internal n t))
899
900 (defun egg-enlarge-bunsetsu-minor (n)
901   (interactive "p")
902   (egg-enlarge-bunsetsu-internal n nil))
903
904 (defun egg-shrink-bunsetsu-major (n)
905   (interactive "p")
906   (egg-enlarge-bunsetsu-internal (- n) t))
907
908 (defun egg-shrink-bunsetsu-minor (n)
909   (interactive "p")
910   (egg-enlarge-bunsetsu-internal (- n) nil))
911
912 (defun egg-enlarge-bunsetsu-internal (n major)
913   (let ((inhibit-read-only t)
914         b prev-b next-b s1 s1len s2 s2len nchar i last next end beep)
915     (if major
916         (setq b (egg-get-major-bunsetsu (point))
917               prev-b (egg-get-previous-major-bunsetsu (point)))
918       (setq b (list (egg-get-bunsetsu-info (point)))
919             prev-b (egg-get-previous-bunsetsu (point))
920             prev-b (and prev-b (list prev-b))))
921     (setq end (egg-next-bunsetsu-point (point) (length b))
922           last (egg-get-bunsetsu-last (1- end)))
923     (while (null last)
924       (setq next-b (cons (egg-get-bunsetsu-info end) next-b)
925             last (egg-get-bunsetsu-last end)
926             end (egg-next-bunsetsu-point end)))
927     (setq next-b (nreverse next-b)
928           s1 (egg-get-major-bunsetsu-source b)
929           s2 (concat s1 (egg-get-major-bunsetsu-source next-b))
930           s1len (egg-separate-characters s1)
931           s2len (egg-separate-characters s2)
932           n (+ n s1len))
933     (cond
934      ((<= n 0)
935       (setq beep t nchar (and (/= s1len 1) (egg-get-char-size 0 s1))))
936      ((> n s2len)
937       (setq beep t nchar (and (/= s2len 0) (length s2))))
938      (t
939       (setq nchar 0)
940       (while (> n 0)
941         (setq nchar (+ nchar (egg-get-char-size nchar s2))
942               n (1- n)))))
943     (if nchar
944         (progn
945           (setq next-b (nconc b next-b)
946                 i (length (egg-get-bunsetsu-source (car next-b))))
947           (while (< i nchar)
948             (setq next-b (cdr next-b)
949                   i (+ i (length (egg-get-bunsetsu-source (car next-b))))))
950           (setq next-b (prog1 (cdr next-b) (setcdr next-b nil))
951                 next (egg-next-bunsetsu-point (point) (length b))
952                 b (egg-change-bunsetsu-length b prev-b next-b nchar major))
953           (if (null b)
954               (setq beep t)
955             (setq prev-b (nth 1 b)
956                   next-b (nth 2 b)
957                   b (car b))
958             (egg-insert-new-bunsetsu b prev-b next-b next (and next-b end)))))
959     (if beep
960         (ding))))
961
962 (defun egg-reconvert-bunsetsu (n)
963   (interactive "P")
964   (egg-reconvert-bunsetsu-internal n 'egg-get-bunsetsu-converted))
965
966 (defun egg-reconvert-bunsetsu-from-source (n)
967   (interactive "P")
968   (egg-reconvert-bunsetsu-internal n 'egg-get-bunsetsu-source))
969
970 (defun egg-reconvert-bunsetsu-internal (n func)
971   (let* ((inhibit-read-only t)
972          (backend (egg-get-backend (point)))
973          (source (funcall func (egg-get-bunsetsu-info (point))))
974          (reconv-backend (egg-get-reconvert-backend backend n))
975          (p (point))
976          (last (egg-get-bunsetsu-last (point)))
977          new prev-b next-b)
978     (if (or (null reconv-backend)
979             (null (setq new (egg-start-conversion reconv-backend source nil))))
980         (ding)
981       (delete-region p (egg-next-bunsetsu-point p))
982       (setq next-b (egg-get-bunsetsu-info (point)))
983       (if (and (equal (egg-get-backend p) backend)
984                (eq (egg-bunsetsu-get-backend next-b)
985                    (egg-bunsetsu-get-backend (car new)))
986                (egg-bunsetsu-combinable-p (egg-get-bunsetsu-tail new) next-b))
987           (setq last nil)
988         (setq last (or (eq last t) 'continue)))
989       (egg-insert-bunsetsu-list backend new last)
990       (goto-char p)
991       (setq prev-b (egg-get-bunsetsu-info (1- p)))
992       (if prev-b
993           (progn
994             (if (and (equal (egg-get-backend (1- p)) backend)
995                      (eq (egg-bunsetsu-get-backend prev-b)
996                          (egg-bunsetsu-get-backend (car new)))
997                      (egg-bunsetsu-combinable-p prev-b (car new)))
998                 (setq last nil)
999               (setq last (or (eq last t) 'continue)))
1000             (setq backend (egg-get-backend (1- p)))
1001             (delete-region (egg-previous-bunsetsu-point p) p)
1002             (egg-insert-bunsetsu-list backend (list prev-b) last))))))
1003
1004 (defun egg-decide-before-point ()
1005   (interactive)
1006   (let* ((inhibit-read-only t)
1007          (start (if (get-text-property (1- (point)) 'egg-start)
1008                     (point)
1009                   (previous-single-property-change (point) 'egg-start)))
1010          (end (if (get-text-property (point) 'egg-end)
1011                   (point)
1012                 (next-single-property-change (point) 'egg-end)))
1013          (decided (buffer-substring start (point)))
1014          (undecided (buffer-substring (point) end))
1015          i len bunsetsu source context)
1016     (delete-region
1017      (previous-single-property-change start 'egg-start nil (point-min))
1018      (next-single-property-change end 'egg-end nil (point-max)))
1019     (setq i 0
1020           len (length decided))
1021     (while (< i len)
1022       (setq bunsetsu (nconc bunsetsu (list (egg-get-bunsetsu-info i decided)))
1023             i (egg-next-bunsetsu-point i 1 decided len))
1024       (if (or (= i len)
1025               (egg-get-bunsetsu-last (1- i) decided))
1026           (progn
1027             (apply 'insert (mapcar
1028                             (lambda (b) (egg-get-bunsetsu-converted b))
1029                             bunsetsu))
1030             (setq context (cons (cons (egg-bunsetsu-get-backend (car bunsetsu))
1031                                       (egg-end-conversion bunsetsu nil))
1032                                 context)
1033                   bunsetsu nil))))
1034     (setq len (length undecided))
1035     (if (= len 0)
1036         (progn
1037           (egg-do-auto-fill)
1038           (run-hooks 'input-method-after-insert-chunk-hook)
1039           context)
1040       (setq i 0)
1041       (while (< i len)
1042         (setq bunsetsu (egg-get-bunsetsu-info i undecided)
1043               source (cons (egg-get-bunsetsu-source bunsetsu)
1044                            source))
1045         (put-text-property 0 (length (car source))
1046                            'egg-lang
1047                            (egg-get-source-language bunsetsu)
1048                            (car source))
1049         (setq i (egg-next-bunsetsu-point i 1 undecided len)))
1050       (its-restart (apply 'concat (nreverse source)) t t context))))
1051
1052 (defun egg-decide-first-char ()
1053   (interactive)
1054   (let* ((inhibit-read-only t)
1055          (start (if (get-text-property (1- (point)) 'egg-start)
1056                     (point)
1057                   (previous-single-property-change (point) 'egg-start)))
1058          (end (if (get-text-property (point) 'egg-end)
1059                   (point)
1060                 (next-single-property-change (point) 'egg-end)))
1061          (bunsetsu (egg-get-bunsetsu-info start)))
1062     (delete-region
1063      (previous-single-property-change start 'egg-start nil (point-min))
1064      (next-single-property-change end 'egg-end nil (point-max)))
1065     (egg-end-conversion (list bunsetsu) nil)
1066     (insert (egg-string-to-char-at (egg-get-bunsetsu-converted bunsetsu) 0))))
1067
1068 (defun egg-exit-conversion ()
1069   (interactive)
1070   (if (egg-get-bunsetsu-info (point))
1071       (progn
1072         (goto-char (next-single-property-change (point) 'egg-end))
1073         (egg-decide-before-point))))
1074
1075 (defun egg-abort-conversion ()
1076   (interactive)
1077   (let ((inhibit-read-only t)
1078         source context)
1079     (goto-char (previous-single-property-change
1080                 (if (get-text-property (1- (point)) 'egg-start)
1081                     (point)
1082                   (previous-single-property-change (point) 'egg-start))
1083                 'egg-start nil (point-min)))
1084     (setq source (get-text-property (point) 'egg-source)
1085           context (get-text-property (point) 'egg-context))
1086     (delete-region (point) (next-single-property-change
1087                             (next-single-property-change (point) 'egg-end)
1088                             'egg-end nil (point-max)))
1089     (its-restart source nil nil context)))
1090
1091 (defun egg-toroku-bunsetsu ()
1092   (interactive)
1093   (let* ((p (point))
1094          (lang (egg-get-source-language (egg-get-bunsetsu-info p)))
1095          (egg-mode-hook (or (cdr (assq lang its-select-func-alist))
1096                             (cdr (assq lang its-select-func-default-alist))))
1097          (s "")
1098          bunsetsu str yomi last)
1099     (while (null last)
1100       (setq bunsetsu (egg-get-bunsetsu-info p)
1101             str (concat str (egg-get-bunsetsu-converted bunsetsu))
1102             yomi (concat yomi (egg-get-bunsetsu-source bunsetsu))
1103             last (egg-get-bunsetsu-last p)
1104             p (egg-next-bunsetsu-point p)))
1105     (while (equal s "")
1106       (setq s (read-multilingual-string (egg-get-message 'register-str)
1107                                         str egg-last-method-name))
1108       (and (equal s "") (ding)))
1109     (egg-toroku-string s nil yomi lang (egg-bunsetsu-get-backend bunsetsu))))
1110
1111 (defun egg-toroku-region (start end &optional nth-backend)
1112   (interactive "r\nP")
1113   (egg-toroku-string (buffer-substring start end) nil nil nil nil nth-backend))
1114
1115 (defun egg-toroku-string (str &optional yomi guess lang backend nth-backend)
1116   (let (egg-mode-hook result)
1117     (if (= (length str) 0)
1118         (egg-error "Egg word registration: null string"))
1119     (egg-separate-languages str lang)
1120     (setq lang (egg-get-language 0 str)
1121           egg-mode-hook (or (cdr (assq lang its-select-func-alist))
1122                             (cdr (assq lang its-select-func-default-alist))))
1123     (or yomi (setq yomi ""))
1124     (while (equal yomi "")
1125       (setq yomi (read-multilingual-string
1126                   (format (egg-get-message 'register-yomi) str)
1127                   guess egg-last-method-name))
1128       (and (equal yomi "") (ding)))
1129     (egg-separate-languages yomi lang)
1130     (if (null backend)
1131         (progn
1132           (setq backend (egg-assign-backend str nth-backend))
1133           (if (cdr backend)
1134               (egg-error "Egg word registration: cannot decide backend"))
1135           (setq backend (egg-get-current-backend (caar backend)))))
1136     (setq result (egg-word-registration backend str yomi))
1137     (if result
1138         (apply 'message (egg-get-message 'registered) str yomi result)
1139       (beep))))
1140 \f
1141 (defun egg-conversion-mode ()
1142   "\\{egg-conversion-map}"
1143   ;; dummy function to get docstring
1144   )
1145
1146 (defun egg-help-command ()
1147   "Display documentation for EGG Conversion mode."
1148   (interactive)
1149   (with-output-to-temp-buffer "*Help*"
1150     (princ "EGG Conversion mode:\n")
1151     (princ (documentation 'egg-conversion-mode))
1152     (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p))))
1153
1154 (provide 'egg-cnv)
1155 ;;; egg-cnv.el ends here.