1 ;;; egg/anthy.el --- ANTHY Support (high level interface) in Egg
2 ;;; Input Method Architecture
4 ;; Copyright (C) 2002 The Free Software Initiative of Japan
5 ;; 2015 Hiroki Sato <hrs@allbsd.org>
7 ;; Author: NIIBE Yutaka <gniibe@m17n.org>
9 ;; Keywords: mule, multilingual, input method
11 ;; This file is part of EGG.
13 ;; EGG is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; EGG is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc.,
26 ;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 (defgroup anthy-egg nil
36 "Anthy interface for Tamago-tsunagi."
39 (defcustom anthy-egg-use-utf8 nil
40 "*Use UTF-8 for anthy-agent and anthy-dic-tool."
42 :type '(choice (const :tag "Use UTF8" t)
43 (const :tag "No use UTF8" nil)))
45 (defcustom anthy-egg-input-method-list '("japanese-egg-anthy")
46 "*List of input method to use egg-anthy."
48 :type '(repeat (string :format "Input method: %v\n" :size 0)))
50 (defcustom anthy-egg-use-chinese-korean-server nil
51 "*Use egg-anthy with Chinese and/or Korean servers."
53 :type '(choice (const :tag "Use Anthy with Chinese and/or Korean servers" t)
54 (const :tag "No use" nil)))
56 (setplist 'anthy-egg-conversion-backend
57 '(egg-start-conversion anthy-egg-convert
58 egg-get-bunsetsu-source anthy-egg-get-bunsetsu-source
59 egg-get-bunsetsu-converted anthy-egg-get-bunsetsu-converted
60 egg-list-candidates anthy-egg-get-candidates
61 egg-decide-candidate anthy-egg-select-candidate
62 egg-change-bunsetsu-length anthy-egg-resize-segment
63 egg-end-conversion anthy-egg-commit
65 egg-special-candidate anthy-egg-special-candidate
66 egg-word-registration anthy-egg-word-registration
68 egg-get-source-language anthy-egg-get-source-language
69 egg-get-converted-language anthy-egg-get-converted-language))
71 (defconst anthy-egg-backend-alist '((Japanese ((anthy-egg-conversion-backend)))))
73 (egg-set-finalize-backend '(anthy-egg-finalize-backend))
75 (defvar anthy-egg-proc nil
76 "Process of ANTHY helper agent.")
78 (defvar anthy-egg-version nil)
79 (defvar anthy-egg-el-version "20070419")
81 (defvar anthy-egg-anthy-agent-version "")
83 (defun anthy-egg-version ()
85 (message "anthy-egg/anthyipc/anthy-agent: %s" anthy-egg-version)
88 ;; <env> ::= <context-descriptor>
89 ;; <context-descriptor> ::= <integer>
90 (defvar anthy-egg-environment-pool nil
91 "Environments for ANTHY kana-kanji conversion, to be used.")
93 (defvar anthy-egg-environments-in-use nil
94 "Environments for ANTHY kana-kanji conversion, in use.")
97 ;; <anthy-bunsetsu> ::=
98 ;; [ <env> <source> <converted> <candidates> <candidate-pos> <seg-no> ]
99 (defsubst anthy-egg-make-bunsetsu (env source converted seg-no)
101 'anthy-egg-conversion-backend
102 (vector env source converted nil 0 seg-no)))
104 (defsubst anthy-egg-bunsetsu-get-env (b)
105 (aref (egg-bunsetsu-get-info b) 0))
106 (defsubst anthy-egg-bunsetsu-get-source (b)
107 (aref (egg-bunsetsu-get-info b) 1))
108 (defsubst anthy-egg-bunsetsu-get-converted (b)
109 (aref (egg-bunsetsu-get-info b) 2))
110 (defsubst anthy-egg-bunsetsu-get-candidates (b)
111 (aref (egg-bunsetsu-get-info b) 3))
112 (defsubst anthy-egg-bunsetsu-set-candidates (b z)
113 (aset (egg-bunsetsu-get-info b) 3 z))
114 (defsubst anthy-egg-bunsetsu-get-candidate-pos (b)
115 (aref (egg-bunsetsu-get-info b) 4))
116 (defsubst anthy-egg-bunsetsu-set-candidate-pos (b zp)
117 (aset (egg-bunsetsu-get-info b) 4 zp))
118 (defsubst anthy-egg-bunsetsu-get-seg-no (b)
119 (aref (egg-bunsetsu-get-info b) 5))
121 (defun anthy-egg-get-bunsetsu-source (b)
122 (anthy-egg-bunsetsu-get-source b))
124 (defun anthy-egg-get-bunsetsu-converted (b)
125 (let ((cands (anthy-egg-bunsetsu-get-candidates b)))
127 (nth (anthy-egg-bunsetsu-get-candidate-pos b) cands)
128 (anthy-egg-bunsetsu-get-converted b))))
130 (defun anthy-egg-get-source-language (b) 'Japanese)
131 (defun anthy-egg-get-converted-language (b) 'Japanese)
133 (defvar anthy-egg-agent-buffer-name " *anthy-egg*")
135 ;; Getting new context-descriptor, and returns environment with 'inuse' bit
136 (defun anthy-egg-new-environment ()
137 (if (null anthy-egg-proc)
138 (let ((buf (get-buffer-create anthy-egg-agent-buffer-name))
139 (cs (if anthy-egg-use-utf8 'utf-8-dos 'euc-japan-dos))
140 (process-connection-type nil)) ; avoid using pty
142 (apply 'start-process "anthy-egg-agent" buf
144 (if anthy-egg-use-utf8
147 (set-process-query-on-exit-flag anthy-egg-proc nil)
148 (set-process-coding-system anthy-egg-proc cs cs)
149 (set-process-sentinel anthy-egg-proc 'anthy-egg-proc-sentinel)
150 (set-marker-insertion-type (process-mark anthy-egg-proc) t)
151 (with-current-buffer buf
153 (buffer-disable-undo))
154 (anthyipc-get-greeting anthy-egg-proc)))
155 ;; Patch http://www.freebsd.org/cgi/query-pr.cgi?pr=68617
156 (anthyipc-new-context anthy-egg-proc))
158 ;;; XXX: Don't kill buffer (for now) so that I can debug this program
159 (defun anthy-egg-proc-sentinel (proc reason)
160 ;; (kill-buffer (process-buffer proc))
161 (setq anthy-egg-proc nil
162 anthy-egg-environments-in-use nil
163 anthy-egg-environment-pool nil))
165 (defun anthy-egg-get-environment ()
166 "Return the ANTHY environment."
167 (if anthy-egg-environment-pool
168 (let ((env (car anthy-egg-environment-pool)))
169 (setq anthy-egg-environment-pool (cdr anthy-egg-environment-pool))
170 (setq anthy-egg-environments-in-use (cons env anthy-egg-environments-in-use))
172 (let ((env (anthy-egg-new-environment)))
173 (setq anthy-egg-environments-in-use (cons env anthy-egg-environments-in-use))
177 ;; Fake egg functions for UTF-8
179 (defvar anthy-egg-force-anthy nil)
180 (make-variable-buffer-local 'anthy-egg-force-anthy)
182 (defmacro anthy-egg-utf8-p ()
183 `(and anthy-egg-use-utf8
184 (not anthy-egg-use-chinese-korean-server)
185 (or (equal (egg-get-conversion-backend 'Japanese 0 nil)
186 '(0 (anthy-egg-conversion-backend)))
187 (and (not egg-conversion-backend-alist)
188 (member default-input-method anthy-egg-input-method-list)))))
190 (defadvice egg-toroku-bunsetsu (around force-anthy activate compile)
191 "Advice for force-anthy."
192 (if (anthy-egg-utf8-p)
193 (let ((anthy-egg-force-anthy t))
197 (defadvice egg-toroku-region (around force-anthy activate compile)
198 "Advice for force-anthy."
199 (if (anthy-egg-utf8-p)
200 (let ((anthy-egg-force-anthy t))
204 (defadvice egg-convert-region (around force-anthy activate compile)
205 "Advice for force-anthy."
206 (if (and (interactive-p) (anthy-egg-utf8-p))
207 (let ((anthy-egg-force-anthy t))
211 (defadvice egg-separate-languages (around force-anthy activate compile)
212 "Advice for force-anthy."
213 (if (and anthy-egg-force-anthy
215 (eq last-lang 'Japanese)))
216 (let ((len (length str)))
217 (egg-remove-all-text-properties 0 len str)
218 (put-text-property 0 len 'egg-lang 'Japanese str))
222 ;; Returns list of bunsetsu
224 (defun anthy-egg-convert (backend yomi &optional context)
225 "Convert YOMI string to kanji, and enter conversion mode.
226 Return the list of bunsetsu."
227 ;; Convert Katakana to Hiragana
228 (when (eq last-command 'its-katakana)
229 (setq yomi (japanese-hiragana yomi)))
230 (let ((env (anthy-egg-get-environment)))
231 (anthyipc-convert anthy-egg-proc env yomi)))
236 (defun anthy-egg-commit (bunsetsu-list abort)
237 (let ((env (anthy-egg-bunsetsu-get-env (car bunsetsu-list))))
238 (anthyipc-commit anthy-egg-proc env (if abort 1 0))
239 ;; Guard twice pool in egg-decide-before-point()
240 ;; Add. Hideyuki SHIRAI at 2005-02-10
241 (unless (memq env anthy-egg-environment-pool)
242 (setq anthy-egg-environment-pool (cons env anthy-egg-environment-pool)))
243 (setq anthy-egg-environments-in-use (delq env anthy-egg-environments-in-use))
244 (anthy-egg-debug-check)))
247 ;; Returns ( <pos> <candidates> )
249 (defun anthy-egg-get-candidates (bunsetsu-list prev-bunsetsu next-bunsetsu major)
250 (let ((bunsetsu (car bunsetsu-list)))
251 (if (anthy-egg-bunsetsu-get-candidates bunsetsu)
252 (cons (anthy-egg-bunsetsu-get-candidate-pos bunsetsu)
253 (anthy-egg-bunsetsu-get-candidates bunsetsu))
254 (let* ((env (anthy-egg-bunsetsu-get-env bunsetsu))
255 (seg-no (anthy-egg-bunsetsu-get-seg-no bunsetsu))
256 (cands (anthyipc-get-candidates anthy-egg-proc env seg-no)))
257 (cons (anthy-egg-bunsetsu-set-candidate-pos bunsetsu 0)
258 (anthy-egg-bunsetsu-set-candidates bunsetsu cands))))))
260 ;; Returns list of list of bunsetsu
261 (defun anthy-egg-select-candidate (bunsetsu-list candidate-pos prev-b next-b)
262 (let* ((bunsetsu (car bunsetsu-list))
263 (candidate-list (anthy-egg-bunsetsu-get-candidates bunsetsu))
264 (candidate (nth candidate-pos candidate-list))
265 (env (anthy-egg-bunsetsu-get-env bunsetsu))
266 (seg-no (anthy-egg-bunsetsu-get-seg-no bunsetsu)))
267 (anthy-egg-bunsetsu-set-candidate-pos bunsetsu candidate-pos)
268 ;; Anthy doesn't have capability of changing another segment
269 ;; at the selection of a segment.
270 ;; So, just ignore the result of "SELECT-CANDIDATE"
271 (anthyipc-select-candidate anthy-egg-proc env seg-no candidate-pos)
272 (list (list bunsetsu))))
274 ;; Returns list of list of bunsetsu
275 (defun anthy-egg-resize-segment (bunsetsu-list prev-b next-b len major)
276 (let ((bunsetsu (car bunsetsu-list)))
277 (let ((env (anthy-egg-bunsetsu-get-env bunsetsu))
278 (seg-no (anthy-egg-bunsetsu-get-seg-no bunsetsu))
279 (prevlen (length (anthy-egg-bunsetsu-get-source bunsetsu))))
280 (let ((r (anthyipc-resize-segment anthy-egg-proc env seg-no
281 (if (< prevlen len) 0 1))))
282 ;; XXX: I don't know what this means,
283 ;; but this works. Blame EGG.
284 (list (list (car r)) nil (cdr r))))))
286 (defun anthy-egg-finalize-backend ()
288 (delete-process anthy-egg-proc)
289 (setq anthy-egg-proc nil)))
292 ;; Add. Hideyuki SHIRAI at 2005-02-10
293 (defvar anthy-egg-debug t
294 "*Enable debug for egg-anthy.")
296 (defvar anthy-egg-debug-depth 15
297 "*Display message when over this.")
299 (defadvice egg-abort-conversion (before release-content activate)
301 (anthy-egg-pool-content))
303 (defadvice egg-decide-before-point (before release-content activate)
305 (anthy-egg-pool-content))
307 (defun anthy-egg-pool-content ()
308 "Used context move to `pool'."
309 (let* ((bunsetsu (egg-get-bunsetsu-info (point)))
310 (backend (car bunsetsu))
312 (when (eq backend 'anthy-egg-conversion-backend)
313 (setq env (anthy-egg-bunsetsu-get-env bunsetsu))
314 ;; Guard twice pool in egg-decide-before-point()
315 (unless (memq env anthy-egg-environment-pool)
316 (setq anthy-egg-environment-pool (cons env anthy-egg-environment-pool)))
317 (setq anthy-egg-environments-in-use (delq env anthy-egg-environments-in-use))
318 (anthy-egg-debug-check))))
320 (defun anthy-egg-debug-check ()
322 (when (and anthy-egg-debug
323 (> (length anthy-egg-environments-in-use) anthy-egg-debug-depth))
324 (message "egg-anthy debug: in-use %d, pool %d with `%s' => `%s'."
325 (length anthy-egg-environments-in-use)
326 (length anthy-egg-environment-pool)
327 (symbol-name last-command) (symbol-name this-command))
330 (defun anthy-egg-recover ()
331 "Recover error Anthy."
334 (delete-process anthy-egg-proc)
335 (setq anthy-egg-proc nil))
336 (setq anthy-egg-environments-in-use nil)
337 (setq anthy-egg-environment-pool nil))
339 (defun anthy-egg-special-candidate (bunsetsu prev-b next-b major type)
340 "Suport Hiragana, Katakana."
341 (let* ((head (car bunsetsu))
342 (backend (egg-bunsetsu-get-backend head))
343 (lang (get backend 'language))
344 source converted zenkouho-list kouho-list pos)
346 (setq source (anthy-egg-get-bunsetsu-source head))
347 (cond ((eq type 'egg-hiragana)
348 (setq converted source))
349 ((eq type 'egg-katakana)
350 (setq converted (japanese-katakana source))))
352 (cdr (anthy-egg-get-candidates bunsetsu prev-b next-b major)))
354 (when (setq kouho-list (member converted zenkouho-list))
355 (- (length zenkouho-list) (length kouho-list))))
357 (anthy-egg-select-candidate bunsetsu pos prev-b next-b))))
361 ;; freq
\e$B$O$$$/$D$,NI$$$N$+!)
\e(B 1, 10, 100, 1000?
\e$BA*Br!)
\e(B
362 (defvar anthy-egg-hinshi-menu '(("
\e$B0lHLL>;l
\e(B" . NOUN)
363 ("
\e$B8GM-L>;l
\e(B" . PROPER_NOUN)
364 ("
\e$B7AMF;l
\e(B" . ADJECTIVE)
365 ("
\e$BI{;l
\e(B" . ADV)
366 ("
\e$BF0;l
\e(B" . VERB))
367 "*Anthy
\e$B$N<-=qEPO?MQIJ;l
\e(B.")
369 (defvar anthy-egg-hinshi-proper-menu '("
\e$B?ML>
\e(B" "
\e$BCOL>
\e(B")
370 "*Anthy
\e$B$N8GM-L>;l
\e(B")
372 (defvar anthy-egg-hinshi-verb-menu '(("
\e$B%+9T8^CJ3hMQ
\e(B" . "
\e$B%+9T8^CJ
\e(B")
373 ("
\e$B%,9T8^CJ3hMQ
\e(B" . "
\e$B%,9T8^CJ
\e(B")
374 ("
\e$B%59T8^CJ3hMQ
\e(B" . "
\e$B%59T8^CJ
\e(B")
375 ("
\e$B%?9T8^CJ3hMQ
\e(B" . "
\e$B%?9T8^CJ
\e(B")
376 ("
\e$B%J9T8^CJ3hMQ
\e(B" . "
\e$B%J9T8^CJ
\e(B")
377 ("
\e$B%P9T8^CJ3hMQ
\e(B" . "
\e$B%P9T8^CJ
\e(B")
378 ("
\e$B%^9T8^CJ3hMQ
\e(B" . "
\e$B%^9T8^CJ
\e(B")
379 ("
\e$B%i9T8^CJ3hMQ
\e(B" . "
\e$B%i9T8^CJ
\e(B")
380 ("
\e$B%o9T8^CJ3hMQ
\e(B" . "
\e$B%o9T8^CJ
\e(B"))
381 "*Anthy
\e$B$NF0;l3hMQ7?
\e(B.")
384 (defvar anthy-egg-dic-util-command "anthy-dic-tool")
385 (defvar anthy-egg-dic-buffer-name " *anthy-egg-dic*")
387 (defun anthy-egg-add-word-compose-paramlist (param)
390 (let* ((cur (car param))
392 (val (if (stringp (cdr cur))
394 (if (cdr cur) "y" "n"))))
395 (setq str (concat str
396 var " = " val "\n")))
397 (setq param (cdr param)))
400 (defun anthy-egg-add-word (yomi freq word paramlist)
401 (let ((buf (get-buffer-create anthy-egg-dic-buffer-name))
402 (cs (if anthy-egg-use-utf8 'utf-8-unix 'euc-japan-unix))
404 (with-current-buffer buf
405 (setq proc (apply 'start-process "anthy-egg-dic" buf
406 anthy-egg-dic-util-command
407 (if anthy-egg-use-utf8
408 '("--append" "--utf8")
411 (set-process-coding-system proc cs cs)
412 (set-process-sentinel proc
414 (let ((buf (process-buffer proc)))
415 (when (and (process-buffer proc)
416 (buffer-name (process-buffer proc)))
417 (kill-buffer (process-buffer proc))))))
418 (process-send-string proc
420 (int-to-string freq) " "
422 (process-send-string proc
423 (anthy-egg-add-word-compose-paramlist paramlist))
424 (process-send-string proc "\n")
425 (process-send-eof proc)
428 (defun anthy-egg-hinshi-NOUN (kanji)
429 (let ((res '(("
\e$BIJ;l
\e(B" . "
\e$BL>;l
\e(B")))
430 (na (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$J!W$H8@$$$^$9$+
\e(B? " kanji)))
431 (sa (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$5!W$H8@$$$^$9$+
\e(B? " kanji)))
432 (suru (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$9$k!W$H8@$$$^$9$+
\e(B? " kanji)))
433 (ind (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B!W$OC1FH$GJ8@a$K$J$j$^$9$+
\e(B? " kanji)))
434 (kaku (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$H!W$H8@$$$^$9$+
\e(B? " kanji))))
435 (setq res (cons `("
\e$B$J@\B3
\e(B" . ,na) res))
436 (setq res (cons `("
\e$B$5@\B3
\e(B" . ,sa) res))
437 (setq res (cons `("
\e$B$9$k@\B3
\e(B" . ,suru) res))
438 (setq res (cons `("
\e$B8l44$N$_$GJ8@a
\e(B" . ,ind) res))
439 (setq res (cons `("
\e$B3J=u;l@\B3
\e(B" . ,kaku) res))
442 (defun anthy-egg-hinshi-PROPER_NOUN (kanji)
443 `(("
\e$BIJ;l
\e(B" . ,(menudiag-select (list 'menu
444 (format "(%s)
\e$B3hMQ7O
\e(B:" kanji)
445 anthy-egg-hinshi-proper-menu)))))
447 (defun anthy-egg-hinshi-PERSONAL (kanji)
448 '(("
\e$BIJ;l
\e(B" . "
\e$B?ML>
\e(B")))
450 (defun anthy-egg-hinshi-PLACE (kanji)
451 '(("
\e$BIJ;l
\e(B" . "
\e$BCOL>
\e(B")))
453 (defun anthy-egg-hinshi-ADJECTIVE (kanji)
454 '(("
\e$BIJ;l
\e(B" . "
\e$B7AMF;l
\e(B")))
456 (defun anthy-egg-hinshi-ADV (kanji)
457 (let ((res '(("
\e$BIJ;l
\e(B" . "
\e$BI{;l
\e(B")))
458 (to (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$H!W$H8@$$$^$9$+
\e(B? " kanji)))
459 (taru (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$?$k!W$H8@$$$^$9$+
\e(B? " kanji)))
460 (suru (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B$9$k!W$H8@$$$^$9$+
\e(B? " kanji)))
461 (ind (y-or-n-p (format "
\e$B!V
\e(B%s
\e$B!W$OC1FH$GJ8@a$K$J$j$^$9$+
\e(B? " kanji))))
462 (setq res (cons `("
\e$B$H@\B3
\e(B" . ,to) res))
463 (setq res (cons `("
\e$B$?$k@\B3
\e(B" . ,taru) res))
464 (setq res (cons `("
\e$B$9$k@\B3
\e(B" . ,suru) res))
465 (setq res (cons `("
\e$B8l44$N$_$GJ8@a
\e(B" . ,ind) res))
468 (defun anthy-egg-hinshi-VERB (kanji)
469 (let* ((res '(("
\e$BIJ;l
\e(B" . "
\e$BF0;l
\e(B")))
470 (key (menudiag-select (list 'menu
471 (format "(%s)
\e$B3hMQ7O
\e(B:" kanji)
472 anthy-egg-hinshi-verb-menu)))
473 (meishi (y-or-n-p (format "%s:
\e$BO"BN7A$rL>;l2=$7$^$9$+
\e(B? " kanji))))
474 (setq res (cons `("
\e$B3hMQ
\e(B" . ,key) res))
475 (setq res (cons `("
\e$BO"MQ7A$NL>;l2=
\e(B" . ,meishi) res))
478 (defun anthy-egg-hinshi-select (kanji yomi)
479 (let ((key (menudiag-select (list 'menu
480 (concat kanji"(" yomi ") " "
\e$BIJ;l
\e(B:")
481 anthy-egg-hinshi-menu))))
483 (funcall (intern (concat "anthy-egg-hinshi-" (symbol-name key)))
486 (cdr (assoc key anthy-egg-hinshi-menu))))))
488 (defun anthy-egg-word-registration-add (kanji yomi)
490 (setq param (nreverse (anthy-egg-hinshi-select kanji yomi)))
491 (if (anthy-egg-add-word yomi 1000 kanji param)
492 (list (cdr (car param)) "
\e$B%f!<%6<-=q
\e(B")
493 (message "%s (%s)
\e$B$NEPO?$K<:GT$7$^$7$?
\e(B" kanji yomi))))
495 (defun anthy-egg-word-registration (backend kanji yomi)
496 "Register a word KANJI with a pronunciation YOMI."
497 (if (or (null (eq (egg-get-language 0 kanji)
498 (anthy-egg-get-converted-language backend)))
499 (next-single-property-change 0 'egg-lang kanji)
500 (null (eq (egg-get-language 0 yomi)
501 (anthy-egg-get-source-language backend)))
502 (next-single-property-change 0 'egg-lang yomi))
503 (egg-error "word registration: invalid character")
504 (anthy-egg-word-registration-add kanji yomi)))
508 (load "egg/anthyipc")
509 (run-hooks 'anthy-egg-load-hook)
512 (defun egg-activate-anthy (&rest arg)
513 "Activate ANTHY backend of Tamago-tsunagi."
514 (apply 'egg-mode (append arg anthy-egg-backend-alist)))
516 ;;; egg/anthy.el ends here.