1 ;;; its.el --- Input Translation Systam AKA "ITS(uDekirunDa!)"
3 ;; Copyright (C) 1997, 1998 Mule Project, Powered by Electrotechnical
5 ;; Project Leader: Satoru Tomura <tomura@etl.go.jp>
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
12 ;; This file will be part of GNU Emacs (in future).
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.
35 (defvar its-current-language)
36 (make-variable-buffer-local 'its-current-language)
38 ;; Data structure in ITS
41 ;; "SYL" stands for something like a syllable.
43 ;; <SYL> ::= ( <output> . ( <keyseq> . <terminal> )) ; Determined: DSYL
44 ;; | <state> ; Intermediate: ISYL
45 ;; | ( <output> . <point> ) ; Verbatim: VSYL
49 ;; ; ( <output> . ( <keyseq> . <key-state-table/terminal> ))
51 ;; <keyseq> ::= "string" of key sequence
52 ;; <output> ::= "string"
54 ;; <point> ::= integer which specifies point
56 ;; <cursor> ::= nil ; Previous SYL is active (input will go that SYL)
57 ;; | t ; input makes new SYL. DEL deletes previous SYL
58 ;; | its-cursor ; DEL breaks previous SYL, input makes new SYL
60 ;; Data structures in ITS
61 ;; (2) State machine which recognizes SYL
63 ;; <state> ::= ( <output> <keyseq> . <key-state-table/terminal> )
65 ;; <key-state-table/terminal> ::= <key-state-table> ; intermediate state
66 ;; | <terminal> ; terminal state
68 ;; <key-state-table> ::= ( <key-state-alist> . <expr-output-back-list> )
69 ;; <key-state-alist> ::= ( <key-state> ... )
70 ;; <key-state> ::= ( <key> . <state> )
71 ;; <key> ::= Positive INTEGER which specifies KEY STROKE
72 ;; | -1 ; means END of key stroke
74 ;; Only applicable for last transition.
75 ;; <expr-output-back-list> ::= ( (<output> . (<keyexpr> . <howmanyback>))... )
76 ;; <keyexpr> ::= something like "[a-z]" which specifies class of key.
77 ;; | NIL; means ANY of key (except END of the key stroke)
80 ;; <keyseq> ::= "string"
85 ;; <howmanyback> ::= integer which specifies how many key strokes we go back
87 ;; <output> ::= "string"
89 ;; Data structure in ITS (3) Map
91 ;; <map> ::= ( <name> <indicator> <language> . <start-state> )
92 ;; <name> ::= "string"
93 ;; <indicator> ::= "string"
94 ;; <language> ::= "string"
95 ;; <start-state> ::= <state>
98 (defsubst its-new-state (output keyseq back)
99 (cons output (cons keyseq back)))
101 (defsubst its-new-map (name indicator language)
102 (cons name (cons indicator (cons language (its-new-state "" "" nil)))))
104 (defsubst its-get-indicator (map)
107 (defsubst its-get-language (map)
110 (defsubst its-get-start-state (map)
113 (defsubst its-get-kst/t (state)
116 (defsubst its-set-kst (state kst)
117 (setcdr (cdr state) kst))
119 (defsubst its-get-keyseq (state)
122 (defsubst its-set-keyseq (state keyseq)
123 (setcar (cdr state) keyseq))
125 (defun its-get-keyseq-cooked (state)
126 (let ((keyseq (its-get-keyseq state))
127 (back (its-get-kst/t state)))
129 (substring keyseq 0 back)
132 (defsubst its-kst-p (kst/t)
133 (not (or (numberp kst/t) (null kst/t))))
135 (defsubst its-get-output (syl/state)
138 (defsubst its-set-output (state output)
139 (setcar state output))
141 (defsubst its-get-keyseq-syl (syl)
143 (cond ((stringp l) ; DSYL
148 (substring (car l) 0 (cdr l)))
152 (defsubst its-eob-keyexpr (eob)
154 (defsubst its-eob-back (eob)
157 (defsubst its-make-class+back (class back)
159 (defsubst its-make-otherwise (output class+back)
160 (cons output class+back))
162 (defsubst its-DSYL-with-back-p (syl)
163 (and (consp (cdr syl))
164 (numberp (its-get-kst/t syl))))
166 (defsubst its-concrete-DSYL-p (syl)
169 (defsubst its-make-concrete-DSYL (syl)
170 (if (consp (cdr syl))
171 (cons (its-get-output syl) (its-get-keyseq-syl syl))
177 (require 'its-keydef)
180 (let ((map (make-sparse-keymap))
182 (define-key map "\C-a" 'its-beginning-of-input-buffer)
183 (define-key map "\C-b" 'its-backward-SYL)
184 (define-key map "\C-d" 'its-delete-SYL)
185 (define-key map "\C-e" 'its-end-of-input-buffer)
186 (define-key map "\C-f" 'its-forward-SYL)
187 (define-key map "\C-]" 'its-cancel-input)
188 (define-key map "\C-h" 'its-mode-help-command)
189 (define-key map "\C-k" 'its-kill-line)
190 ;; (define-key map "\C-l" 'its-exit-mode)
191 (define-key map "\C-m" 'its-exit-mode) ; RET
192 (define-key map [return] 'its-exit-mode)
193 (define-key map "\C-t" 'its-transpose-chars)
194 (define-key map [backspace] 'its-delete-backward-SYL)
195 (define-key map [delete] 'its-delete-backward-SYL)
196 (define-key map [M-backspace] 'its-delete-backward-SYL-by-keystroke)
197 (define-key map [M-delete] 'its-delete-backward-SYL-by-keystroke)
198 (define-key map [right] 'its-forward-SYL)
199 (define-key map [left] 'its-backward-SYL)
200 (define-key map "\C-\\" 'its-exit-mode-off-input-method)
202 (define-key map (vector i) 'its-self-insert-char)
204 (define-key map " " 'its-kick-convert-region)
205 (define-key map "\177" 'its-delete-backward-SYL)
207 (define-key map "\M-p" 'its-previous-map)
208 (define-key map "\M-n" 'its-next-map)
209 (define-key map "\M-h" 'its-hiragana) ; hiragana-region for input-buffer
210 (define-key map "\M-k" 'its-katakana)
211 (define-key map "\M-<" 'its-hankaku)
212 (define-key map "\M->" 'its-zenkaku)
213 (its-define-select-keys map t)
215 "Keymap for ITS mode.")
217 (defvar its-fence-open "|" "*
\e$B%U%'%s%9$N;OE@$r<($9J8;zNs
\e(B (1
\e$BJ8;z
\e(B)")
218 (defvar its-fence-close "|" "*
\e$B%U%'%s%9$N=*E@$r<($9J8;zNs
\e(B (1
\e$BJ8;z
\e(B)")
219 (defvar its-fence-face nil "*
\e$B%U%'%s%9I=<($KMQ$$$k
\e(B face
\e$B$^$?$O
\e(B nil")
221 (defconst its-setup-fence-before-insert-SYL nil)
223 (defun its-put-cursor (cursor)
225 (map (copy-keymap its-mode-map)))
226 (its-define-select-keys map)
228 (add-text-properties p (point) (list 'local-map map
230 'intangible 'its-part-2
234 (defsubst its-set-cursor-status (cursor)
235 (put-text-property (point) (1+ (point)) 'its-cursor cursor)
239 ;; +-- START property
240 ;; | --- CURSOR Property
242 ;; v v v-- END Property
244 ;; ^^^ ^^^ ^^^------ SYL Property
246 ;; intangible intangible
249 (defun its-setup-fence-mode ()
250 (let ((open-props '(its-start t intangible its-part-1))
251 (close-props '(its-end t intangible its-part-2))
253 (insert its-fence-open)
255 (add-text-properties p p1 open-props)
256 (insert its-fence-close)
257 (add-text-properties p1 (point) close-props)
259 (put-text-property 'invisible t p (point)))
263 (defun its-start (key)
264 (let ((its-setup-fence-before-insert-SYL t))
266 (force-mode-line-update)))
268 (defun its-restart (str)
270 (its-setup-fence-mode)
273 (its-beginning-of-input-buffer)))
275 (defun its-self-insert-char ()
277 (let ((key last-command-char)
278 (cursor (get-text-property (point) 'its-cursor))
279 (syl (get-text-property (1- (point)) 'its-syl)))
282 (not (eq (get-text-property (1- (point)) 'its-map) its-current-map)))
283 (put-text-property (- (point) (length (its-get-output syl))) (point)
284 'its-syl (its-make-concrete-DSYL syl))
288 (its-input syl key)))
290 (defvar its-current-map nil)
291 (make-variable-buffer-local 'its-current-map)
292 (put 'its-current-map 'permanent-local t)
294 (defun its-initial-ISYL ()
295 (its-get-start-state its-current-map))
297 (defun its-make-VSYL (keyseq)
298 (cons keyseq (length keyseq)))
300 (defvar its-barf-on-invalid-keyseq nil
301 "T means don't allow invalid key sequence in input buffer.")
303 (defun its-input-error ()
304 (error "Invalid Romaji Sequence"))
307 (defun its-input (syl key)
309 (setq syl (its-initial-ISYL)))
310 (let ((output (car syl))
314 ;; k/kk/s is "point in keyseq"
315 (its-input-to-vsyl syl key k/kk/s output))
316 ((and its-barf-on-invalid-keyseq
317 (null (its-keyseq-acceptable-p (vector key) syl)))
318 ;; signal before altering
322 (its-state-machine syl key 'its-buffer-ins/del-SYL)))))
324 (defun its-input-to-vsyl (syl key point output)
326 (its-set-cursor-status t)
327 (let ((len (length output)))
329 ;; point is at end of VSYL. Don't need to call state machine.
330 (its-buffer-ins/del-SYL
331 (its-make-VSYL (concat output (vector key))) syl nil)
332 ;; point is at middle of VSYL.
333 (let ((new-keyseq (concat (substring output 0 point)
335 (substring output point))))
336 (its-state-machine-keyseq new-keyseq 'its-buffer-ins/del-SYL))))))
339 ;;; ITS State Machine
343 (defun its-state-machine (state key emit)
344 (let ((next-state (its-get-next-state state key))
345 expr-output-back kst/t output keyseq back)
347 ;; proceed to next status
349 (setq kst/t (its-get-kst/t next-state)
350 output (its-get-output next-state)
351 keyseq (its-get-keyseq next-state))
353 ;; Still, it's a intermediate state.
355 (funcall emit next-state state nil))
357 ;; It's negative integer which specifies how many
358 ;; characters we go backwards
360 (funcall emit next-state state 'its-cursor)
361 (its-state-machine-keyseq (substring keyseq kst/t) emit (< key 0)))
363 ;; Here we arrive to a terminal state.
364 ;; Emit a DSYL, and go ahead.
366 (funcall emit next-state state 'its-cursor))))
368 ;; push back by otherwise status
370 (setq expr-output-back (its-get-otherwise state key)))
371 (setq keyseq (concat (its-get-keyseq state) (vector key)))
373 (cons (its-get-output expr-output-back)
374 (cons keyseq (its-eob-back expr-output-back)))
376 (its-state-machine-keyseq
377 (substring keyseq (its-eob-back expr-output-back)) emit))
379 ((eq its-barf-on-invalid-keyseq 'its-keyseq-test)
380 'its-keyseq-test-failed)
382 ;; No next state for KEY. It's invalid sequence.
383 (its-barf-on-invalid-keyseq
387 ;; XXX Should make DSYL (instead of VSYL)?
388 (setq keyseq (concat (its-get-keyseq state) (if (> key 0) (vector key))))
389 (funcall emit (its-make-VSYL keyseq) state nil)))))
391 (defvar its-latest-SYL nil
392 "The latest SYL inserted.")
393 (defsubst its-update-latest-SYL (syl)
394 (setq its-latest-SYL syl))
397 (defun its-state-machine-keyseq (keyseq emit &optional eol)
399 (len (length keyseq))
400 (syl (its-initial-ISYL))
405 ;; VSYL - no need looping
407 (its-make-VSYL (concat (car syl) (substring keyseq i)))
412 (setq cursor (its-state-machine syl (aref keyseq i) emit))))
413 (if (eq cursor 'its-keyseq-test-failed)
415 (setq syl (if cursor (its-initial-ISYL) its-latest-SYL)
417 (if (and eol (not (eq cursor 'its-keyseq-test-failed)))
418 (its-state-machine syl -1 emit)
421 (defun its-buffer-ins/del-SYL (newsyl oldsyl cursor)
422 (if its-setup-fence-before-insert-SYL
424 (setq its-setup-fence-before-insert-SYL nil)
425 (its-setup-fence-mode)))
426 (its-buffer-delete-SYL oldsyl)
427 (its-update-latest-SYL newsyl)
429 (insert (its-get-output newsyl))
430 (add-text-properties p (point)
431 (list 'its-syl newsyl
432 'its-map its-current-map
433 'its-lang its-current-language
434 'intangible 'its-part-1))
436 (put-text-property p (point) 'face its-fence-face))
437 (its-set-cursor-status cursor)))
439 (defun its-buffer-delete-SYL (syl)
440 (let ((len (length (its-get-output syl))))
441 (delete-region (- (point) len) (point))))
443 (defun its-get-next-state (state key)
444 (let ((kst/t (its-get-kst/t state)))
445 (cdr (assq key (car kst/t)))))
448 (defun its-otherwise-match (expr key)
449 (or (null expr) ; <expr>::= NIL means "ANY"
450 (let ((case-fold-search nil))
451 (string-match expr (char-to-string key)))))
453 (defun its-get-otherwise (state key)
454 (let* ((kst/t (its-get-kst/t state))
458 (setq expr-output-back (car ebl))
459 (let ((expr (its-eob-keyexpr expr-output-back)))
460 (if (its-otherwise-match expr key)
462 (setq ebl (cdr ebl)))))
465 (defun its-keyseq-acceptable-p (keyseq &optional syl eol)
467 (len (length keyseq))
468 (its-barf-on-invalid-keyseq 'its-keyseq-test)
470 (emit (lambda (nsyl osyl cursor)
471 (its-update-latest-SYL nsyl)
475 (setq syl (its-initial-ISYL)))
476 (while (and syl (< i len))
477 (setq cursor (its-state-machine syl (aref keyseq i) emit))
479 ((eq cursor 'its-keyseq-test-failed)
482 (setq syl (its-initial-ISYL)))
487 (setq cursor (its-state-machine syl -1 emit)))
488 (not (eq cursor 'its-keyseq-test-failed))))
495 (defvar its-map-alist nil)
497 (defun its-get-map (name)
498 (assoc name its-map-alist))
500 (defun its-register-map (map)
501 (let* ((name (car map))
502 (place (assoc name its-map-alist)))
504 (setcdr place (cdr map))
505 (setq its-map-alist (cons map its-map-alist)))
508 (defmacro define-its-state-machine (map name indicator lang doc &rest exprs)
510 (eval-when (eval compile)
511 (let ((its-current-map (its-new-map ,name ,indicator ,lang)))
513 (setq ,map its-current-map)))
514 (define-its-compiled-map ,map ,doc)))
516 (defmacro define-its-compiled-map (map doc)
517 `(defconst ,map ',(symbol-value map) ,doc))
519 (defmacro define-its-state-machine-append (map &rest exprs)
521 `(let ((its-current-map ,map)))
523 (list `(setq ,map its-current-map))))
526 ;; Construct State Machine
528 (defun its-defrule (input output &optional back enable-overwrite)
529 "
\e$BF~NO
\e(B INPUT
\e$B$rG'<1$7
\e(B, OUTPUT
\e$B$r=PNO$9$k$h$&$K%9%F!<%H%^%7%s$r9=@.$9$k!#
\e(B
530 BACK
\e$B$,
\e(B(
\e$BIi$N
\e(B)
\e$B@0?t$N;~$O
\e(B, OUTPUT
\e$B$r=PNO$7$?8e
\e(B, BACK
\e$B$NJ,
\e(B key stroke
\e$B$r
\e(B
531 \e$BLa$C$FF0$/$b$N$H$9$k!#JQ495,B'$O$b$C$H$b:G6a$K
\e(B its-define-state-machine
532 \e$B$5$l$?JQ49I=$KEPO?$5$l$k!#
\e(B
534 (let ((state (its-goto-state (substring input 0 -1) nil t))
535 (key (aref input (1- (length input)))))
536 (if (and (its-get-next-state state key) (not enable-overwrite))
537 (error "Duplicated definition (%s)" input)
538 (its-make-next-state state key input output back))))
540 (defun its-goto-state (input &optional initial-state build-if-none)
541 (let ((len (length input))
543 (state (or initial-state (its-get-start-state its-current-map))))
546 (or (its-get-next-state state (aref input i))
548 (let ((keyseq (substring input 0 (1+ i))))
549 (its-make-next-state state (aref input i) keyseq keyseq))
550 (error "No such state (%s)" input)))
554 (defun its-defoutput (input display)
555 (let ((state (its-goto-state input)))
556 (its-set-output state display)))
558 (defun its-define-otherwise (state otherwise)
559 (let ((kst (its-get-kst/t state)))
561 (setcdr kst (cons otherwise (cdr kst)))
562 (its-set-kst state (cons nil (cons otherwise nil))))))
564 (defconst its-otherwise-back-one
565 (its-make-class+back nil -1))
567 (defun its-defrule-otherwise (state output &optional class back)
570 (setq class+back its-otherwise-back-one)
571 (setq class+back (its-make-class+back class back)))
572 (its-define-otherwise state
573 (its-make-otherwise output class+back))))
575 (defun its-defrule* (input output)
576 (let ((state (its-defrule input output)))
577 (its-defrule-otherwise state output)))
579 (defun its-make-next-state (state key keyseq output &optional back)
580 (let ((next-state (its-new-state output keyseq back))
581 (kst (its-get-kst/t state)))
583 (setcar kst (cons (cons key next-state) (car kst)))
584 (its-set-kst state (list (list (cons key next-state)))))
588 (defun its-beginning-of-input-buffer ()
591 (if (not (get-text-property (1- (point)) 'its-start))
592 (let ((begpos (previous-single-property-change (point) 'its-start)))
593 ;; Make SYLs have property of "part 2"
594 (put-text-property begpos (point) 'intangible 'its-part-2)
598 (defun its-end-of-input-buffer ()
601 (if (not (get-text-property (point) 'its-end))
602 (let ((endpos (next-single-property-change (point) 'its-end)))
603 ;; Make SYLs have property of "part 1"
604 (put-text-property (point) endpos 'intangible 'its-part-1)
608 ;; TODO: move in VSYL
609 (defun its-backward-SYL (n)
612 (let ((syl (get-text-property (1- (point)) 'its-syl))
615 (while (and syl (> n 0))
616 (setq p (- p (length (its-get-output syl))))
617 (setq syl (get-text-property (1- p) 'its-syl))
619 ;; Make SYLs have property of "part 2"
620 (put-text-property p old-point 'intangible 'its-part-2)
624 (signal 'beginning-of-buffer nil))))
626 ;; TODO: move in VSYL
627 (defun its-forward-SYL (n)
630 (let ((syl (get-text-property (point) 'its-syl))
633 (while (and syl (> n 0))
634 (setq p (+ p (length (its-get-output syl))))
635 (setq syl (get-text-property p 'its-syl))
637 ;; Make SYLs have property of "part 1"
638 (put-text-property old-point p 'intangible 'its-part-1)
642 (signal 'end-of-buffer nil))))
644 ;; TODO: handle VSYL. KILLFLAG
645 (defun its-delete-SYL (n killflag)
648 (let ((syl (get-text-property (point) 'its-syl))
650 (while (and syl (> n 0))
651 (setq p (+ p (length (its-get-output syl))))
652 (setq syl (get-text-property p 'its-syl))
657 (signal 'args-out-of-range (list p n)))
658 (delete-region (point) p)
660 (let ((s (get-text-property (1- (point)) 'its-start))
661 (e (get-text-property (point) 'its-end)))
663 (its-exit-mode-internal)
664 (its-put-cursor t))))))
667 (defun its-delete-backward-SYL (n killflag)
669 (let ((syl (get-text-property (1- (point)) 'its-syl))
670 (cursor (get-text-property (point) 'its-cursor)))
672 (signal 'beginning-of-buffer nil)
674 (its-delete-backward-SYL-internal n killflag)
675 (its-delete-backward-within-SYL syl n killflag)))))
678 (defun its-delete-backward-SYL-internal (n killflag)
679 (let ((syl (get-text-property (1- (point)) 'its-syl))
681 (while (and syl (> n 0))
682 (setq p (- p (length (its-get-output syl))))
683 (setq syl (get-text-property (1- p) 'its-syl))
686 (signal 'args-out-of-range (list p n))
687 (delete-region p (1+ (point))) ; also delete cursor
689 (let ((s (get-text-property (1- (point)) 'its-start))
690 (e (get-text-property (point) 'its-end)))
692 (its-exit-mode-internal)
693 (its-put-cursor t))))))
695 (defvar its-delete-by-keystroke nil)
697 (defun its-delete-backward-SYL-by-keystroke (n killflag)
699 (let ((its-delete-by-keystroke t))
700 (its-delete-backward-SYL n killflag)))
703 (defun its-delete-backward-within-SYL (syl n killflag)
704 (let* ((keyseq (its-get-keyseq-syl syl))
705 (len (length keyseq))
706 (p (- (point) (length (its-get-output syl))))
707 (its-current-map (get-text-property (1- (point)) 'its-map))
710 (signal 'args-out-of-range (list (- (point) n) (point))))
711 (if its-delete-by-keystroke
712 (while (null (or (eq p pp) (its-concrete-DSYL-p syl)))
714 (while (and (setq syl (get-text-property (1- p) 'its-syl))
715 (its-DSYL-with-back-p syl)
716 (<= (setq back (- (its-get-kst/t syl))) len)
718 (equal (substring (its-get-keyseq syl) (- back))
719 (substring keyseq 0 back)))
720 (setq keyseq (concat (its-get-keyseq-syl syl) keyseq)
722 p (- p (length (its-get-output syl)))))
723 (if (and (eq p pp) syl (> n len))
725 keyseq (its-get-keyseq-syl syl)
727 p (- p (length (its-get-output syl))))))
728 (if (and (> n len) (its-concrete-DSYL-p syl))
733 (while (and (> n len) (setq syl (get-text-property (1- p) 'its-syl)))
735 p (- p (length (its-get-output syl)))))
737 (signal 'beginning-of-buffer nil))
738 (delete-region p (point))
741 (its-state-machine-keyseq (substring keyseq 0 (- len n))
742 'its-buffer-ins/del-SYL))
744 ((and (get-text-property (1- (point)) 'its-start)
745 (get-text-property (1+ (point)) 'its-end))
747 (delete-region (point) (1+ (point)))
748 (its-exit-mode-internal))
749 ((and its-delete-by-keystroke
750 (null (its-concrete-DSYL-p (get-text-property (1- p) 'its-syl))))
751 (its-set-cursor-status 'its-cursor))
753 (its-set-cursor-status t)))))
755 (defun its-transpose-chars (n)
757 (let ((syl (get-text-property (1- (point)) 'its-syl))
758 (cursor (get-text-property (point) 'its-cursor))
762 (signal 'beginning-of-buffer nil))
764 (if (and (= n 1) (get-text-property (1+ (point)) 'its-end))
767 (setq syl (get-text-property (1- (point)) 'its-syl))
769 (signal 'beginning-of-buffer nil))))
770 (its-buffer-delete-SYL syl)
772 (if (get-text-property (1+ (point)) 'its-end)
774 (its-buffer-ins/del-SYL syl nil t)
775 (signal 'end-of-buffer nil)))
779 (if (get-text-property (1- (point)) 'its-start)
781 (its-buffer-ins/del-SYL syl nil t)
782 (signal 'beginning-of-buffer nil)))
785 (its-buffer-ins/del-SYL syl nil t))
787 (setq keyseq (its-get-keyseq-syl syl)
790 ((or (> n 1) (<= len 1))
791 (signal 'end-of-buffer nil))
793 (signal 'beginning-of-buffer nil))
795 (setq n (if (> n 0) (- -1 n) (1- n)))
796 (setq keyseq (concat (substring keyseq 0 n)
797 (substring keyseq -1)
798 (substring keyseq n -1)))
799 (if (and its-barf-on-invalid-keyseq
800 (null (its-keyseq-acceptable-p keyseq)))
802 (delete-region (- (point) (length (its-get-output syl))) (point))
803 (its-state-machine-keyseq keyseq 'its-buffer-ins/del-SYL)))))))
806 (defun its-input-end ()
807 (let ((cursor (get-text-property (point) 'its-cursor)))
810 (its-input (get-text-property (1- (point)) 'its-syl) -1))
811 (delete-region (point) (1+ (point)))))
813 (defun its-exit-mode ()
817 (its-exit-mode-internal))
819 (defun its-exit-mode-off-input-method ()
823 (its-exit-mode-internal)
824 (inactivate-input-method))
826 ;; TODO: handle overwrite-mode, insertion-hook, fill...
827 (defun its-exit-mode-internal (&optional proceed-to-conversion)
830 (if (get-text-property (1- (point)) 'its-start)
831 (setq start (1- (point)))
832 (setq start (1- (previous-single-property-change (point) 'its-start))))
833 (delete-region start (1+ start))
834 ;; Delete close fence
835 (if (get-text-property (point) 'its-end)
837 (setq end (next-single-property-change (point) 'its-end)))
838 (delete-region end (1+ end))
839 ;; Remove all properties added by ITS
840 (remove-text-properties start end '(its-map nil
843 (if proceed-to-conversion
844 (egg-convert-region start end)
845 (remove-text-properties start end '(its-lang nil its-syl nil))
847 (run-hooks 'input-method-after-insert-chunk-hook))))
849 (defun its-kick-convert-region ()
852 (its-exit-mode-internal t))
854 (defun its-in-fence-p ()
855 (eq (get-text-property (point) 'intangible) 'its-part-2))
857 (defvar its-translation-result "" "")
859 (defun its-ins/del-SYL-batch (newsyl oldsyl cursor)
860 (its-update-latest-SYL newsyl)
863 (not (its-kst-p (its-get-kst/t newsyl))))
865 (let ((output (its-get-output newsyl))
866 (oldlen (length its-translation-result)))
867 (setq its-translation-result (concat its-translation-result output))
868 (put-text-property oldlen (length its-translation-result)
869 'its-lang its-current-language
870 its-translation-result)))
873 (defun its-translate-region (start end)
875 (its-translate-region-internal start end)
876 (remove-text-properties start (point) '(its-lang nil)))
878 (defun its-translate-region-internal (start end)
879 (setq its-translation-result "")
882 (syl (its-initial-ISYL))
883 ;; temporally enable DING
884 (its-barf-on-invalid-keyseq t)
886 (while (< (point) end)
887 (let ((key (following-char)))
888 (setq cursor (its-state-machine syl key 'its-ins/del-SYL-batch))
891 (setq syl (its-initial-ISYL))
892 (setq syl its-latest-SYL))))
893 (if (eq syl its-latest-SYL)
894 (its-state-machine syl -1 'its-ins/del-SYL-batch))
895 (delete-region start end)
896 (insert its-translation-result)))
899 ;;; its.el ends here.