Sync up with egg-980404.
[elisp/egg.git] / egg-cnv.el
1 ;;; egg-cnv.el --- Conversion Backend in Egg Input Method Architecture
2
3 ;; Copyright (C) 1997, 1998 Mule Project,
4 ;; Powered by Electrotechnical Laboratory, JAPAN.
5 ;; Project Leader: Satoru Tomura <tomura@etl.go.jp>
6
7 ;; Author: NIIBE Yutaka <gniibe@mri.co.jp>
8 ;;         KATAYAMA Yoshio <kate@pfu.co.jp>
9 ;; Maintainer: NIIBE Yutaka <gniibe@mri.co.jp>
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 (defvar egg-current-language)
35 (make-variable-buffer-local 'egg-current-language)
36 (put 'egg-current-language 'permanent-local t)
37
38 (defsubst egg-bunsetsu-info () 'intangible)
39
40 (defun egg-get-bunsetsu-info (p)
41   (let ((bunsetsu-info (get-text-property p (egg-bunsetsu-info))))
42     (if bunsetsu-info
43         (setq egg-conversion-backend (get-text-property p 'egg-backend)
44               egg-current-language (get-text-property p 'egg-lang)))
45     bunsetsu-info))
46 ;;
47
48 (defconst egg-conversion-backend-other-languages
49   [ egg-init-other-languages
50
51         egg-start-conversion-other-languages
52       egg-get-bunsetsu-converted-other-languages
53       egg-get-bunsetsu-source-other-languages
54       egg-list-candidates-other-languages
55           egg-get-number-of-candidates-other-languages
56           egg-get-current-candidate-number-other-languages
57           egg-get-all-candidates-other-languages
58           egg-decide-candidate-other-languages
59       egg-change-bunsetsu-length-other-languages
60     egg-end-conversion-other-languages
61     nil
62
63     egg-fini-other-languages
64  ])
65
66 (defun egg-init-other-languages ()
67   )
68
69 (defun egg-start-conversion-other-languages (yomi-string language)
70   (list yomi-string))
71 (defun egg-get-bunsetsu-converted-other-languages (bunsetsu-info)
72   bunsetsu-info)
73 (defun egg-get-bunsetsu-source-other-languages (bunsetsu-info)
74   bunsetsu-info)
75 (defun egg-list-candidates-other-languages (bunsetsu-info prev-bunsetsu-info)
76   1)
77 (defun egg-get-number-of-candidates-other-languages (bunsetsu-info)
78   1)
79 (defun egg-get-current-candidate-number-other-languages (bunsetsu-info)
80   0)
81 (defun egg-get-all-candidates-other-languages (bunsetsu-info)
82   (list bunsetsu-info))
83 (defun egg-decide-candidate-other-languages (bunsetsu-info candidate-pos)
84   bunsetsu-info)
85 (defun egg-change-bunsetsu-length-other-languages (b0 b1 b2 len)
86   (let ((s (concat b1 b2)))
87     (set-text-properties 0 (length s) nil s)
88     (if (= len (length s))
89         (list s)
90       (list (substring s 0 len) (substring s len)))))
91 (defun egg-end-conversion-other-languages (bunsetsu-info-list abort)
92   nil)
93 (defun egg-fini-other-languages (language)
94   nil)
95
96 (defvar egg-conversion-backend-alist nil)
97 (make-variable-buffer-local 'egg-conversion-backend-alist)
98 (defvar egg-conversion-backend nil)
99 (make-variable-buffer-local 'egg-conversion-backend)
100
101 (defvar egg-finalize-backend-alist nil)
102
103 (defun egg-set-current-backend (language)
104   (setq egg-conversion-backend
105         (cdr (assoc language egg-conversion-backend-alist)))
106   (if (null egg-conversion-backend)
107       (setq egg-conversion-backend egg-conversion-backend-other-languages)))
108
109 (defun egg-initialize-backend (language)
110   (egg-set-current-backend language)
111   (funcall (aref egg-conversion-backend 0)))
112
113 (defun egg-start-conversion (yomi-string language)
114   (egg-set-current-backend language)
115   (funcall (aref egg-conversion-backend 1) yomi-string language))
116 (defun egg-get-bunsetsu-converted (bunsetsu-info)
117   (funcall (aref egg-conversion-backend 2) bunsetsu-info))
118 (defun egg-get-bunsetsu-source (bunsetsu-info)
119   (funcall (aref egg-conversion-backend 3) bunsetsu-info))
120 (defun egg-list-candidates (bunsetsu-info prev-bunsetsu-info)
121   (funcall (aref egg-conversion-backend 4) bunsetsu-info prev-bunsetsu-info))
122 (defun egg-get-number-of-candidates (bunsetsu-info)
123   (funcall (aref egg-conversion-backend 5) bunsetsu-info))
124 (defun egg-get-current-candidate-number (bunsetsu-info)
125   (funcall (aref egg-conversion-backend 6) bunsetsu-info))
126 (defun egg-get-all-candidates (bunsetsu-info)
127   (funcall (aref egg-conversion-backend 7) bunsetsu-info))
128 (defun egg-decide-candidate (bunsetsu-info candidate-pos)
129   (funcall (aref egg-conversion-backend 8) bunsetsu-info candidate-pos))
130 (defun egg-change-bunsetsu-length (b0 b1 b2 len)
131   (funcall (aref egg-conversion-backend 9) b0 b1 b2 len))
132 (defun egg-end-conversion (bunsetsu-info-list abort)
133   (funcall (aref egg-conversion-backend 10) bunsetsu-info-list abort))
134 (defun egg-start-reverse-conversion (yomi-string language)
135   (egg-set-current-backend language)
136   (if (aref egg-conversion-backend 11)
137       (funcall (aref egg-conversion-backend 11) yomi-string language)
138     (beep)))
139
140 (defun egg-finalize-backend ()
141   (let ((alist egg-finalize-backend-alist))
142     (while alist
143       (funcall (car (car (car alist))) (cdr (car (car alist))))
144       (setq alist (cdr alist)))))
145
146 (defun egg-set-conversion-backend (backend langs &optional force)
147   (let (pair)
148     (if backend
149         (setq egg-conversion-backend backend)
150       (setq backend egg-conversion-backend))
151     (while langs
152       (setq pair (assoc (car langs) egg-conversion-backend-alist))
153       (cond
154        ((null pair)
155         (setq egg-conversion-backend-alist
156               (cons (cons (car langs) backend) egg-conversion-backend-alist)))
157        (force
158         (setcdr pair backend)))
159       (setq pair (cons (aref backend (1- (length backend))) (car langs)))
160       (if (null (assoc pair egg-finalize-backend-alist))
161           (setq egg-finalize-backend-alist
162                 (cons (list pair) egg-finalize-backend-alist)))
163       (setq langs (cdr langs)))))
164 \f
165 (defvar egg-conversion-open  "|"  "*\e$B%U%'%s%9$N;OE@$r<($9J8;zNs\e(B (1 \e$BJ8;z0J>e\e(B)")
166 (defvar egg-conversion-close "|"  "*\e$B%U%'%s%9$N=*E@$r<($9J8;zNs\e(B (1 \e$BJ8;z0J>e\e(B)")
167 (defvar egg-conversion-face  nil  "*\e$B%U%'%s%9I=<($KMQ$$$k\e(B face \e$B$^$?$O\e(B nil")
168 (defvar egg-conversion-separator " ")
169
170 (defun egg-get-conversion-face ()
171   (let ((face (and (listp egg-conversion-face)
172                    (or (assoc egg-current-language egg-conversion-face)
173                        (assoc t egg-conversion-face)))))
174     (if face (cdr face) egg-conversion-face)))
175
176 ;;
177 (defun egg-convert-region (start end)
178   (interactive "r")
179   (if (>= start end)
180       ;; nothing to do
181       nil
182     (remove-text-properties start end '(read-only nil intangible nil))
183     (goto-char start)
184     (insert egg-conversion-open)
185     (let ((inhibit-read-only t)
186           (max (make-marker))
187           bunsetsu-info-list contin p s e result)
188       (setq p (+ (point) (- end start)))
189       (set-text-properties start (point)
190                            (list
191                             'read-only t
192                             'egg-start t
193                             'egg-source (buffer-substring (point) p)))
194       (if egg-conversion-face
195           (put-text-property start (point) 'invisible t))
196       (setq start (point))
197       (goto-char p)
198       (insert egg-conversion-close)
199       (set-text-properties p (point) '(read-only t rear-nonsticky t egg-end t))
200       (if egg-conversion-face
201           (put-text-property p (point) 'invisible t))
202       (set-marker max p)
203       (egg-separate-languages start max)
204       (goto-char start)
205       (while (< (point) max)
206         (setq egg-current-language (get-text-property (point) 'egg-lang)
207               s (point)
208               e (point))
209         (while (and (< e max)
210                     (equal egg-current-language
211                            (get-text-property e 'egg-lang)))
212           (setq e (next-single-property-change e 'egg-lang nil max)))
213         (condition-case result
214             (setq bunsetsu-info-list
215                   (egg-start-conversion
216                    (buffer-substring-no-properties s e)
217                    egg-current-language))
218           (error                        ; XXX: catching all error is BADBADBAD
219            (setq egg-conversion-backend egg-conversion-backend-other-languages
220                  bunsetsu-info-list (egg-start-conversion-other-languages
221                                      (buffer-substring-no-properties s e)
222                                      egg-current-language))
223            (message "egg %s backend: %s" egg-current-language (cadr result))))
224         (setq contin (< e max))
225         (delete-region s e)
226         (egg-insert-bunsetsu-list bunsetsu-info-list
227                                   (if (< (point) max) 'contine t)))
228       (set-marker max nil)
229       (goto-char start))))
230
231 (defun egg-separate-languages (start end &optional use-context)
232   (let (lang last-lang last-chinese p pe l c cset)
233     ;; 1st pass -- mark undefined Chinese part
234     (goto-char start)
235     (and use-context
236          (setq last-lang (get-text-property (1- (point)) 'egg-lang))
237          (or (equal last-lang "Chinese-GB") (equal last-lang "Chinese-CNS"))
238          (setq last-chinese last-lang))
239     (while (< (point) end)
240       (setq p (point)
241             pe (next-single-property-change (point) 'egg-lang nil end))
242       (cond
243        ((get-text-property (point) 'egg-lang)
244         (goto-char pe)
245         (setq lang nil))
246        ((setq l (egg-chinese-syllable (buffer-substring p pe)))
247         (goto-char (+ p l))
248         (setq lang "Chinese"))
249        ((progn
250           (setq c (following-char)
251                 cset (char-charset c))
252           (eq cset 'chinese-sisheng))
253         (forward-char)
254         (setq lang "Chinese"))
255        ((eq cset 'ascii)
256         (skip-chars-forward "\0-\177" pe)
257         (if (eq (char-charset (following-char)) 'chinese-sisheng)
258             (goto-char (max (1+ pp) (- (point) 6))))
259         (setq lang nil))
260        ((eq cset 'composition)
261         (forward-char)
262         (setq lang (egg-charset-to-language
263                     (char-charset (car (decompose-composite-char c 'list))))))
264        (t
265         (skip-chars-forward (concat (vector (make-char cset 33 33))
266                                     "-"
267                                     (vector (make-char cset 127 127)))
268                             pe)
269         (setq lang (egg-charset-to-language cset))))
270       (if lang
271           (put-text-property p (point) 'egg-lang lang)))
272     ;; 2nd pass -- set language property
273     (goto-char start)
274     (while (< (point) end)
275       (setq lang (get-text-property (point) 'egg-lang))
276       (cond
277        ((null lang)
278         (setq lang (or last-lang
279                        (egg-next-part-lang end))))
280        ((equal lang "Chinese")
281         (setq lang (or last-chinese
282                        (egg-next-chinese-lang end)))))
283       (setq last-lang lang)
284       (if (or (equal lang "Chinese-GB") (equal lang "Chinese-CNS"))
285           (setq last-chinese lang))
286       (setq p (point))
287       (goto-char (next-single-property-change (point) 'egg-lang nil end))
288       (set-text-properties p (point) (list 'egg-lang lang)))))
289
290 (defun egg-charset-to-language (charset)
291   (let ((list language-info-alist))
292     (while (and list
293                 (null (memq charset (assq 'charset (car list)))))
294       (setq list (cdr list)))
295     (car (car list))))
296
297 (defun egg-next-part-lang (end)
298   (let* ((p (next-single-property-change (point) 'egg-lang nil end))
299          (lang (get-text-property p 'egg-lang)))
300     (if (equal lang "Chinese")
301         (egg-next-chinese-lang end)
302       (or lang
303           its-current-language
304           egg-default-language))))
305
306 (defun egg-next-chinese-lang (end)
307   (let (p lang)
308     (setq p (point))
309     (while (and (< p end) (null lang))
310       (setq p (next-single-property-change p 'egg-lang nil end))
311       (setq lang (get-text-property p 'egg-lang))
312       (if (null (or (equal lang "Chinese-GB")
313                     (equal lang "Chinese-CNS")))
314           (setq lang nil)))
315     (cond
316      (lang lang)
317      ((or (equal its-current-language "Chinese-GB")
318           (equal its-current-language "Chinese-CNS"))
319       its-current-language)
320      ((or (equal egg-default-language "Chinese-GB")
321           (equal egg-default-language "Chinese-CNS"))
322       egg-default-language)
323      (t "Chinese-GB"))))
324 \f
325 (require 'its-keydef)
326
327 (defvar egg-conversion-map
328   (let ((map (make-sparse-keymap))
329         (i 33))
330     (while (< i 127)
331       (define-key map (vector i) 'egg-exit-conversion-unread-char)
332       (setq i (1+ i)))
333     (define-key map "\C-@" 'egg-decide-first-char)
334     (define-key map [?\C-\ ] 'egg-decide-first-char)
335     (define-key map "\C-a"   'egg-beginning-of-conversion-buffer)
336     (define-key map "\C-b"   'egg-backward-bunsetsu)
337     (define-key map "\C-c"   'egg-abort-conversion)
338     (define-key map "\C-e"   'egg-end-of-conversion-buffer)
339     (define-key map "\C-f"   'egg-forward-bunsetsu)
340     (define-key map "\C-h"   'egg-help-command)
341     (define-key map "\C-i"   'egg-shrink-bunsetsu)
342     (define-key map "\C-k"   'egg-decide-before-point)
343 ;;    (define-key map "\C-l"   'egg-exit-conversion)  ; Don't override C-L
344     (define-key map "\C-m"   'egg-exit-conversion)
345     (define-key map "\C-n"   'egg-next-candidate)
346     (define-key map "\C-o"   'egg-enlarge-bunsetsu)
347     (define-key map "\C-p"   'egg-previous-candidate)
348     (define-key map "\C-r"   'egg-reverse-convert-bunsetu)
349     (define-key map "\M-r"   'egg-reconvert-bunsetsu)
350     (define-key map "\M-s"   'egg-select-candidate)
351     (define-key map [return] 'egg-exit-conversion)
352     (define-key map [right]  'egg-forward-bunsetsu)
353     (define-key map [left]   'egg-backward-bunsetsu)
354     (define-key map " "      'egg-next-candidate)
355     (its-define-select-keys map)
356     map)
357   "Keymap for EGG Conversion mode.")
358
359 (defun egg-exit-conversion-unread-char ()
360   (interactive)
361   (setq unread-command-events (list last-command-event))
362   (egg-exit-conversion))
363
364 (defun egg-insert-bunsetsu (bunsetsu-info last)
365   (let ((bunsetsu (egg-get-bunsetsu-converted bunsetsu-info))
366         (p (point)) p1)
367     (insert bunsetsu)
368     (setq p1 (point))
369     (if (null (eq last t))
370         (insert egg-conversion-separator))
371     (set-text-properties p (point)
372                          (list 'read-only          t
373                                (egg-bunsetsu-info) bunsetsu-info
374                                'egg-backend        egg-conversion-backend
375                                'egg-lang           egg-current-language
376                                'egg-bunsetsu-last  last
377                                'local-map          egg-conversion-map))
378     (if egg-conversion-face
379         (egg-set-face p p1 (egg-get-conversion-face)))))
380
381 (defun egg-insert-bunsetsu-list (bunsetsu-info-list &optional last)
382   (let ((l bunsetsu-info-list)
383         bunsetsu-info)
384     (while l
385       (setq bunsetsu-info (car l)
386             l (cdr l))
387       (egg-insert-bunsetsu bunsetsu-info (and (null l) last)))))
388
389 (defun egg-beginning-of-conversion-buffer (n)
390   (interactive "p")
391   (cond
392    ((<= n 0)
393     (egg-end-of-conversion-buffer 1))
394    ((null (get-text-property (1- (point)) 'egg-start))
395     (goto-char (previous-single-property-change (1- (point)) 'egg-start)))))
396
397 (defun egg-end-of-conversion-buffer(n)
398   (interactive "p")
399   (cond
400    ((<= n 0)
401     (egg-beginning-of-conversion-buffer 1))
402    (t
403     (goto-char (next-single-property-change (point) 'egg-end))
404     (backward-char))))
405
406 (defun egg-backward-bunsetsu (n)
407   (interactive "p")
408   (let (start)
409     (while (and (null start) (> n 0))
410       (backward-char)
411       (if (setq start (get-text-property (point) 'egg-start))
412           (forward-char)
413         (setq n (1- n))))
414     (if (> n 0)
415         (signal 'beginning-of-buffer nil))))
416
417 (defun egg-forward-bunsetsu (n)
418   (interactive "p")
419   (let (end)
420     (while (and (null end) (> n 0))
421       (forward-char)
422       (if (setq end (get-text-property (point) 'egg-end))
423           (backward-char)
424         (setq n (1- n))))
425     (if (> n 0)
426         (signal 'end-of-buffer nil))))
427
428 (defun egg-get-previous-bunsetsu (p)
429   (and (null (get-text-property (1- p) 'egg-start))
430        (null (get-text-property (1- p) 'egg-bunsetsu-last))
431        (egg-get-bunsetsu-info (- p 2))))
432
433 (defun egg-separate-characters (str)
434   (let* ((v (string-to-vector str))
435          (len (length v))
436          (i 0) (j 0) m n (nchar 0))
437     (while (< i len)
438       (if (setq n (egg-chinese-syllable str j))
439           (setq m (chars-in-string (substring str j (+ j n))))
440         (setq m 1 n (char-bytes (aref v i))))
441       (put-text-property j (+ j n) 'egg-char-size n str)
442       (setq nchar (1+ nchar) i (+ i m) j (+ j n)))
443     nchar))
444
445 (defun egg-shrink-bunsetsu (n)
446   (interactive "p")
447   (egg-enlarge-bunsetsu (- n)))
448
449 (defun egg-enlarge-bunsetsu (n)
450   (interactive "p")
451   (let* ((inhibit-read-only t)
452          (b0 (egg-get-previous-bunsetsu (point)))
453          (b1 (egg-get-bunsetsu-info (point)))
454          (s1 (egg-get-bunsetsu-source b1))
455          (s1len (egg-separate-characters s1))
456          (s2len 0)
457          (chrs (length s1))
458          (last (get-text-property (point) 'egg-bunsetsu-last))
459          b2 s2 source bunsetsu-info-list beep)
460     (if (not last)
461         (let ((p2 (save-excursion (forward-char) (point))))
462           (setq b2 (egg-get-bunsetsu-info p2)
463                 s2 (egg-get-bunsetsu-source b2)
464                 s2len (egg-separate-characters s2)
465                 last (get-text-property p2 'egg-bunsetsu-last))))
466     (setq source (concat s1 s2))
467     (cond
468      ((<= n (- s1len))
469       (setq beep t chrs (get-text-property 0 'egg-char-size source)))
470      ((> n s2len)
471       (setq beep t chrs (length source)))
472      ((< n 0)
473       (while (< n 0)
474         (setq chrs (- chrs (get-text-property (1- chrs) 'egg-char-size source))
475               n (1+ n))))
476      (t
477       (while (> n 0)
478         (setq chrs (+ chrs (get-text-property chrs 'egg-char-size source))
479               n (1- n)))))
480     (setq bunsetsu-info-list (egg-change-bunsetsu-length b0 b1 b2 chrs))
481     (delete-region (point)
482                    (progn (forward-char) (if b2 (forward-char)) (point)))
483     (let ((p (point)))
484       (egg-insert-bunsetsu-list bunsetsu-info-list last)
485       (goto-char p))
486     (if beep
487         (ding))))
488
489 (defun egg-next-candidate (n)
490   (interactive "p")
491   (let ((inhibit-read-only t)
492         (last (get-text-property (point) 'egg-bunsetsu-last))
493         (b (egg-get-bunsetsu-info (point)))
494         new i max+ p beep)
495     (setq max+ (egg-get-number-of-candidates b))
496     (if (null max+)
497         (let ((prev-b (egg-get-previous-bunsetsu (point))))
498           (setq i (egg-list-candidates b prev-b)) ; there is a case I=/=0
499           (if (or (> n 1) (< n 0))      ; with N=/=1, start with I
500               (setq i (+ n i))          ; or else (N==1),
501             (setq i (if (= i 0) 1 0)))  ;   I:=1 when I was 0, or else I:=0
502           (setq max+ (egg-get-number-of-candidates b)))
503       (setq i (egg-get-current-candidate-number b))
504       (setq i (+ n i)))
505     (if (null max+)
506         (setq beep t)
507       (if (< i 0)                       ; go backward as if it is ring
508           (while (< i 0)
509             (setq i (+ i max+))))
510       (if (>= i max+)                   ; don't go forward 
511           (setq i (1- max+)
512                 beep t))
513       (setq new (egg-decide-candidate b i))
514       (setq p (point))
515       (delete-region p (progn (forward-char) (point)))
516       (egg-insert-bunsetsu new last)
517       (goto-char p))
518     (if beep
519         (ding))))
520
521 (defun egg-previous-candidate (n)
522   (interactive "p")
523   (egg-next-candidate (- n)))
524
525 (defun egg-reconvert-bunsetsu-internal (n func)
526   (let ((inhibit-read-only t)
527         (p (point))
528         source last bunsetsu-list)
529     (if (<= n 0)
530         (beep)
531       (while (and (null last) (> n 0))
532         (setq source (concat source
533                              (egg-get-bunsetsu-converted
534                               (egg-get-bunsetsu-info (point))))
535               last (get-text-property (point) 'egg-bunsetsu-last)
536               n (1- n))
537         (forward-char))
538       (cond
539        ((> n 0)
540         (beep))
541        ((setq bunsetsu-list (funcall func source egg-current-language))
542         (delete-region p (point))
543         (egg-insert-bunsetsu-list bunsetsu-list (if (eq last t) t 'contine))
544         (goto-char p)
545         (if (egg-get-previous-bunsetsu p)
546             (progn
547               (backward-char)
548               (put-text-property (point) p 'egg-bunsetsu-last 'contine)
549               (forward-char))))))))
550
551 (defun egg-reverse-convert-bunsetu (n)
552   (interactive "p")
553   (egg-reconvert-bunsetsu-internal n 'egg-start-reverse-conversion))
554
555 (defun egg-reconvert-bunsetsu (n)
556   (interactive "p")
557   (egg-reconvert-bunsetsu-internal n 'egg-start-conversion))
558
559 (defun egg-decide-before-point ()
560   (interactive)
561   (let ((inhibit-read-only t)
562         (len (length egg-conversion-open))
563         bunsetsu-list bl (p (point)) source lang s)
564     (save-restriction
565       (if (null (get-text-property (1- (point)) 'egg-start))
566           (goto-char (previous-single-property-change (point) 'egg-start)))
567       (narrow-to-region (- (point) len) p)
568       (setq bunsetsu-list (setq bl (list nil)))
569       (while (< (point) (point-max))
570         ;; delete sparator/open marker
571         (delete-region (- (point) len) (point))
572         (setq len 1
573               bl (setcdr bl (list (egg-get-bunsetsu-info (point)))))
574         (if (get-text-property (point) 'egg-bunsetsu-last)
575             (progn
576               (egg-end-conversion (cdr bunsetsu-list) nil)
577               (setq bunsetsu-list (setq bl (list nil)))))
578         (setq p (point))
579         (forward-char)
580         (set-text-properties p (point) nil)))
581     (if (cdr bunsetsu-list)
582         (egg-end-conversion (cdr bunsetsu-list) nil))
583     (if (get-text-property (point) 'egg-end)
584         (progn
585           ;; delete close marker
586           (delete-region (point) (+ (point) (length egg-conversion-close)))
587           (egg-do-auto-fill)
588           (run-hooks 'input-method-after-insert-chunk-hook))
589       ;; delete from last speparater
590       (delete-region (1- (point)) (point))
591       (setq source "")
592       (while (null (get-text-property (point) 'egg-end))
593         (setq s (egg-get-bunsetsu-source (egg-get-bunsetsu-info (point))))
594         (put-text-property 0 (length s) 'egg-lang egg-current-language s)
595         (setq source (concat source s))
596         (setq p (point))
597         (forward-char)
598         (delete-region p (point)))
599       ;; delete close marker
600       (delete-region (point) (+ (point) (length egg-conversion-close)))
601       (its-restart source t))))
602
603 (defun egg-exit-conversion ()
604   (interactive)
605   (goto-char (next-single-property-change (point) 'egg-end))
606   (egg-decide-before-point))
607
608 (defun egg-abort-conversion ()
609   (interactive)
610   (let ((inhibit-read-only t)
611         start bunsetsu-list source)
612     (if (get-text-property (1- (point)) 'egg-start)
613         (setq start (1- (point)))
614       (setq start (1- (previous-single-property-change (point) 'egg-start))))
615     (goto-char start)
616     (setq source (get-text-property (point) 'egg-source))
617     ;; Delete open marker
618     (delete-region start (+ start (length egg-conversion-open)))
619     (setq bunsetsu-list (egg-decide-bunsetsu))
620     ;; Delete close marker
621     (delete-region (point) (+ (point) (length egg-conversion-close)))
622     (egg-end-conversion bunsetsu-list t)
623     (delete-region start (point))
624     (its-restart source)))
625
626 (defun egg-select-candidate ()
627   (interactive)
628   (let ((inhibit-read-only t)
629         (last (get-text-property (point) 'egg-bunsetsu-last))
630         (b (egg-get-bunsetsu-info (point)))
631         (in-loop t)
632         new i max+ p)
633     (setq max+ (egg-get-number-of-candidates b))
634     (if (null max+)
635         (let ((prev-b (egg-get-previous-bunsetsu (point))))
636           (setq i (egg-list-candidates b prev-b))
637           (setq max+ (egg-get-number-of-candidates b)))
638       (setq i (egg-get-current-candidate-number b)))
639     (let (candidate-list candidate l)
640       (if (null max+)
641           ;; fake 1 candidate
642           (menudiag-select (list 'menu "\e$B8uJd\e(B:"
643                                  (list (egg-get-bunsetsu-converted b))
644                                  (list (egg-get-bunsetsu-converted b))))
645         (setq candidate-list (egg-get-all-candidates b)
646               l candidate-list
647               candidate (menudiag-select (list 'menu "\e$B8uJd\e(B:" l)
648                                          (list (nth i l))))
649         (setq i 0)
650         (while in-loop
651           (if (eq candidate (car l))
652               (setq in-loop nil)
653             (setq l (cdr l)
654                   i (1+ i))))
655         (setq new (egg-decide-candidate b i))
656         (setq p (point))
657         (delete-region p (progn (forward-char) (point)))
658         (egg-insert-bunsetsu new last)
659         (goto-char p)))))
660
661 (provide 'egg-cnv)
662 ;;; egg-cnv.el ends here.