tamago-current.diff.gz in [tamago:00423] is applied.
[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 egg-end t) s)
325         (if egg-conversion-fence-invisible
326             (put-text-property 0 len 'invisible t s))
327         (insert s)
328         (goto-char start)
329         (insert source)
330         (goto-char start)
331         (setq source (copy-sequence source))
332         (egg-separate-languages source)
333         (setq backend-source-list (egg-assign-backend source nth-backend))
334         (while (and (null abort) backend-source-list)
335           (setq backend (car (car backend-source-list))
336                 lang (nth 1 (car backend-source-list))
337                 source (nth 2 (car backend-source-list))
338                 backend-source-list (cdr backend-source-list))
339           (condition-case error
340               (progn
341                 (setq converted (egg-start-conversion
342                                  (egg-get-current-backend backend)
343                                  source context))
344                 (if (null converted)
345                     (egg-error "no conversion result"))
346                 (setq converted-list (nconc converted-list
347                                             (list (cons backend converted)))
348                       context 'continued)
349                 (or (egg-default-conversion-backend-p backend)
350                     (setq success t)))
351             ((egg-error quit)
352              (cond
353               ((null (or success
354                          (delq t (mapcar (lambda (s)
355                                            (egg-default-conversion-backend-p
356                                             (cdr (car s))))
357                                          backend-source-list))))
358                (message "egg %s backend: %s"
359                         (if (cdr lang) lang (car lang))
360                         (nth (if (eq (car error) 'quit) 0 1) error))
361                (ding)
362                (setq abort t))
363               ((condition-case err
364                    (y-or-n-p
365                     (format "egg %s backend %s: continue? "
366                             lang (nth (if (eq (car error) 'quit) 0 1) error)))
367                  ((error quit) nil))
368                (setq backend (egg-get-conversion-backend nil 0 t)
369                      converted (egg-start-conversion
370                                 (egg-get-current-backend backend)
371                                 source context)
372                      converted-list (nconc converted-list
373                                            (list (cons backend converted)))
374                      context 'continued))
375               (t
376                (setq abort t))))))
377         (delete-region start end)
378         (while converted-list
379           (egg-insert-bunsetsu-list (caar converted-list) (cdar converted-list)
380                                     (or (null (cdr converted-list)) 'continue))
381           (setq converted-list (cdr converted-list)))
382         (goto-char start)
383         (cond (abort
384                (egg-abort-conversion))
385               ((null success)
386                (egg-exit-conversion)))))))
387
388 (defun egg-separate-languages (str &optional last-lang)
389   (let (lang last-chinese
390         (len (length str)) i j l)
391     ;; 1st pass -- mark undefined Chinese part
392     (if (or (eq last-lang 'Chinese-GB) (eq last-lang 'Chinese-CNS))
393         (setq last-chinese last-lang))
394     (setq i 0)
395     (while (< i len)
396       (setq j (egg-next-single-property-change i 'egg-lang str len))
397       (if (null (egg-get-language i str))
398           (progn
399             (setq c (egg-string-to-char-at str i)
400                   cset (char-charset c))
401             (cond
402              ((eq cset 'chinese-sisheng)
403               (egg-string-match-charset 'chinese-sisheng str i)
404               (setq l (match-end 0)
405                     j (min j l)
406                     lang 'Chinese))
407              ((setq l (egg-chinese-syllable str i))
408               (setq j (+ i l)
409                     lang 'Chinese))
410              ((eq cset 'ascii)
411               (if (eq (string-match "[\0-\177\240-\377]+" str (1+ i)) (1+ i))
412                   (setq j (match-end 0))
413                 (setq j (1+ i)))
414               (if (and (< j len)
415                        (eq (char-charset (egg-string-to-char-at str j))
416                            'chinese-sisheng))
417                   (setq j (max (1+ i) (- j 6))))
418               (setq lang nil))
419              ((eq cset 'composition)
420               (setq j (+ i (egg-char-bytes c))
421                     lang (egg-charset-to-language
422                           (char-charset
423                            (car (decompose-composite-char c 'list))))))
424              (t
425               (egg-string-match-charset cset str i)
426               (setq j (match-end 0)
427                     lang (egg-charset-to-language cset))))
428             (if lang
429                 (put-text-property i j 'egg-lang lang str))))
430       (setq i j))
431     ;; 2nd pass -- set language property
432     (setq i 0)
433     (while (< i len)
434       (setq lang (egg-get-language i str))
435       (cond
436        ((null lang)
437         (setq lang (or last-lang
438                        (egg-next-part-lang str i))))
439        ((equal lang 'Chinese)
440         (setq lang (or last-chinese
441                        (egg-next-chinese-lang str i)))))
442       (setq last-lang lang)
443       (if (or (eq lang 'Chinese-GB) (eq lang 'Chinese-CNS))
444           (setq last-chinese lang))
445       (setq j i
446             i (egg-next-single-property-change i 'egg-lang str len))
447       (egg-remove-all-text-properties j i str)
448       (put-text-property j i 'egg-lang lang str))))
449
450 ;;; Should think again the interface to language-info-alist
451 (defun egg-charset-to-language (charset)
452   (let ((list language-info-alist))
453     (while (and list
454                 (null (memq charset (assq 'charset (car list)))))
455       (setq list (cdr list)))
456     (if list
457         (intern (car (car list))))))
458
459 (defun egg-next-part-lang (str pos)
460   (let ((lang (get-text-property
461                (egg-next-single-property-change pos 'egg-lang str (length str))
462                'egg-lang str)))
463     (if (eq lang 'Chinese)
464         (egg-next-chinese-lang str pos)
465       (or lang
466           its-current-language
467           egg-default-language))))
468
469 (defun egg-next-chinese-lang (str pos)
470   (let ((len (length str)) lang)
471     (while (and (< pos len) (null lang))
472       (setq pos (egg-next-single-property-change pos 'egg-lang str len)
473             lang (egg-get-language pos str))
474       (if (null (or (eq lang 'Chinese-GB)
475                     (eq lang 'Chinese-CNS)))
476           (setq lang nil)))
477     (cond
478      (lang lang)
479      ((eq its-current-language 'Chinese-GB)  'Chinese-GB)
480      ((eq its-current-language 'Chinese-CNS) 'Chinese-CNS)
481      ((eq egg-default-language 'Chinese-GB)  'Chinese-GB)
482      ((eq egg-default-language 'Chinese-CNS) 'Chinese-CNS)
483      (t 'Chinese-GB))))
484
485 ;;
486 ;; return value ::= ( (<backend> ( <lang>... ) <source string> )... )
487 ;;
488 (defun egg-assign-backend (source n)
489   (let ((len (length source))
490         (i 0)
491         j s lang backend retval)
492     (while (< i len)
493       (setq j (egg-next-single-property-change i 'egg-lang source len)
494             s (substring source i j)
495             lang (egg-get-language 0 s)
496             backend (egg-get-conversion-backend lang n t))
497       (egg-remove-all-text-properties 0 (- j i) s)
498       (put-text-property 0 (- j i) 'egg-lang lang s)
499       (setq retval (nconc retval (list (list backend (list lang) s)))
500             i j))
501     (prog1
502         retval
503       (while retval
504         (if (or (egg-default-conversion-backend-p (car (car retval)))
505                 (null (equal (car (car retval)) (car (nth 1 retval)))))
506             (setq retval (cdr retval))
507           (nconc (nth 1 (car retval)) (nth 1 (nth 1 retval)))
508           (setcar (nthcdr 2 (car retval))
509                   (concat (nth 2 (car retval)) (nth 2 (nth 1 retval))))
510           (setcdr retval (cddr retval)))))))
511
512 (defun egg-search-file (filename path)
513   (let (file)
514     (if (file-name-directory filename)
515         (setq file (substitute-in-file-name (expand-file-name filename))
516               file (and (file-readable-p file) file))
517       (while (and (null file) path)
518         (if (stringp (car path))
519             (setq file (substitute-in-file-name 
520                         (expand-file-name filename (car path)))
521                   file (and (file-exists-p file) file)))
522         (setq path (cdr path)))
523       file)))
524
525 (defvar egg-default-startup-file "eggrc"
526   "Egg startup file name (system default)")
527
528 (defun egg-load-startup-file (backend lang)
529   (let ((eggrc (or (egg-search-file egg-startup-file
530                                     egg-startup-file-search-path)
531                    (egg-search-file egg-default-startup-file load-path))))
532     (if eggrc
533         (condition-case error
534             (let ((egg-backend-type backend) (egg-language lang))
535               (load-file eggrc))
536           (error
537            (message "%s: %s" (car error)
538                     (mapconcat (lambda (s) (format "%S" s)) (cdr error) ", "))
539            (egg-error 'rcfile-error))
540           (quit
541            (egg-error 'rcfile-error)))
542       (egg-error 'no-rcfile egg-startup-file-search-path))))
543
544 (defun egg-get-conversion-face (lang)
545   (if (null (consp egg-conversion-face))
546       egg-conversion-face
547     (cdr (or (assq lang egg-conversion-face)
548              (assq t egg-conversion-face)))))
549 \f
550 (defvar egg-conversion-map
551   (let ((map (make-sparse-keymap))
552         (i 33))
553     (while (< i 127)
554       (define-key map (vector i) 'egg-exit-conversion-unread-char)
555       (setq i (1+ i)))
556     (define-key map "\C-@"      'egg-decide-first-char)
557     (define-key map [?\C-\ ]    'egg-decide-first-char)
558     (define-key map "\C-a"      'egg-beginning-of-conversion-buffer)
559     (define-key map "\C-b"      'egg-backward-bunsetsu)
560     (define-key map "\C-c"      'egg-abort-conversion)
561     (define-key map "\C-e"      'egg-end-of-conversion-buffer)
562     (define-key map "\C-f"      'egg-forward-bunsetsu)
563     (define-key map "\C-h"      'egg-help-command)
564     (define-key map "\C-i"      'egg-shrink-bunsetsu-major)
565     (define-key map "\C-k"      'egg-decide-before-point)
566 ;;    (define-key map "\C-l"      'egg-exit-conversion)  ; Don't override C-L
567     (define-key map "\C-m"      'egg-exit-conversion)
568     (define-key map "\C-n"      'egg-next-candidate-major)
569     (define-key map "\C-o"      'egg-enlarge-bunsetsu-major)
570     (define-key map "\C-p"      'egg-previous-candidate-major)
571     (define-key map "\C-r"      'egg-reconvert-bunsetsu)
572     (define-key map "\C-t"      'egg-toroku-bunsetsu)
573     (define-key map "\C-v"      'egg-inspect-bunsetsu)
574     (define-key map "\M-i"      'egg-shrink-bunsetsu-minor)
575     (define-key map "\M-n"      'egg-next-candidate-minor)
576     (define-key map "\M-o"      'egg-enlarge-bunsetsu-minor)
577     (define-key map "\M-p"      'egg-previous-candidate-minor)
578     (define-key map "\M-r"      'egg-reconvert-bunsetsu-from-source)
579     (define-key map "\M-s"      'egg-select-candidate-major)
580     (define-key map "\M-v"      'egg-toggle-inspect-mode)
581     (define-key map "\M-z"      'egg-select-candidate-minor)
582     (define-key map "\e\C-s"    'egg-select-candidate-list-all-major)
583     (define-key map "\e\C-z"    'egg-select-candidate-list-all-minor)
584     (define-key map [return]    'egg-exit-conversion)
585     (define-key map [right]     'egg-forward-bunsetsu)
586     (define-key map [left]      'egg-backward-bunsetsu)
587     (define-key map [up]        'egg-previous-candidate)
588     (define-key map [down]      'egg-next-candidate)
589     (define-key map [backspace] 'egg-abort-conversion)
590     (define-key map [clear]     'egg-abort-conversion)
591     (define-key map [delete]    'egg-abort-conversion)
592     (define-key map " "         'egg-next-candidate)
593     (define-key map "/"         'egg-exit-conversion)
594     (define-key map "\M-h"      'egg-hiragana)
595     (define-key map "\M-k"      'egg-katakana)
596     (define-key map "\M-P"      'egg-pinyin)
597     (define-key map "\M-Z"      'egg-zhuyin)
598     (define-key map "\M-H"      'egg-hangul)
599     map)
600   "Keymap for EGG Conversion mode.")
601 (fset 'egg-conversion-map egg-conversion-map)
602
603 (defvar egg-conversion-mode nil)
604 (make-variable-buffer-local 'egg-conversion-mode)
605 (put 'egg-conversion-mode 'permanent-local t)
606
607 (or (assq 'egg-conversion-mode egg-sub-mode-map-alist)
608     (setq egg-sub-mode-map-alist (cons
609                                   '(egg-conversion-mode . egg-conversion-map)
610                                   egg-sub-mode-map-alist)))
611
612 (defun egg-conversion-enter/leave-fence (&optional old new)
613   (setq egg-conversion-mode (egg-conversion-fence-p)))
614
615 (add-hook 'egg-enter/leave-fence-hook 'egg-conversion-enter/leave-fence)
616
617 (defun egg-exit-conversion-unread-char ()
618   (interactive)
619   (setq egg-context (egg-exit-conversion)
620         unread-command-events (list last-command-event)
621         this-command 'egg-use-context))
622
623 (defun egg-make-bunsetsu (backend bunsetsu last)
624   (let* ((converted (copy-sequence (egg-get-bunsetsu-converted bunsetsu)))
625          (language (egg-get-converted-language bunsetsu))
626          (continue (and (null last) (egg-major-bunsetsu-continue-p bunsetsu)))
627          (face (egg-get-conversion-face language))
628          len len1)
629     (setq len1 (length converted))
630     (or (eq last t)
631         (setq converted (concat converted
632                                 (if continue
633                                     egg-conversion-minor-separator
634                                   egg-conversion-major-separator))))
635     (setq len (length converted))
636     (egg-remove-all-text-properties 0 len converted)
637     (add-text-properties 0 len
638                          (list 'read-only          t
639                                (egg-bunsetsu-info) bunsetsu
640                                'egg-backend        backend
641                                'egg-lang           language
642                                'egg-bunsetsu-last  last
643                                'egg-major-continue continue
644                                'point-entered      'egg-enter/leave-fence
645                                'point-left         'egg-enter/leave-fence
646                                'modification-hooks '(egg-modify-fence))
647                          converted)
648     (if face
649         (egg-set-face 0 len1 face converted))
650     converted))
651
652 (defun egg-insert-bunsetsu-list (backend bunsetsu-list &optional last before)
653   (let ((len (length bunsetsu-list)))
654     (funcall (if before 'insert-before-markers 'insert)
655              (mapconcat
656               (lambda (b)
657                 (setq len (1- len))
658                 (egg-make-bunsetsu backend b (and (= len 0) last)))
659               bunsetsu-list nil))))
660
661 (defun egg-beginning-of-conversion-buffer (n)
662   (interactive "p")
663   (cond
664    ((<= n 0)
665     (egg-end-of-conversion-buffer 1))
666    ((null (get-text-property (1- (point)) 'egg-start))
667     (goto-char (previous-single-property-change (point) 'egg-start)))))
668
669 (defun egg-end-of-conversion-buffer(n)
670   (interactive "p")
671   (cond
672    ((<= n 0)
673     (egg-beginning-of-conversion-buffer 1))
674    (t
675     (goto-char (next-single-property-change (point) 'egg-end))
676     (backward-char))))
677
678 (defun egg-backward-bunsetsu (n)
679   (interactive "p")
680   (while (and (> n 0)
681               (null (get-text-property (1- (point)) 'egg-start)))
682     (backward-char)
683     (setq n (1- n)))
684   (if (> n 0)
685       (signal 'beginning-of-buffer nil)))
686
687 (defun egg-forward-bunsetsu (n)
688   (interactive "p")
689   (while (and (>= n 0)
690               (null (get-text-property (point) 'egg-end)))
691     (forward-char)
692     (setq n (1- n)))
693   (backward-char)
694   (if (>= n 0)
695       (signal 'end-of-buffer nil)))
696 \f
697 (defun egg-get-bunsetsu-tail (b)
698   (nth (1- (length b)) b))
699
700 (defun egg-previous-bunsetsu-point (p &optional n obj lim)
701   (or n (setq n 1))
702   (while (> n 0)
703     (setq p (previous-single-property-change p (egg-bunsetsu-info) obj lim)
704           n (1- n)))
705   p)
706
707 (defun egg-next-bunsetsu-point (p &optional n obj lim)
708   (or n (setq n 1))
709   (while (> n 0)
710     (setq p (egg-next-single-property-change p (egg-bunsetsu-info) obj lim)
711           n (1- n)))
712   p)
713
714 (defun egg-get-previous-bunsetsu (p)
715   (and (null (egg-get-bunsetsu-last (1- p)))
716        (egg-get-bunsetsu-info (1- p))))
717
718 (defun egg-get-previous-major-bunsetsu (p)
719   (let ((prev (egg-get-previous-bunsetsu p))
720         bunsetsu)
721     (while prev
722       (setq bunsetsu (cons prev bunsetsu)
723             p (egg-previous-bunsetsu-point p)
724             prev (and (egg-get-major-continue (1- p))
725                       (egg-get-bunsetsu-info (1- p)))))
726     bunsetsu))
727
728 (defun egg-get-next-bunsetsu (p)
729   (and (null (egg-get-bunsetsu-last p))
730        (egg-get-bunsetsu-info (egg-next-bunsetsu-point p))))
731
732 (defun egg-get-major-bunsetsu (p)
733   (let ((next (egg-get-bunsetsu-info p))
734         bunsetsu)
735     (while next
736       (setq bunsetsu (cons next bunsetsu)
737             p (egg-next-bunsetsu-point p)
738             next (and (egg-get-major-continue (1- p))
739                       (egg-get-bunsetsu-info p))))
740     (nreverse bunsetsu)))
741
742 (defsubst egg-get-major-bunsetsu-source (list)
743   (mapconcat 'egg-get-bunsetsu-source list nil))
744
745 (defsubst egg-get-major-bunsetsu-converted (list)
746   (mapconcat 'egg-get-bunsetsu-converted list nil))
747
748 (defvar egg-inspect-mode nil
749   "*Display clause information on candidate selection, if non-NIL.")
750
751 (defun egg-toggle-inspect-mode ()
752   (interactive)
753   (if (setq egg-inspect-mode (not egg-inspect-mode))
754       (egg-inspect-bunsetsu t)))
755
756 (defun egg-inspect-bunsetsu (&optional quiet)
757   (interactive)
758   (or (egg-word-inspection (egg-get-bunsetsu-info (point)))
759       quiet
760       (beep)))
761
762 (defvar egg-candidate-selection-info nil)
763 (make-variable-buffer-local 'egg-candidate-selection-info)
764
765 (defvar egg-candidate-selection-major t)
766 (make-variable-buffer-local 'egg-candidate-selection-major)
767
768 (defsubst egg-set-candsel-info (b major)
769   (setq egg-candidate-selection-info (list (car b) (cadr b) (caddr b) major)))
770
771 (defsubst egg-candsel-last-bunsetsu () (car egg-candidate-selection-info))
772 (defsubst egg-candsel-last-prev-b () (nth 1 egg-candidate-selection-info))
773 (defsubst egg-candsel-last-next-b () (nth 2 egg-candidate-selection-info))
774 (defsubst egg-candsel-last-major () (nth 3 egg-candidate-selection-info))
775
776 (defun egg-major-bunsetsu-head-p (head bunsetsu)
777   (while (and head (eq (car head) (car bunsetsu)))
778     (setq head (cdr head)
779           bunsetsu (cdr bunsetsu)))
780   (null head))
781
782 (defun egg-major-bunsetsu-tail-p (tail bunsetsu)
783   (egg-major-bunsetsu-head-p
784    tail (nthcdr (- (length bunsetsu) (length tail)) bunsetsu)))
785
786 (defun egg-get-candsel-target-major ()
787   (let ((bunsetsu (egg-get-major-bunsetsu (point)))
788         (prev-b (egg-get-previous-major-bunsetsu (point)))
789         next-b)
790     (cond
791      ((and (egg-candsel-last-major)
792            (egg-major-bunsetsu-tail-p (egg-candsel-last-prev-b) prev-b)
793            (egg-major-bunsetsu-head-p (append (egg-candsel-last-bunsetsu)
794                                               (egg-candsel-last-next-b))
795                                       bunsetsu))
796       (setq bunsetsu (egg-candsel-last-bunsetsu)
797             prev-b (egg-candsel-last-prev-b)
798             next-b (egg-candsel-last-next-b)))
799      ((null (egg-get-bunsetsu-last
800              (egg-next-bunsetsu-point (point) (1- (length bunsetsu)))))
801       (setq next-b (egg-get-major-bunsetsu
802                     (egg-next-bunsetsu-point (point) (length bunsetsu))))))
803     (setq egg-candidate-selection-major t)
804     (list bunsetsu prev-b next-b t)))
805
806 (defun egg-get-candsel-target-minor ()
807   (let* ((bunsetsu (list (egg-get-bunsetsu-info (point))))
808          (prev-b (egg-get-previous-bunsetsu (point)))
809          (next-b (egg-get-next-bunsetsu (point))))
810     (setq egg-candidate-selection-major nil)
811     (list bunsetsu (and prev-b (list prev-b)) (and next-b (list next-b)) nil)))
812
813 (defun egg-check-candsel-target (b prev-b next-b major)
814   (if major
815       (and (egg-major-bunsetsu-tail-p
816             prev-b (egg-get-previous-major-bunsetsu (point)))
817            (let* ((cur-b (egg-get-major-bunsetsu (point)))
818                   (next-p (egg-next-bunsetsu-point (point) (length cur-b))))
819              (egg-major-bunsetsu-head-p
820               (append b next-b)
821               (append cur-b (and (null (egg-get-bunsetsu-last (1- next-p)))
822                                  (egg-get-major-bunsetsu next-p))))))
823     (and (eq (egg-get-bunsetsu-info (point)) (car b))
824          (eq (egg-get-previous-bunsetsu (point)) (car prev-b))
825          (eq (egg-get-next-bunsetsu (point)) (car next-b)))))
826
827 (defun egg-insert-new-bunsetsu (b tail new-b)
828   (let* ((backend (egg-get-backend (point)))
829          (start (egg-previous-bunsetsu-point (point) (length (cadr new-b))))
830          (end (egg-next-bunsetsu-point (point) (+ (length b) (length tail))))
831          (last (egg-get-bunsetsu-last (1- end)))
832          (insert-before (buffer-has-markers-at end)))
833     (cond
834      ((buffer-has-markers-at end)
835       (delete-region start end)
836       (egg-insert-bunsetsu-list backend
837                                 (append (cadr new-b) (car new-b) (caddr new-b))
838                                 last t))
839      ((buffer-has-markers-at (egg-next-bunsetsu-point (point) (length b)))
840       (delete-region start end)
841       (egg-insert-bunsetsu-list backend (append (cadr new-b) (car new-b))
842                                 nil t)
843       (egg-insert-bunsetsu-list backend (caddr new-b) last))
844      ((buffer-has-markers-at (point))
845       (delete-region start end)
846       (egg-insert-bunsetsu-list backend (cadr new-b) nil t)
847       (egg-insert-bunsetsu-list backend (append (car new-b) (caddr new-b))
848                                 last))
849      (t
850       (delete-region start end)
851       (egg-insert-bunsetsu-list backend
852                                 (append (cadr new-b) (car new-b) (caddr new-b))
853                                 last)))
854     (goto-char (egg-next-bunsetsu-point start (length (cadr new-b))))
855     (if egg-inspect-mode
856         (egg-inspect-bunsetsu t))))
857
858 (defun egg-next-candidate (n)
859   (interactive "p")
860   (if egg-candidate-selection-major
861       (egg-next-candidate-major n)
862     (egg-next-candidate-minor n)))
863
864 (defun egg-next-candidate-major (n)
865   (interactive "p")
866   (apply 'egg-next-candidate-internal n (egg-get-candsel-target-major)))
867
868 (defun egg-next-candidate-minor (n)
869   (interactive "p")
870   (apply 'egg-next-candidate-internal n (egg-get-candsel-target-minor)))
871
872 (defun egg-previous-candidate (n)
873   (interactive "p")
874   (if egg-candidate-selection-major
875       (egg-previous-candidate-major n)
876     (egg-previous-candidate-minor n)))
877
878 (defun egg-previous-candidate-major (n)
879   (interactive "p")
880   (apply 'egg-next-candidate-internal (- n) (egg-get-candsel-target-major)))
881
882 (defun egg-previous-candidate-minor (n)
883   (interactive "p")
884   (apply 'egg-next-candidate-internal (- n) (egg-get-candsel-target-minor)))
885
886 (defvar egg-candidate-select-counter 1)
887 (make-variable-buffer-local 'egg-candidate-select-counter)
888
889 (defun egg-next-candidate-internal (n b prev-b next-b major)
890   (if (eq last-command (if major 'egg-candidate-major 'egg-candidate-minor))
891       (setq egg-candidate-select-counter (1+ egg-candidate-select-counter))
892     (setq egg-candidate-select-counter 1))
893   (if (= egg-candidate-select-counter egg-conversion-auto-candidate-menu)
894       (egg-select-candidate-internal 
895        nil egg-conversion-auto-candidate-menu-show-all
896        b prev-b next-b major)
897     (setq this-command (if major 'egg-candidate-major 'egg-candidate-minor))
898     (let ((inhibit-read-only t)
899           new-b candidates nitem i beep)
900       (setq candidates (egg-list-candidates b prev-b next-b major))
901       (if (null candidates)
902           (setq beep t)
903         (setq i (+ n (car candidates))
904               nitem (length (cdr candidates)))
905         (cond
906          ((< i 0)                       ; go backward as if it is ring
907           (setq i (% i nitem))
908           (if (< i 0)
909               (setq i (+ i nitem))))
910          ((< i nitem))                  ; OK
911          (egg-conversion-wrap-select    ; go backward as if it is ring
912           (setq i (% i nitem)))
913          (t                             ; don't go forward 
914           (setq i (1- nitem)
915                 beep t)))
916         (setq new-b (egg-decide-candidate b i prev-b next-b))
917         (egg-set-candsel-info new-b major)
918         (egg-insert-new-bunsetsu b (caddr new-b) new-b))
919       (if beep
920           (ding)))))
921
922 (defun egg-numbering-item (list)
923   (let ((n -1))
924     (mapcar (lambda (item) (cons item (setq n (1+ n)))) list)))
925
926 (defun egg-sort-item (list sort)
927   (if (eq (null sort) (null egg-conversion-sort-by-converted-string))
928       list
929     (sort list (lambda (a b) (string< (car a) (car b))))))
930
931 (defun egg-select-candidate-major (sort)
932   (interactive "P")
933   (apply 'egg-select-candidate-internal sort nil (egg-get-candsel-target-major)))
934
935 (defun egg-select-candidate-minor (sort)
936   (interactive "P")
937   (apply 'egg-select-candidate-internal sort nil (egg-get-candsel-target-minor)))
938
939 (defun egg-select-candidate-list-all-major (sort)
940   (interactive "P")
941   (apply 'egg-select-candidate-internal sort t (egg-get-candsel-target-major)))
942
943 (defun egg-select-candidate-list-all-minor (sort)
944   (interactive "P")
945   (apply 'egg-select-candidate-internal sort t (egg-get-candsel-target-minor)))
946
947 (defun egg-select-candidate-internal (sort all b prev-b next-b major)
948   (let ((prompt (egg-get-message 'candidate))
949         new-b candidates pos clist item-list i)
950     (setq candidates (egg-list-candidates b prev-b next-b major))
951     (if (null candidates)
952         (ding)
953       (setq pos (car candidates)
954             clist (cdr candidates)
955             item-list (egg-sort-item (egg-numbering-item clist) sort)
956             i (menudiag-select (list 'menu prompt item-list)
957                                all
958                                (list (assq (nth pos clist) item-list))))
959       (if (or (null (egg-conversion-fence-p))
960               (null (egg-check-candsel-target b prev-b next-b major)))
961           (error "Fence was already modified")
962         (let ((inhibit-read-only t))
963           (setq new-b (egg-decide-candidate b i prev-b next-b))
964           (egg-set-candsel-info new-b major)
965           (egg-insert-new-bunsetsu b (caddr new-b) new-b))))))
966
967 (defun egg-hiragana (&optional minor)
968   (interactive "P")
969   (if (null minor)
970       (apply 'egg-special-convert this-command (egg-get-candsel-target-major))
971     (apply 'egg-special-convert this-command (egg-get-candsel-target-minor))))
972
973 (defalias 'egg-katakana 'egg-hiragana)
974 (defalias 'egg-pinyin 'egg-hiragana)
975 (defalias 'egg-zhuyin 'egg-hiragana)
976 (defalias 'egg-hangul 'egg-hiragana)
977
978 (defun egg-special-convert (type b prev-b next-b major)
979   (let ((inhibit-read-only t)
980         (new-b (egg-special-candidate b prev-b next-b major type)))
981     (if (null new-b)
982         (ding)
983       (egg-set-candsel-info new-b major)
984       (egg-insert-new-bunsetsu b (caddr new-b) new-b))))
985
986 (defun egg-separate-characters (str)
987   (let* ((v (egg-string-to-vector str))
988          (len (length v))
989          (i 0) (j 0) m n (nchar 0))
990     (while (< i len)
991       (if (setq n (egg-chinese-syllable str j))
992           (setq m (egg-chars-in-period str j n))
993         (setq m 1 n (egg-char-bytes (aref v i))))
994       (put-text-property j (+ j n) 'egg-char-size n str)
995       (setq nchar (1+ nchar) i (+ i m) j (+ j n)))
996     nchar))
997
998 (defun egg-enlarge-bunsetsu-major (n)
999   (interactive "p")
1000   (egg-enlarge-bunsetsu-internal n t))
1001
1002 (defun egg-enlarge-bunsetsu-minor (n)
1003   (interactive "p")
1004   (egg-enlarge-bunsetsu-internal n nil))
1005
1006 (defun egg-shrink-bunsetsu-major (n)
1007   (interactive "p")
1008   (egg-enlarge-bunsetsu-internal (- n) t))
1009
1010 (defun egg-shrink-bunsetsu-minor (n)
1011   (interactive "p")
1012   (egg-enlarge-bunsetsu-internal (- n) nil))
1013
1014 (defun egg-enlarge-bunsetsu-internal (n major)
1015   (let ((inhibit-read-only t)
1016         b prev-b next-b new-b s1 s1len s2 s2len nchar i last end beep)
1017     (if major
1018         (setq b (egg-get-major-bunsetsu (point))
1019               prev-b (egg-get-previous-major-bunsetsu (point)))
1020       (setq b (list (egg-get-bunsetsu-info (point)))
1021             prev-b (egg-get-previous-bunsetsu (point))
1022             prev-b (and prev-b (list prev-b))))
1023     (setq end (egg-next-bunsetsu-point (point) (length b))
1024           last (egg-get-bunsetsu-last (1- end)))
1025     (while (null last)
1026       (setq next-b (cons (egg-get-bunsetsu-info end) next-b)
1027             last (egg-get-bunsetsu-last end)
1028             end (egg-next-bunsetsu-point end)))
1029     (setq next-b (nreverse next-b)
1030           s1 (egg-get-major-bunsetsu-source b)
1031           s2 (concat s1 (egg-get-major-bunsetsu-source next-b))
1032           s1len (egg-separate-characters s1)
1033           s2len (egg-separate-characters s2)
1034           n (+ n s1len))
1035     (cond
1036      ((<= n 0)
1037       (setq beep t nchar (and (/= s1len 1) (egg-get-char-size 0 s1))))
1038      ((> n s2len)
1039       (setq beep t nchar (and (/= s2len s1len) (length s2))))
1040      (t
1041       (setq nchar 0)
1042       (while (> n 0)
1043         (setq nchar (+ nchar (egg-get-char-size nchar s2))
1044               n (1- n)))))
1045     (when nchar
1046       (setq next-b (nconc b next-b)
1047             i (length (egg-get-bunsetsu-source (car next-b))))
1048       (while (< i nchar)
1049         (setq next-b (cdr next-b)
1050               i (+ i (length (egg-get-bunsetsu-source (car next-b))))))
1051       (setq next-b (prog1 (cdr next-b) (setcdr next-b nil))
1052             new-b (egg-change-bunsetsu-length b prev-b next-b nchar major))
1053       (if (null new-b)
1054           (setq beep t)
1055         (egg-insert-new-bunsetsu b (and (caddr new-b) next-b) new-b)))
1056     (if beep
1057         (ding))))
1058
1059 (defun egg-reconvert-bunsetsu (n)
1060   (interactive "P")
1061   (egg-reconvert-bunsetsu-internal n 'egg-get-bunsetsu-converted))
1062
1063 (defun egg-reconvert-bunsetsu-from-source (n)
1064   (interactive "P")
1065   (egg-reconvert-bunsetsu-internal n 'egg-get-bunsetsu-source))
1066
1067 (defun egg-reconvert-bunsetsu-internal (n func)
1068   (let* ((inhibit-read-only t)
1069          (backend (egg-get-backend (point)))
1070          (source (funcall func (egg-get-bunsetsu-info (point))))
1071          (reconv-backend (egg-get-reconvert-backend backend n))
1072          (p (point))
1073          (last (egg-get-bunsetsu-last (point)))
1074          new prev-b next-b)
1075     (if (or (null reconv-backend)
1076             (null (setq new (egg-start-conversion reconv-backend source nil))))
1077         (ding)
1078       (delete-region p (egg-next-bunsetsu-point p))
1079       (setq next-b (egg-get-bunsetsu-info (point)))
1080       (if (and (equal (egg-get-backend p) backend)
1081                (eq (egg-bunsetsu-get-backend next-b)
1082                    (egg-bunsetsu-get-backend (car new)))
1083                (egg-bunsetsu-combinable-p (egg-get-bunsetsu-tail new) next-b))
1084           (setq last nil)
1085         (setq last (or (eq last t) 'continue)))
1086       (egg-insert-bunsetsu-list backend new last)
1087       (goto-char p)
1088       (setq prev-b (egg-get-bunsetsu-info (1- p)))
1089       (if prev-b
1090           (progn
1091             (if (and (equal (egg-get-backend (1- p)) backend)
1092                      (eq (egg-bunsetsu-get-backend prev-b)
1093                          (egg-bunsetsu-get-backend (car new)))
1094                      (egg-bunsetsu-combinable-p prev-b (car new)))
1095                 (setq last nil)
1096               (setq last (or (eq last t) 'continue)))
1097             (setq backend (egg-get-backend (1- p)))
1098             (delete-region (egg-previous-bunsetsu-point p) p)
1099             (egg-insert-bunsetsu-list backend (list prev-b) last))))))
1100
1101 (defun egg-decide-before-point ()
1102   (interactive)
1103   (let* ((inhibit-read-only t)
1104          (start (if (get-text-property (1- (point)) 'egg-start)
1105                     (point)
1106                   (previous-single-property-change (point) 'egg-start)))
1107          (end (if (get-text-property (point) 'egg-end)
1108                   (point)
1109                 (next-single-property-change (point) 'egg-end)))
1110          (decided (buffer-substring start (point)))
1111          (undecided (buffer-substring (point) end))
1112          i len bunsetsu source context)
1113     (delete-region
1114      (previous-single-property-change start 'egg-start nil (point-min))
1115      (next-single-property-change end 'egg-end nil (point-max)))
1116     (setq i 0
1117           len (length decided))
1118     (while (< i len)
1119       (setq bunsetsu (nconc bunsetsu (list (egg-get-bunsetsu-info i decided)))
1120             i (egg-next-bunsetsu-point i 1 decided len))
1121       (if (or (= i len)
1122               (egg-get-bunsetsu-last (1- i) decided))
1123           (progn
1124             (insert (mapconcat 'egg-get-bunsetsu-converted bunsetsu nil))
1125             (setq context (cons (cons (egg-bunsetsu-get-backend (car bunsetsu))
1126                                       (egg-end-conversion bunsetsu nil))
1127                                 context)
1128                   bunsetsu nil))))
1129     (setq len (length undecided))
1130     (if (= len 0)
1131         (progn
1132           (egg-do-auto-fill)
1133           (run-hooks 'input-method-after-insert-chunk-hook)
1134           context)
1135       (setq i 0)
1136       (while (< i len)
1137         (setq bunsetsu (egg-get-bunsetsu-info i undecided)
1138               source (cons (egg-get-bunsetsu-source bunsetsu)
1139                            source))
1140         (put-text-property 0 (length (car source))
1141                            'egg-lang
1142                            (egg-get-source-language bunsetsu)
1143                            (car source))
1144         (setq i (egg-next-bunsetsu-point i 1 undecided len)))
1145       (its-restart (apply 'concat (nreverse source)) t t context))))
1146
1147 (defun egg-decide-first-char ()
1148   (interactive)
1149   (let* ((inhibit-read-only t)
1150          (start (if (get-text-property (1- (point)) 'egg-start)
1151                     (point)
1152                   (previous-single-property-change (point) 'egg-start)))
1153          (end (if (get-text-property (point) 'egg-end)
1154                   (point)
1155                 (next-single-property-change (point) 'egg-end)))
1156          (bunsetsu (egg-get-bunsetsu-info start)))
1157     (delete-region
1158      (previous-single-property-change start 'egg-start nil (point-min))
1159      (next-single-property-change end 'egg-end nil (point-max)))
1160     (egg-end-conversion (list bunsetsu) nil)
1161     (insert (egg-string-to-char-at (egg-get-bunsetsu-converted bunsetsu) 0))))
1162
1163 (defun egg-exit-conversion ()
1164   (interactive)
1165   (if (egg-conversion-fence-p)
1166       (progn
1167         (goto-char (next-single-property-change (point) 'egg-end))
1168         (egg-decide-before-point))))
1169
1170 (defun egg-abort-conversion ()
1171   (interactive)
1172   (let ((inhibit-read-only t)
1173         source context)
1174     (goto-char (previous-single-property-change
1175                 (if (get-text-property (1- (point)) 'egg-start)
1176                     (point)
1177                   (previous-single-property-change (point) 'egg-start))
1178                 'egg-start nil (point-min)))
1179     (setq source (get-text-property (point) 'egg-source)
1180           context (get-text-property (point) 'egg-context))
1181     (delete-region (point) (next-single-property-change
1182                             (next-single-property-change (point) 'egg-end)
1183                             'egg-end nil (point-max)))
1184     (its-restart source nil nil context)))
1185
1186 (defun egg-toroku-bunsetsu ()
1187   (interactive)
1188   (let* ((p (point))
1189          (lang (egg-get-source-language (egg-get-bunsetsu-info p)))
1190          (egg-mode-hook (or (cdr (assq lang its-select-func-alist))
1191                             (cdr (assq lang its-select-func-default-alist))))
1192          (s "")
1193          bunsetsu str yomi last)
1194     (while (null last)
1195       (setq bunsetsu (egg-get-bunsetsu-info p)
1196             str (concat str (egg-get-bunsetsu-converted bunsetsu))
1197             yomi (concat yomi (egg-get-bunsetsu-source bunsetsu))
1198             last (egg-get-bunsetsu-last p)
1199             p (egg-next-bunsetsu-point p)))
1200     (while (equal s "")
1201       (setq s (read-multilingual-string (egg-get-message 'register-str)
1202                                         str egg-last-method-name))
1203       (and (equal s "") (ding)))
1204     (egg-toroku-string s nil yomi lang (egg-bunsetsu-get-backend bunsetsu))))
1205
1206 (defun egg-toroku-region (start end &optional nth-backend)
1207   (interactive "r\nP")
1208   (egg-toroku-string (buffer-substring start end) nil nil nil nil nth-backend))
1209
1210 (defun egg-toroku-string (str &optional yomi guess lang backend nth-backend)
1211   (let (egg-mode-hook result)
1212     (if (= (length str) 0)
1213         (egg-error "Egg word registration: null string"))
1214     (egg-separate-languages str lang)
1215     (setq lang (egg-get-language 0 str)
1216           egg-mode-hook (or (cdr (assq lang its-select-func-alist))
1217                             (cdr (assq lang its-select-func-default-alist))))
1218     (or yomi (setq yomi ""))
1219     (while (equal yomi "")
1220       (setq yomi (read-multilingual-string
1221                   (format (egg-get-message 'register-yomi) str)
1222                   guess egg-last-method-name))
1223       (and (equal yomi "") (ding)))
1224     (egg-separate-languages yomi lang)
1225     (if (null backend)
1226         (progn
1227           (setq backend (egg-assign-backend str nth-backend))
1228           (if (cdr backend)
1229               (egg-error "Egg word registration: cannot decide backend"))
1230           (setq backend (egg-get-current-backend (caar backend)))))
1231     (setq result (egg-word-registration backend str yomi))
1232     (if result
1233         (apply 'message (egg-get-message 'registered) str yomi result)
1234       (beep))))
1235 \f
1236 (defun egg-conversion-mode ()
1237   "\\{egg-conversion-map}"
1238   ;; dummy function to get docstring
1239   )
1240
1241 (defun egg-help-command ()
1242   "Display documentation for EGG Conversion mode."
1243   (interactive)
1244   (with-output-to-temp-buffer "*Help*"
1245     (princ "EGG Conversion mode:\n")
1246     (princ (documentation 'egg-conversion-mode))
1247     (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p))))
1248
1249 (provide 'egg-cnv)
1250 ;;; egg-cnv.el ends here.