1 ;;; egg-cnv.el --- Conversion Backend in Egg Input Method Architecture
3 ;; Copyright (C) 1999,2000 PFU LIMITED
5 ;; Author: NIIBE Yutaka <gniibe@chroot.org>
6 ;; KATAYAMA Yoshio <kate@pfu.co.jp>
8 ;; Maintainer: TOMURA Satoru <tomura@etl.go.jp>
10 ;; Keywords: mule, multilingual, input method
12 ;; This file is part of EGG.
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)
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.
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.
36 (defgroup egg-conv nil
37 "Conversion backend Interface of Tamagotchy"
40 (defcustom egg-conversion-wrap-select nil
41 "*Candidate selection wraps around to first candidate, if non-NIL.
42 Otherwise stop at the last candidate."
43 :group 'egg-conv :type 'boolean)
45 (defcustom egg-conversion-auto-candidate-menu 0
46 "*Automatically enter the candidate selectionmenu mode at N times
47 next/previous-candidate, if positive number N."
48 :group 'egg-conv :type 'integer)
50 (defcustom egg-conversion-fence-invisible nil
51 "*Make fence marks invisible, if non-NIL."
52 :group 'egg-conv :type 'boolean)
54 (defcustom egg-conversion-fence-open "|"
55 "*String of conversion fence start mark. (should not be null string)"
56 :group 'egg-conv :type '(string :valid-regexp ".+"))
58 (defcustom egg-conversion-fence-close "|"
59 "*String of conversion fence end mark. (should not be null string)"
60 :group 'egg-conv :type '(string :valid-regexp ".+"))
62 (defcustom egg-conversion-face nil
63 "*Face (or alist of languages and faces) of text in conversion fences."
66 (repeat :tag "Language-Face alist"
67 (cons :tag "Language-Face"
68 (choice :tag "Language"
73 (const :tag "Default" t)
74 (symbol :tag "Other"))
77 (defcustom egg-conversion-major-separator " "
78 "*Major clause seperator"
79 :group 'egg-conv :type 'string)
81 (defcustom egg-conversion-minor-separator "-"
82 "*Minor clause seperator"
83 :group 'egg-conv :type 'string)
85 (defcustom egg-startup-file ".eggrc"
86 "*Egg startup file name."
87 :group 'egg-conv :type 'string)
89 (defcustom egg-startup-file-search-path '("~")
90 "*List of directories to search for egg-startup-file (default .eggrc)."
91 :group 'egg-conv :type '(repeat string))
95 (no-rcfile "no egg-startup-file on %S")
96 (rcfile-error "error occured in egg-startup-file")
97 (candidate "candidates:")
98 (register-str "Chinese character:")
99 (register-yomi "word registration ``%s'' pronunciation:")
100 (registered "dictionary entry ``%s''(%s: %s) is registerd at %s"))
102 (no-rcfile "%S
\e$B>e$K
\e(B egg-startup-file
\e$B$,$"$j$^$;$s
\e(B")
103 (rcfile-error "egg-startup-file
\e$B$G%(%i!<$,$"$j$^$7$?
\e(B")
104 (candidate "
\e$B8uJd
\e(B:")
105 (register-str "
\e$B4A;z
\e(B:")
106 (register-yomi "
\e$B<-=qEPO?!X
\e(B%s
\e$B!Y
\e(B
\e$BFI$_
\e(B:")
107 (registered "
\e$B<-=q9`L\!X
\e(B%s
\e$B!Y
\e(B(%s: %s)
\e$B$r
\e(B %s
\e$B$KEPO?$7$^$7$?
\e(B"))
109 (no-rcfile "
\e$ATZ
\e(B %S
\e$AIOC;SP
\e(B egg-startup-file")
110 (rcfile-error "
\e$ATZ6AH!
\e(B egg-startup-file
\e$AJ1#,SP3v4m7"IzAK
\e(B")
111 (candidate "
\e$A:r29
\e(B:")
112 (register-str "
\e$A::WV
\e(B:")
113 (register-yomi "
\e$A4G5d5GB<!:
\e(B%s
\e$A!;
\e(B
\e$A6A7(
\e(B:")
114 (registered "
\e$A4G5dOnD?!:
\e(B%s
\e$A!;
\e(B(%s: %s)
\e$ARQ1;5GB<5=
\e(B %s
\e$AVPAK
\e(B"))
116 (no-rcfile "
\e$(GGc
\e(B %S
\e$(GD8JtH4
\e(B egg-startup-file")
117 (rcfile-error "
\e$(GGc{tL=
\e(B egg-startup-file
\e$(GUk!"H4Exrc`uFmD'
\e(B")
118 (register-str "
\e$(GiGGs
\e(B:")
119 (candidate "
\e$(GT7fP
\e(B:")
120 (register-yomi "
\e$(Gy0L(`trg!Z
\e(B%s
\e$(G![
\e(B
\e$(G{tNN
\e(B:")
121 (registered "
\e$(Gy0L(bzFx!Z
\e(B%s
\e$(G![
\e(B(%s: %s)
\e$(GDX]7`trgL/
\e(B %s
\e$(GDcD'
\e(B"))
123 (no-rcfile "%S
\e$(C?!
\e(B egg-startup-file
\e$(C@L
\e(B
\e$(C>x@>4O4Y
\e(B")
124 (rcfile-error "egg-startup-file
\e$(C?!
\e(B
\e$(C?!7/0!
\e(B
\e$(C9_;}G_@>4O4Y
\e(B")
125 (candidate "
\e$(CHD:8
\e(B:")
126 (register-str "
\e$(CGQ@Z
\e(B:")
127 (register-yomi "
\e$(C;g@|5n7O!:
\e(B%s
\e$(C!;
\e(B
\e$(C569}
\e(B:")
128 (registered "
\e$(C;g@|GW8q!:
\e(B%s
\e$(C!;
\e(B(%s: %s)
\e$(C@;
\e(B %s
\e$(C?!
\e(B
\e$(C5n7OG_@>4O4Y
\e(B"))))
131 ;; <backend-alist> ::= ( ( <language> ( <stage>... )... )... )
132 ;; <stage> ::= ( <backend> <backend-for-reconvert>... )
133 ;; <backend-for-reconvert> ::= <backend>
134 ;; <backend> ::= symbol
137 (defvar egg-conversion-backend-alist nil)
138 (make-variable-buffer-local 'egg-conversion-backend-alist)
139 (put 'egg-conversion-backend-alist 'permanent-local t)
141 (defun egg-set-conversion-backend (backend-alist &optional force)
142 (let (pair lang backend-set)
144 (setq lang (caar backend-alist)
145 backend-set (cdar backend-alist)
146 backend-alist (cdr backend-alist)
147 pair (assq lang egg-conversion-backend-alist))
150 (setq egg-conversion-backend-alist
151 (cons (cons lang backend-set) egg-conversion-backend-alist)))
153 (setcdr pair backend-set))))))
155 (defun egg-get-conversion-backend (language n use-default)
157 (cond ((null n) (setq n 0))
158 ((null (integerp n)) (setq n 1)))
159 (setq backend (nth (1+ n) (assq language egg-conversion-backend-alist)))
161 (and backend (cons 0 (mapcar 'copy-sequence backend)))
162 (and use-default (cons 0 egg-default-conversion-backend)))))
164 (defsubst egg-default-conversion-backend-p (backend)
165 (eq (cdr backend) egg-default-conversion-backend))
167 (defsubst egg-get-current-backend (backend)
168 (car (nth (car backend) (cdr backend))))
170 (defsubst egg-get-reconvert-backend (backend &optional n)
171 (cond ((null n) (setq n 0))
172 ((null (integerp n)) (setq n 1)))
173 (nth (1+ n) (nth (car backend) (cdr backend))))
175 (defmacro egg-bunsetsu-info () ''intangible)
177 (defsubst egg-get-bunsetsu-info (p &optional object)
178 (get-text-property p (egg-bunsetsu-info) object))
180 (defsubst egg-get-backend (p &optional object)
181 (get-text-property p 'egg-backend object))
183 (defsubst egg-get-language (p &optional object)
184 (get-text-property p 'egg-lang object))
186 (defsubst egg-get-bunsetsu-last (p &optional object)
187 (get-text-property p 'egg-bunsetsu-last object))
189 (defsubst egg-get-major-continue (p &optional object)
190 (get-text-property p 'egg-major-continue object))
192 (defsubst egg-get-char-size (p &optional object)
193 (get-text-property p 'egg-char-size object))
195 ;; <bunsetsu-info> ::= ( <backend> . <backend-dependent-info> )
197 (defsubst egg-bunsetsu-create (backend info)
200 (defsubst egg-bunsetsu-get-backend (bunsetsu)
202 (defsubst egg-bunsetsu-set-backend (bunsetsu backend)
203 (setcar bunsetsu backend))
205 (defsubst egg-bunsetsu-get-info (bunsetsu)
207 (defsubst egg-bunsetsu-set-info (bunsetsu info)
208 (setcdr bunsetsu info))
210 (defvar egg-finalize-backend-list nil)
212 (defun egg-set-finalize-backend (func-list)
213 (mapcar (lambda (func)
215 (null (memq func egg-finalize-backend-list)))
216 (setq egg-finalize-backend-list
217 (cons func egg-finalize-backend-list))))
220 (defmacro egg-define-backend-functions (list)
224 (let* ((func (car def))
226 (backend (car args)))
227 (cond ((eq backend 'bunsetsu)
228 (setq backend `(egg-bunsetsu-get-backend ,backend)))
229 ((eq backend 'bunsetsu-list)
230 (setq backend `(egg-bunsetsu-get-backend (car ,backend)))))
232 (let ((func (get ,backend ',func)))
234 (funcall func ,@args))))))
237 (egg-define-backend-functions
238 ((egg-start-conversion (backend source-string context))
239 (egg-get-bunsetsu-source (bunsetsu))
240 (egg-get-bunsetsu-converted (bunsetsu))
241 (egg-get-source-language (bunsetsu))
242 (egg-get-converted-language (bunsetsu))
243 (egg-major-bunsetsu-continue-p (bunsetsu))
244 (egg-list-candidates (bunsetsu-list prev-b next-b major))
245 (egg-decide-candidate (bunsetsu-list candidate-pos prev-b next-b))
246 (egg-change-bunsetsu-length (bunsetsu-list prev-b next-b length major))
247 (egg-bunsetsu-combinable-p (bunsetsu next-b))
248 (egg-end-conversion (bunsetsu-list abort))
249 (egg-word-inspection (bunsetsu))
250 (egg-word-registration (backend source converted))))
252 (defun egg-finalize-backend ()
253 (run-hooks 'egg-finalize-backend-list))
255 (setplist 'egg-conversion-backend-noconv
256 '(egg-start-conversion egg-start-conversion-noconv
257 egg-get-bunsetsu-source egg-get-bunsetsu-source-noconv
258 egg-get-bunsetsu-converted egg-get-bunsetsu-converted-noconv
259 egg-get-source-language egg-get-source-language-noconv
260 egg-get-converted-language egg-get-converted-language-noconv
261 egg-end-conversion egg-end-conversion-noconv))
263 (defun egg-start-conversion-noconv (backend yomi-string context)
264 (let ((string (copy-sequence yomi-string))
265 (language (egg-get-language 0 yomi-string)))
266 (set-text-properties 0 (length string) nil string)
267 (list (egg-bunsetsu-create backend (vector string language)))))
269 (defun egg-get-bunsetsu-source-noconv (bunsetsu)
270 (aref (egg-bunsetsu-get-info bunsetsu) 0))
271 (defun egg-get-bunsetsu-converted-noconv (bunsetsu)
272 (aref (egg-bunsetsu-get-info bunsetsu) 0))
273 (defun egg-get-source-language-noconv (bunsetsu)
274 (aref (egg-bunsetsu-get-info bunsetsu) 1))
275 (defun egg-get-converted-language-noconv (bunsetsu)
276 (aref (egg-bunsetsu-get-info bunsetsu) 1))
277 (defun egg-end-conversion-noconv (bunsetsu-list abort)
280 (defconst egg-default-conversion-backend '((egg-conversion-backend-noconv)))
282 (defun egg-convert-region (start end &optional context nth-backend)
283 (interactive "r\ni\nP")
284 (let ((source (buffer-substring start end))
285 backend backend-source-list converted converted-list
286 lang len s success abort)
290 (delete-region start end)
291 (let ((inhibit-read-only t))
292 (its-define-select-keys egg-conversion-map)
294 (setq s (copy-sequence egg-conversion-fence-open)
298 (set-text-properties 0 len (list 'read-only t
303 (put-text-property 0 len 'egg-context context s))
304 (if egg-conversion-fence-invisible
305 (put-text-property 0 len 'invisible t s))
307 (setq s (copy-sequence egg-conversion-fence-close)
309 (set-text-properties 0 len '(read-only t rear-nonsticky t egg-end t) s)
310 (if egg-conversion-fence-invisible
311 (put-text-property 0 len 'invisible t s))
316 (setq source (copy-sequence source))
317 (egg-separate-languages source)
318 (setq backend-source-list (egg-assign-backend source nth-backend))
319 (while (and (null abort) backend-source-list)
320 (setq backend (car (car backend-source-list))
321 lang (nth 1 (car backend-source-list))
322 source (nth 2 (car backend-source-list))
323 backend-source-list (cdr backend-source-list))
324 (condition-case error
326 (setq converted (egg-start-conversion
327 (egg-get-current-backend backend)
330 (egg-error "no conversion result"))
331 (setq converted-list (nconc converted-list
332 (list (cons backend converted)))
334 (or (egg-default-conversion-backend-p backend)
339 (delq t (mapcar (lambda (s)
340 (egg-default-conversion-backend-p
342 backend-source-list))))
343 (message "egg %s backend: %s"
344 (if (cdr lang) lang (car lang))
345 (nth (if (eq (car error) 'quit) 0 1) error))
350 (format "egg %s backend %s: continue? "
351 lang (nth (if (eq (car error) 'quit) 0 1) error)))
353 (setq backend (egg-get-conversion-backend nil 0 t)
354 converted (egg-start-conversion
355 (egg-get-current-backend backend)
357 converted-list (nconc converted-list
358 (list (cons backend converted)))
362 (delete-region start end)
363 (while converted-list
364 (egg-insert-bunsetsu-list (caar converted-list) (cdar converted-list)
365 (or (null (cdr converted-list)) 'continue))
366 (setq converted-list (cdr converted-list)))
369 (egg-abort-conversion))
371 (egg-exit-conversion)))))))
373 (defun egg-separate-languages (str &optional last-lang)
374 (let (lang last-chinese
375 (len (length str)) i j l)
376 ;; 1st pass -- mark undefined Chinese part
377 (if (or (eq last-lang 'Chinese-GB) (eq last-lang 'Chinese-CNS))
378 (setq last-chinese last-lang))
381 (setq j (egg-next-single-property-change i 'egg-lang str len))
382 (if (null (egg-get-language i str))
384 (setq c (egg-string-to-char-at str i)
385 cset (char-charset c))
387 ((eq cset 'chinese-sisheng)
388 (egg-string-match-charset 'chinese-sisheng str i)
389 (setq l (match-end 0)
392 ((setq l (egg-chinese-syllable str i))
396 (if (eq (string-match "[\0-\177\240-\377]+" str (1+ i)) (1+ i))
397 (setq j (match-end 0))
400 (eq (char-charset (egg-string-to-char-at str j))
402 (setq j (max (1+ i) (- j 6))))
404 ((eq cset 'composition)
405 (setq j (+ i (egg-char-bytes c))
406 lang (egg-charset-to-language
408 (car (decompose-composite-char c 'list))))))
410 (egg-string-match-charset cset str i)
411 (setq j (match-end 0)
412 lang (egg-charset-to-language cset))))
414 (put-text-property i j 'egg-lang lang str))))
416 ;; 2nd pass -- set language property
419 (setq lang (egg-get-language i str))
422 (setq lang (or last-lang
423 (egg-next-part-lang str i))))
424 ((equal lang 'Chinese)
425 (setq lang (or last-chinese
426 (egg-next-chinese-lang str i)))))
427 (setq last-lang lang)
428 (if (or (eq lang 'Chinese-GB) (eq lang 'Chinese-CNS))
429 (setq last-chinese lang))
431 i (egg-next-single-property-change i 'egg-lang str len))
432 (set-text-properties j i (list 'egg-lang lang) str))))
434 ;;; Should think again the interface to language-info-alist
435 (defun egg-charset-to-language (charset)
436 (let ((list language-info-alist))
438 (null (memq charset (assq 'charset (car list)))))
439 (setq list (cdr list)))
441 (intern (car (car list))))))
443 (defun egg-next-part-lang (str pos)
444 (let ((lang (get-text-property
445 (egg-next-single-property-change pos 'egg-lang str (length str))
447 (if (eq lang 'Chinese)
448 (egg-next-chinese-lang str pos)
451 egg-default-language))))
453 (defun egg-next-chinese-lang (str pos)
454 (let ((len (length str)) lang)
455 (while (and (< pos len) (null lang))
456 (setq pos (egg-next-single-property-change pos 'egg-lang str len)
457 lang (egg-get-language pos str))
458 (if (null (or (eq lang 'Chinese-GB)
459 (eq lang 'Chinese-CNS)))
463 ((eq its-current-language 'Chinese-GB) 'Chinese-GB)
464 ((eq its-current-language 'Chinese-CNS) 'Chinese-CNS)
465 ((eq egg-default-language 'Chinese-GB) 'Chinese-GB)
466 ((eq egg-default-language 'Chinese-CNS) 'Chinese-CNS)
470 ;; return value ::= ( (<backend> ( <lang>... ) <source string> )... )
472 (defun egg-assign-backend (source n)
473 (let ((len (length source))
475 j s lang backend retval)
477 (setq j (egg-next-single-property-change i 'egg-lang source len)
478 s (substring source i j)
479 lang (egg-get-language 0 s)
480 backend (egg-get-conversion-backend lang n t))
481 (set-text-properties 0 (- j i) (list 'egg-lang lang) s)
482 (setq retval (nconc retval (list (list backend (list lang) s)))
487 (if (or (egg-default-conversion-backend-p (car (car retval)))
488 (null (equal (car (car retval)) (car (nth 1 retval)))))
489 (setq retval (cdr retval))
490 (nconc (nth 1 (car retval)) (nth 1 (nth 1 retval)))
491 (setcar (nthcdr 2 (car retval))
492 (concat (nth 2 (car retval)) (nth 2 (nth 1 retval))))
493 (setcdr retval (cddr retval)))))))
495 (defun egg-search-file (filename path)
497 (if (file-name-directory filename)
498 (setq file (substitute-in-file-name (expand-file-name filename))
499 file (and (file-readable-p file) file))
500 (while (and (null file) path)
501 (if (stringp (car path))
502 (setq file (substitute-in-file-name
503 (expand-file-name filename (car path)))
504 file (and (file-exists-p file) file)))
505 (setq path (cdr path)))
508 (defvar egg-default-startup-file "eggrc"
509 "Egg startup file name (system default)")
511 (defun egg-load-startup-file (backend lang)
512 (let ((eggrc (or (egg-search-file egg-startup-file
513 egg-startup-file-search-path)
514 (egg-search-file egg-default-startup-file load-path))))
516 (condition-case error
517 (let ((egg-backend-type backend) (egg-language lang))
520 (message "%s: %s" (car error)
521 (mapconcat (lambda (s) (format "%S" s)) (cdr error) ", "))
522 (egg-error 'rcfile-error))
524 (egg-error 'rcfile-error)))
525 (egg-error 'no-rcfile egg-startup-file-search-path))))
527 (defun egg-get-conversion-face (lang)
528 (if (null (consp egg-conversion-face))
530 (cdr (or (assq lang egg-conversion-face)
531 (assq t egg-conversion-face)))))
533 (defvar egg-conversion-map
534 (let ((map (make-sparse-keymap))
537 (define-key map (vector i) 'egg-exit-conversion-unread-char)
539 (define-key map "\C-@" 'egg-decide-first-char)
540 (define-key map [?\C-\ ] 'egg-decide-first-char)
541 (define-key map "\C-a" 'egg-beginning-of-conversion-buffer)
542 (define-key map "\C-b" 'egg-backward-bunsetsu)
543 (define-key map "\C-c" 'egg-abort-conversion)
544 (define-key map "\C-e" 'egg-end-of-conversion-buffer)
545 (define-key map "\C-f" 'egg-forward-bunsetsu)
546 (define-key map "\C-h" 'egg-help-command)
547 (define-key map "\C-i" 'egg-shrink-bunsetsu-major)
548 (define-key map "\C-k" 'egg-decide-before-point)
549 ;; (define-key map "\C-l" 'egg-exit-conversion) ; Don't override C-L
550 (define-key map "\C-m" 'egg-exit-conversion)
551 (define-key map "\C-n" 'egg-next-candidate-major)
552 (define-key map "\C-o" 'egg-enlarge-bunsetsu-major)
553 (define-key map "\C-p" 'egg-previous-candidate-major)
554 (define-key map "\C-r" 'egg-reconvert-bunsetsu)
555 (define-key map "\C-t" 'egg-toroku-bunsetsu)
556 (define-key map "\C-v" 'egg-inspect-bunsetsu)
557 (define-key map "\M-i" 'egg-shrink-bunsetsu-minor)
558 (define-key map "\M-n" 'egg-next-candidate-minor)
559 (define-key map "\M-o" 'egg-enlarge-bunsetsu-minor)
560 (define-key map "\M-p" 'egg-previous-candidate-minor)
561 (define-key map "\M-r" 'egg-reconvert-bunsetsu-from-source)
562 (define-key map "\M-s" 'egg-select-candidate-major)
563 (define-key map "\M-v" 'egg-toggle-inspect-mode)
564 (define-key map "\M-z" 'egg-select-candidate-minor)
565 (define-key map "\e\C-s" 'egg-select-candidate-list-all-major)
566 (define-key map "\e\C-z" 'egg-select-candidate-list-all-minor)
567 (define-key map [return] 'egg-exit-conversion)
568 (define-key map [right] 'egg-forward-bunsetsu)
569 (define-key map [left] 'egg-backward-bunsetsu)
570 (define-key map " " 'egg-next-candidate)
571 (define-key map "/" 'egg-exit-conversion)
573 "Keymap for EGG Conversion mode.")
575 (fset 'egg-conversion-map egg-conversion-map)
577 (defun egg-exit-conversion-unread-char ()
579 (setq unread-command-events (list last-command-event)
580 this-command 'egg-use-context)
581 (setq egg-context (egg-exit-conversion)))
583 (defun egg-make-bunsetsu (backend bunsetsu last)
584 (let* ((converted (copy-sequence (egg-get-bunsetsu-converted bunsetsu)))
585 (language (egg-get-converted-language bunsetsu))
586 (continue (and (null last) (egg-major-bunsetsu-continue-p bunsetsu)))
587 (face (egg-get-conversion-face language))
589 (setq len1 (length converted))
591 (setq converted (concat converted
593 egg-conversion-minor-separator
594 egg-conversion-major-separator))))
595 (setq len (length converted))
596 (set-text-properties 0 len
598 (egg-bunsetsu-info) bunsetsu
601 'egg-bunsetsu-last last
602 'egg-major-continue continue
603 'local-map 'egg-conversion-map)
606 (egg-set-face 0 len1 face converted))
609 (defun egg-insert-bunsetsu-list (backend bunsetsu-list &optional last)
610 (let ((len (length bunsetsu-list)))
615 (egg-make-bunsetsu backend b (and (= len 0) last)))
618 (defun egg-beginning-of-conversion-buffer (n)
622 (egg-end-of-conversion-buffer 1))
623 ((null (get-text-property (1- (point)) 'egg-start))
624 (goto-char (previous-single-property-change (point) 'egg-start)))))
626 (defun egg-end-of-conversion-buffer(n)
630 (egg-beginning-of-conversion-buffer 1))
632 (goto-char (next-single-property-change (point) 'egg-end))
635 (defun egg-backward-bunsetsu (n)
638 (null (get-text-property (1- (point)) 'egg-start)))
642 (signal 'beginning-of-buffer nil)))
644 (defun egg-forward-bunsetsu (n)
647 (null (get-text-property (point) 'egg-end)))
652 (signal 'end-of-buffer nil)))
654 (defun egg-get-bunsetsu-tail (b)
655 (nth (1- (length b)) b))
657 (defun egg-previous-bunsetsu-point (p &optional n obj lim)
660 (setq p (previous-single-property-change p (egg-bunsetsu-info) obj lim)
664 (defun egg-next-bunsetsu-point (p &optional n obj lim)
667 (setq p (egg-next-single-property-change p (egg-bunsetsu-info) obj lim)
671 (defun egg-get-previous-bunsetsu (p)
672 (and (null (egg-get-bunsetsu-last (1- p)))
673 (egg-get-bunsetsu-info (1- p))))
675 (defun egg-get-previous-major-bunsetsu (p)
677 (prev (egg-get-previous-bunsetsu p))
680 (setq bunsetsu (cons prev bunsetsu)
681 p (egg-previous-bunsetsu-point p)
682 prev (and (egg-get-major-continue (1- p))
683 (egg-get-bunsetsu-info (1- p)))))
686 (defun egg-get-next-bunsetsu (p)
687 (and (null (egg-get-bunsetsu-last p))
688 (egg-get-bunsetsu-info (egg-next-bunsetsu-point p))))
690 (defun egg-get-major-bunsetsu (p)
691 (let ((next (egg-get-bunsetsu-info p))
694 (setq bunsetsu (cons next bunsetsu)
695 p (egg-next-bunsetsu-point p)
696 next (and (egg-get-major-continue (1- p))
697 (egg-get-bunsetsu-info p))))
698 (nreverse bunsetsu)))
700 (defsubst egg-get-major-bunsetsu-source (list)
701 (mapconcat (lambda (b) (egg-get-bunsetsu-source b)) list ""))
703 (defvar egg-inspect-mode nil
704 "*Display clause information on candidate selection, if non-NIL.")
706 (defun egg-toggle-inspect-mode ()
708 (if (setq egg-inspect-mode (not egg-inspect-mode))
709 (egg-inspect-bunsetsu t)))
711 (defun egg-inspect-bunsetsu (&optional quiet)
713 (or (egg-word-inspection (egg-get-bunsetsu-info (point)))
717 (defvar egg-candidate-selection-info nil)
718 (make-variable-buffer-local 'egg-candidate-selection-info)
720 (defvar egg-candidate-selection-major t)
721 (make-variable-buffer-local 'egg-candidate-selection-major)
723 (defsubst egg-set-candsel-info (b prev-b next-b major)
724 (setq egg-candidate-selection-info (list b prev-b next-b major)))
726 (defsubst egg-candsel-last-bunsetsu () (car egg-candidate-selection-info))
727 (defsubst egg-candsel-last-prev-b () (nth 1 egg-candidate-selection-info))
728 (defsubst egg-candsel-last-next-b () (nth 2 egg-candidate-selection-info))
729 (defsubst egg-candsel-last-major () (nth 3 egg-candidate-selection-info))
731 (defun egg-major-bunsetsu-head-p (head bunsetsu)
732 (while (and head (eq (car head) (car bunsetsu)))
733 (setq head (cdr head)
734 bunsetsu (cdr bunsetsu)))
737 (defun egg-major-bunsetsu-tail-p (tail bunsetsu)
738 (egg-major-bunsetsu-head-p
739 tail (nthcdr (- (length bunsetsu) (length tail)) bunsetsu)))
741 (defun egg-get-candsel-target-major ()
742 (let ((bunsetsu (egg-get-major-bunsetsu (point)))
744 (setq prev-b (egg-get-previous-major-bunsetsu (point))
745 next (egg-next-bunsetsu-point (point) (length bunsetsu)))
747 ((and (egg-candsel-last-major)
748 (egg-major-bunsetsu-tail-p (egg-candsel-last-prev-b) prev-b)
749 (egg-major-bunsetsu-head-p (append (egg-candsel-last-bunsetsu)
750 (egg-candsel-last-next-b))
752 (setq bunsetsu (egg-candsel-last-bunsetsu)
753 prev-b (egg-candsel-last-prev-b)
754 next-b (egg-candsel-last-next-b))
755 (setq next (egg-next-bunsetsu-point (point) (length bunsetsu))))
756 ((null (egg-get-bunsetsu-last (1- next)))
757 (setq next-b (egg-get-major-bunsetsu next))))
758 (setq egg-candidate-selection-major t)
759 (list bunsetsu prev-b next-b next t)))
761 (defun egg-get-candsel-target-minor ()
762 (let* ((bunsetsu (list (egg-get-bunsetsu-info (point))))
763 (prev-b (egg-get-previous-bunsetsu (point)))
764 (next-b (egg-get-next-bunsetsu (point))))
765 (and prev-b (setq prev-b (list prev-b)))
766 (and next-b (setq next-b (list next-b)))
767 (setq egg-candidate-selection-major nil)
768 (list bunsetsu prev-b next-b (egg-next-bunsetsu-point (point)) nil)))
770 (defun egg-insert-new-bunsetsu (b prev-b next-b next end)
771 (let ((backend (egg-get-backend (point)))
773 (setq start (egg-previous-bunsetsu-point (point) (length prev-b)))
774 (setq end (or end (egg-next-bunsetsu-point next (length next-b))))
775 (setq last (egg-get-bunsetsu-last (1- end)))
776 (delete-region start end)
777 (egg-insert-bunsetsu-list backend (append prev-b (append b next-b)) last)
778 (goto-char (egg-next-bunsetsu-point start (length prev-b)))
780 (egg-inspect-bunsetsu t))))
782 (defun egg-next-candidate (n)
784 (if egg-candidate-selection-major
785 (egg-next-candidate-major n)
786 (egg-next-candidate-minor n)))
788 (defun egg-next-candidate-major (n)
790 (apply 'egg-next-candidate-internal n (egg-get-candsel-target-major)))
792 (defun egg-next-candidate-minor (n)
794 (apply 'egg-next-candidate-internal n (egg-get-candsel-target-minor)))
796 (defun egg-previous-candidate (n)
798 (if egg-candidate-selection-major
799 (egg-previous-candidate-major n)
800 (egg-previous-candidate-minor n)))
802 (defun egg-previous-candidate-major (n)
804 (apply 'egg-next-candidate-internal (- n) (egg-get-candsel-target-major)))
806 (defun egg-previous-candidate-minor (n)
808 (apply 'egg-next-candidate-internal (- n) (egg-get-candsel-target-minor)))
810 (defvar egg-candidate-select-counter 1)
812 (defun egg-next-candidate-internal (n b prev-b next-b next major)
813 (if (eq last-command (if major 'egg-candidate-major 'egg-candidate-minor))
814 (setq egg-candidate-select-counter (1+ egg-candidate-select-counter))
815 (setq egg-candidate-select-counter 1))
816 (if (= egg-candidate-select-counter egg-conversion-auto-candidate-menu)
817 (egg-select-candidate-internal nil b prev-b next-b next major)
818 (setq this-command (if major 'egg-candidate-major 'egg-candidate-minor))
819 (let ((inhibit-read-only t)
820 candidates nitem i beep)
821 (setq candidates (egg-list-candidates b prev-b next-b major))
822 (if (null candidates)
824 (setq i (+ n (car candidates))
825 nitem (length (cdr candidates)))
827 ((< i 0) ; go backward as if it is ring
829 (setq i (+ i nitem))))
831 (egg-conversion-wrap-select ; go backward as if it is ring
833 (setq i (- i nitem))))
834 (t ; don't go forward
837 (setq b (egg-decide-candidate b i prev-b next-b)
841 (egg-set-candsel-info b prev-b next-b major)
842 (egg-insert-new-bunsetsu b prev-b next-b next nil))
846 (defun egg-numbering-item (list)
848 (mapcar (lambda (item) (cons item (setq n (1+ n)))) list)))
850 (defun egg-select-candidate-major ()
852 (apply 'egg-select-candidate-internal nil (egg-get-candsel-target-major)))
854 (defun egg-select-candidate-minor ()
856 (apply 'egg-select-candidate-internal nil (egg-get-candsel-target-minor)))
858 (defun egg-select-candidate-list-all-major ()
860 (apply 'egg-select-candidate-internal t (egg-get-candsel-target-major)))
862 (defun egg-select-candidate-list-all-minor ()
864 (apply 'egg-select-candidate-internal t (egg-get-candsel-target-minor)))
866 (defun egg-select-candidate-internal (all b prev-b next-b next major)
867 (let ((inhibit-read-only t)
868 (prompt (egg-get-message 'candidate))
869 candidates item-list new i)
870 (setq candidates (egg-list-candidates b prev-b next-b major))
871 (if (null candidates)
873 (setq all (and all '(menudiag-list-all))
874 item-list (egg-numbering-item (cdr candidates))
875 i (menudiag-select (list 'menu prompt item-list)
876 (cons (nth (car candidates) item-list) all))
877 new (egg-decide-candidate b i prev-b next-b)
881 (egg-set-candsel-info new prev-b next-b major)
882 (egg-insert-new-bunsetsu new prev-b next-b next nil))))
884 (defun egg-separate-characters (str)
885 (let* ((v (egg-string-to-vector str))
887 (i 0) (j 0) m n (nchar 0))
889 (if (setq n (egg-chinese-syllable str j))
890 (setq m (egg-chars-in-period str j n))
891 (setq m 1 n (egg-char-bytes (aref v i))))
892 (put-text-property j (+ j n) 'egg-char-size n str)
893 (setq nchar (1+ nchar) i (+ i m) j (+ j n)))
896 (defun egg-enlarge-bunsetsu-major (n)
898 (egg-enlarge-bunsetsu-internal n t))
900 (defun egg-enlarge-bunsetsu-minor (n)
902 (egg-enlarge-bunsetsu-internal n nil))
904 (defun egg-shrink-bunsetsu-major (n)
906 (egg-enlarge-bunsetsu-internal (- n) t))
908 (defun egg-shrink-bunsetsu-minor (n)
910 (egg-enlarge-bunsetsu-internal (- n) nil))
912 (defun egg-enlarge-bunsetsu-internal (n major)
913 (let ((inhibit-read-only t)
914 b prev-b next-b s1 s1len s2 s2len nchar i last next end beep)
916 (setq b (egg-get-major-bunsetsu (point))
917 prev-b (egg-get-previous-major-bunsetsu (point)))
918 (setq b (list (egg-get-bunsetsu-info (point)))
919 prev-b (egg-get-previous-bunsetsu (point))
920 prev-b (and prev-b (list prev-b))))
921 (setq end (egg-next-bunsetsu-point (point) (length b))
922 last (egg-get-bunsetsu-last (1- end)))
924 (setq next-b (cons (egg-get-bunsetsu-info end) next-b)
925 last (egg-get-bunsetsu-last end)
926 end (egg-next-bunsetsu-point end)))
927 (setq next-b (nreverse next-b)
928 s1 (egg-get-major-bunsetsu-source b)
929 s2 (concat s1 (egg-get-major-bunsetsu-source next-b))
930 s1len (egg-separate-characters s1)
931 s2len (egg-separate-characters s2)
935 (setq beep t nchar (and (/= s1len 1) (egg-get-char-size 0 s1))))
937 (setq beep t nchar (and (/= s2len 0) (length s2))))
941 (setq nchar (+ nchar (egg-get-char-size nchar s2))
945 (setq next-b (nconc b next-b)
946 i (length (egg-get-bunsetsu-source (car next-b))))
948 (setq next-b (cdr next-b)
949 i (+ i (length (egg-get-bunsetsu-source (car next-b))))))
950 (setq next-b (prog1 (cdr next-b) (setcdr next-b nil))
951 next (egg-next-bunsetsu-point (point) (length b))
952 b (egg-change-bunsetsu-length b prev-b next-b nchar major))
955 (setq prev-b (nth 1 b)
958 (egg-insert-new-bunsetsu b prev-b next-b next (and next-b end)))))
962 (defun egg-reconvert-bunsetsu (n)
964 (egg-reconvert-bunsetsu-internal n 'egg-get-bunsetsu-converted))
966 (defun egg-reconvert-bunsetsu-from-source (n)
968 (egg-reconvert-bunsetsu-internal n 'egg-get-bunsetsu-source))
970 (defun egg-reconvert-bunsetsu-internal (n func)
971 (let* ((inhibit-read-only t)
972 (backend (egg-get-backend (point)))
973 (source (funcall func (egg-get-bunsetsu-info (point))))
974 (reconv-backend (egg-get-reconvert-backend backend n))
976 (last (egg-get-bunsetsu-last (point)))
978 (if (or (null reconv-backend)
979 (null (setq new (egg-start-conversion reconv-backend source nil))))
981 (delete-region p (egg-next-bunsetsu-point p))
982 (setq next-b (egg-get-bunsetsu-info (point)))
983 (if (and (equal (egg-get-backend p) backend)
984 (eq (egg-bunsetsu-get-backend next-b)
985 (egg-bunsetsu-get-backend (car new)))
986 (egg-bunsetsu-combinable-p (egg-get-bunsetsu-tail new) next-b))
988 (setq last (or (eq last t) 'continue)))
989 (egg-insert-bunsetsu-list backend new last)
991 (setq prev-b (egg-get-bunsetsu-info (1- p)))
994 (if (and (equal (egg-get-backend (1- p)) backend)
995 (eq (egg-bunsetsu-get-backend prev-b)
996 (egg-bunsetsu-get-backend (car new)))
997 (egg-bunsetsu-combinable-p prev-b (car new)))
999 (setq last (or (eq last t) 'continue)))
1000 (setq backend (egg-get-backend (1- p)))
1001 (delete-region (egg-previous-bunsetsu-point p) p)
1002 (egg-insert-bunsetsu-list backend (list prev-b) last))))))
1004 (defun egg-decide-before-point ()
1006 (let* ((inhibit-read-only t)
1007 (start (if (get-text-property (1- (point)) 'egg-start)
1009 (previous-single-property-change (point) 'egg-start)))
1010 (end (if (get-text-property (point) 'egg-end)
1012 (next-single-property-change (point) 'egg-end)))
1013 (decided (buffer-substring start (point)))
1014 (undecided (buffer-substring (point) end))
1015 i len bunsetsu source context)
1017 (previous-single-property-change start 'egg-start nil (point-min))
1018 (next-single-property-change end 'egg-end nil (point-max)))
1020 len (length decided))
1022 (setq bunsetsu (nconc bunsetsu (list (egg-get-bunsetsu-info i decided)))
1023 i (egg-next-bunsetsu-point i 1 decided len))
1025 (egg-get-bunsetsu-last (1- i) decided))
1027 (apply 'insert (mapcar
1028 (lambda (b) (egg-get-bunsetsu-converted b))
1030 (setq context (cons (cons (egg-bunsetsu-get-backend (car bunsetsu))
1031 (egg-end-conversion bunsetsu nil))
1034 (setq len (length undecided))
1038 (run-hooks 'input-method-after-insert-chunk-hook)
1042 (setq bunsetsu (egg-get-bunsetsu-info i undecided)
1043 source (cons (egg-get-bunsetsu-source bunsetsu)
1045 (put-text-property 0 (length (car source))
1047 (egg-get-source-language bunsetsu)
1049 (setq i (egg-next-bunsetsu-point i 1 undecided len)))
1050 (its-restart (apply 'concat (nreverse source)) t t context))))
1052 (defun egg-decide-first-char ()
1054 (let* ((inhibit-read-only t)
1055 (start (if (get-text-property (1- (point)) 'egg-start)
1057 (previous-single-property-change (point) 'egg-start)))
1058 (end (if (get-text-property (point) 'egg-end)
1060 (next-single-property-change (point) 'egg-end)))
1061 (bunsetsu (egg-get-bunsetsu-info start)))
1063 (previous-single-property-change start 'egg-start nil (point-min))
1064 (next-single-property-change end 'egg-end nil (point-max)))
1065 (egg-end-conversion (list bunsetsu) nil)
1066 (insert (egg-string-to-char-at (egg-get-bunsetsu-converted bunsetsu) 0))))
1068 (defun egg-exit-conversion ()
1070 (if (egg-get-bunsetsu-info (point))
1072 (goto-char (next-single-property-change (point) 'egg-end))
1073 (egg-decide-before-point))))
1075 (defun egg-abort-conversion ()
1077 (let ((inhibit-read-only t)
1079 (goto-char (previous-single-property-change
1080 (if (get-text-property (1- (point)) 'egg-start)
1082 (previous-single-property-change (point) 'egg-start))
1083 'egg-start nil (point-min)))
1084 (setq source (get-text-property (point) 'egg-source)
1085 context (get-text-property (point) 'egg-context))
1086 (delete-region (point) (next-single-property-change
1087 (next-single-property-change (point) 'egg-end)
1088 'egg-end nil (point-max)))
1089 (its-restart source nil nil context)))
1091 (defun egg-toroku-bunsetsu ()
1094 (lang (egg-get-source-language (egg-get-bunsetsu-info p)))
1095 (egg-mode-hook (or (cdr (assq lang its-select-func-alist))
1096 (cdr (assq lang its-select-func-default-alist))))
1098 bunsetsu str yomi last)
1100 (setq bunsetsu (egg-get-bunsetsu-info p)
1101 str (concat str (egg-get-bunsetsu-converted bunsetsu))
1102 yomi (concat yomi (egg-get-bunsetsu-source bunsetsu))
1103 last (egg-get-bunsetsu-last p)
1104 p (egg-next-bunsetsu-point p)))
1106 (setq s (read-multilingual-string (egg-get-message 'register-str)
1107 str egg-last-method-name))
1108 (and (equal s "") (ding)))
1109 (egg-toroku-string s nil yomi lang (egg-bunsetsu-get-backend bunsetsu))))
1111 (defun egg-toroku-region (start end &optional nth-backend)
1112 (interactive "r\nP")
1113 (egg-toroku-string (buffer-substring start end) nil nil nil nil nth-backend))
1115 (defun egg-toroku-string (str &optional yomi guess lang backend nth-backend)
1116 (let (egg-mode-hook result)
1117 (if (= (length str) 0)
1118 (egg-error "Egg word registration: null string"))
1119 (egg-separate-languages str lang)
1120 (setq lang (egg-get-language 0 str)
1121 egg-mode-hook (or (cdr (assq lang its-select-func-alist))
1122 (cdr (assq lang its-select-func-default-alist))))
1123 (or yomi (setq yomi ""))
1124 (while (equal yomi "")
1125 (setq yomi (read-multilingual-string
1126 (format (egg-get-message 'register-yomi) str)
1127 guess egg-last-method-name))
1128 (and (equal yomi "") (ding)))
1129 (egg-separate-languages yomi lang)
1132 (setq backend (egg-assign-backend str nth-backend))
1134 (egg-error "Egg word registration: cannot decide backend"))
1135 (setq backend (egg-get-current-backend (caar backend)))))
1136 (setq result (egg-word-registration backend str yomi))
1138 (apply 'message (egg-get-message 'registered) str yomi result)
1141 (defun egg-conversion-mode ()
1142 "\\{egg-conversion-map}"
1143 ;; dummy function to get docstring
1146 (defun egg-help-command ()
1147 "Display documentation for EGG Conversion mode."
1149 (with-output-to-temp-buffer "*Help*"
1150 (princ "EGG Conversion mode:\n")
1151 (princ (documentation 'egg-conversion-mode))
1152 (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p))))
1155 ;;; egg-cnv.el ends here.