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