X-Git-Url: http://git.chise.org/gitweb/?p=elisp%2Fegg.git;a=blobdiff_plain;f=egg-cnv.el;h=a996838cbbb5aeb084c958830446ce97e77f66d3;hp=b85cd045a19ff193138615a8a3653696d056b9c5;hb=a11e28d9cdf108d34265730dcbfd406ae85971b9;hpb=d0114d80c7a6a1a573bb3adc0fd4a3b25fa1e27e diff --git a/egg-cnv.el b/egg-cnv.el index b85cd04..a996838 100644 --- a/egg-cnv.el +++ b/egg-cnv.el @@ -1,4 +1,4 @@ -;;; egg-cnv.el --- Conversion Backend in Egg Input Method Architecture +pn;;; egg-cnv.el --- Conversion Backend in Egg Input Method Architecture ;; Copyright (C) 1997, 1998 Mule Project, ;; Powered by Electrotechnical Laboratory, JAPAN. @@ -9,7 +9,7 @@ ;; Maintainer: NIIBE Yutaka ;; Keywords: mule, multilingual, input method -;; This file will be part of GNU Emacs (in future). +;; This file is part of EGG. ;; EGG is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -31,31 +31,33 @@ ;;; Code: +(require 'egg-edep) + (defvar egg-current-language) (make-variable-buffer-local 'egg-current-language) (put 'egg-current-language 'permanent-local t) (defsubst egg-bunsetsu-info () 'intangible) -(defun egg-get-bunsetsu-info (p) - (let ((bunsetsu-info (get-text-property p (egg-bunsetsu-info)))) +(defun egg-get-bunsetsu-info (p &optional object) + (let ((bunsetsu-info (get-text-property p (egg-bunsetsu-info) object))) (if bunsetsu-info - (setq egg-conversion-backend (get-text-property p 'egg-backend) - egg-current-language (get-text-property p 'egg-lang))) + (setq egg-conversion-backend (get-text-property p 'egg-backend object) + egg-current-language (get-text-property p 'egg-lang object))) bunsetsu-info)) ;; (defconst egg-conversion-backend-other-languages [ egg-init-other-languages - egg-start-conversion-other-languages + egg-start-conversion-other-languages egg-get-bunsetsu-converted-other-languages egg-get-bunsetsu-source-other-languages egg-list-candidates-other-languages - egg-get-number-of-candidates-other-languages - egg-get-current-candidate-number-other-languages - egg-get-all-candidates-other-languages - egg-decide-candidate-other-languages + egg-get-number-of-candidates-other-languages + egg-get-current-candidate-number-other-languages + egg-get-all-candidates-other-languages + egg-decide-candidate-other-languages egg-change-bunsetsu-length-other-languages egg-end-conversion-other-languages nil @@ -67,6 +69,7 @@ ) (defun egg-start-conversion-other-languages (yomi-string language) + (setq egg-conversion-backend egg-conversion-backend-other-languages) (list yomi-string)) (defun egg-get-bunsetsu-converted-other-languages (bunsetsu-info) bunsetsu-info) @@ -88,7 +91,7 @@ (if (= len (length s)) (list s) (list (substring s 0 len) (substring s len))))) -(defun egg-end-conversion-other-languages (bunsetsu-info-list) +(defun egg-end-conversion-other-languages (bunsetsu-info-list abort) nil) (defun egg-fini-other-languages (language) nil) @@ -102,7 +105,7 @@ (defun egg-set-current-backend (language) (setq egg-conversion-backend - (cdr (assoc language egg-conversion-backend-alist))) + (cdr (assq language egg-conversion-backend-alist))) (if (null egg-conversion-backend) (setq egg-conversion-backend egg-conversion-backend-other-languages))) @@ -129,8 +132,8 @@ (funcall (aref egg-conversion-backend 8) bunsetsu-info candidate-pos)) (defun egg-change-bunsetsu-length (b0 b1 b2 len) (funcall (aref egg-conversion-backend 9) b0 b1 b2 len)) -(defun egg-end-conversion (bunsetsu-info-list) - (funcall (aref egg-conversion-backend 10) bunsetsu-info-list)) +(defun egg-end-conversion (bunsetsu-info-list abort) + (funcall (aref egg-conversion-backend 10) bunsetsu-info-list abort)) (defun egg-start-reverse-conversion (yomi-string language) (egg-set-current-backend language) (if (aref egg-conversion-backend 11) @@ -165,165 +168,179 @@ (defvar egg-conversion-open "|" "*フェンスの始点を示す文字列 (1 文字以上)") (defvar egg-conversion-close "|" "*フェンスの終点を示す文字列 (1 文字以上)") (defvar egg-conversion-face nil "*フェンス表示に用いる face または nil") +(defvar egg-conversion-invisible nil) (defvar egg-conversion-separator " ") (defun egg-get-conversion-face () (let ((face (and (listp egg-conversion-face) - (or (assoc egg-current-language egg-conversion-face) - (assoc t egg-conversion-face))))) + (or (assq egg-current-language egg-conversion-face) + (assq t egg-conversion-face))))) (if face (cdr face) egg-conversion-face))) ;; (defun egg-convert-region (start end) (interactive "r") - (if (>= start end) - ;; nothing to do - nil - (remove-text-properties start end '(read-only nil intangible nil)) - (goto-char start) - (insert egg-conversion-open) - (let ((inhibit-read-only t) - (max (make-marker)) - bunsetsu-info-list contin p s e result) - (setq p (+ (point) (- end start))) - (set-text-properties start (point) - (list - 'read-only t - 'egg-start t - 'egg-source (buffer-substring (point) p))) - (if egg-conversion-face - (put-text-property start (point) 'invisible t)) - (setq start (point)) - (goto-char p) - (insert egg-conversion-close) - (set-text-properties p (point) '(read-only t rear-nonsticky t egg-end t)) - (if egg-conversion-face - (put-text-property p (point) 'invisible t)) - (set-marker max p) - (egg-separate-languages start max) - (goto-char start) - (while (< (point) max) - (setq egg-current-language (get-text-property (point) 'egg-lang) - s (point) - e (point)) - (while (and (< e max) - (equal egg-current-language - (get-text-property e 'egg-lang))) - (setq e (next-single-property-change e 'egg-lang nil max))) - (condition-case result - (setq bunsetsu-info-list - (egg-start-conversion - (buffer-substring-no-properties s e) - egg-current-language)) - (error - (setq egg-conversion-backend egg-conversion-backend-other-languages - bunsetsu-info-list (egg-start-conversion-other-languages - (buffer-substring-no-properties s e) - egg-current-language)) - (message "egg %s backend: %s" egg-current-language (cadr result)))) - (setq contin (< e max)) - (delete-region s e) - (egg-insert-bunsetsu-list bunsetsu-info-list - (if (< (point) max) 'contine t))) - (set-marker max nil) - (goto-char start)))) - -(defun egg-separate-languages (start end &optional use-context) - (let (lang last-lang last-chinese p pe l c cset) + (let ((source (buffer-substring start end)) + (no-prop-source (buffer-substring-no-properties start end)) + bunsetsu-info-list len result i j s) + (if (>= start end) + ;; nothing to do + nil + (delete-region start end) + (let ((inhibit-read-only t)) + (its-define-select-keys egg-conversion-map) + (goto-char start) + ;; XXX: Why make OPEN&CLOSE string every time when + ;; this function is invoked? Any Reason? + ;; For me it's matter of user costomization + ;; of setting egg-conversion-open/egg-conversion-close + ;; it can be string of properties at the beginning, isn't it? + (setq s (copy-sequence egg-conversion-open) + len (length s)) + (set-text-properties 0 len + (list + 'read-only t + 'egg-start t + 'egg-source source) + s) + (if egg-conversion-invisible + (put-text-property 0 len 'invisible t s)) + (insert s) + (setq start (point) + s (copy-sequence egg-conversion-close) + len (length s)) + (set-text-properties 0 len + '(read-only t rear-nonsticky t egg-end t) + s) + (if egg-conversion-invisible + (put-text-property 0 len 'invisible t s)) + (insert s) + (goto-char start) + (egg-separate-languages (copy-sequence source)) + (setq i 0 + len (length source)) + (while (< i len) + (setq egg-current-language (get-text-property i 'egg-lang source) + j (egg-next-single-property-change i 'egg-lang source len)) + (condition-case result + (setq bunsetsu-info-list (egg-start-conversion + (substring no-prop-source i j) + egg-current-language)) + (error ; XXX: catching all error is BADBADBAD + (setq bunsetsu-info-list (egg-start-conversion-other-languages + (substring no-prop-source i j) + egg-current-language)) + (message "egg %s backend: %s" + egg-current-language (nth 1 result)))) + (egg-insert-bunsetsu-list bunsetsu-info-list + (if (< j len) 'contine t)) + (setq i j)) + (goto-char start))))) + +(defconst egg-chinese-sisheng-regexp + (concat "[" (list (make-char 'chinese-sisheng 32)) + "-" (list (make-char 'chinese-sisheng 127)) + "]+")) + +(defun egg-separate-languages (str &optional last-lang) + (let (lang last-chinese + (len (length str)) i j l) ;; 1st pass -- mark undefined Chinese part - (goto-char start) - (and use-context - (setq last-lang (get-text-property (1- (point)) 'egg-lang)) - (or (equal last-lang "Chinese-GB") (equal last-lang "Chinese-CNS")) - (setq last-chinese last-lang)) - (while (< (point) end) - (setq p (point) - pe (next-single-property-change (point) 'egg-lang nil end)) - (cond - ((get-text-property (point) 'egg-lang) - (goto-char pe) - (setq lang nil)) - ((setq l (egg-chinese-syllable (buffer-substring p pe))) - (goto-char (+ p l)) - (setq lang "Chinese")) - ((progn - (setq c (following-char) - cset (char-charset c)) - (eq cset 'chinese-sisheng)) - (forward-char) - (setq lang "Chinese")) - ((eq cset 'ascii) - (skip-chars-forward "\0-\177" pe) - (if (eq (char-charset (following-char)) 'chinese-sisheng) - (goto-char (max (1+ pp) (- (point) 6)))) - (setq lang nil)) - ((eq cset 'composition) - (forward-char) - (setq lang (egg-charset-to-language - (char-charset (car (decompose-composite-char c 'list)))))) - (t - (skip-chars-forward (concat (vector (make-char cset 33 33)) - "-" - (vector (make-char cset 127 127))) - pe) - (setq lang (egg-charset-to-language cset)))) - (if lang - (put-text-property p (point) 'egg-lang lang))) + (if (or (eq last-lang 'Chinese-GB) (eq last-lang 'Chinese-CNS)) + (setq last-chinese last-lang)) + (setq i 0) + (while (< i len) + (setq j (egg-next-single-property-change i 'egg-lang str len)) + (if (get-text-property i 'egg-lang str) + nil + (setq c (egg-string-to-char-at str i) + cset (char-charset c)) + (cond + ((eq cset 'chinese-sisheng) + (string-match egg-chinese-sisheng-regexp str i) + (setq l (match-end 0) + j (min j l) + lang 'Chinese)) + ((setq l (egg-chinese-syllable str i)) + (setq j (+ i l) + lang 'Chinese)) + ((eq cset 'ascii) + (if (eq (string-match "[\0-\177\240-\377]+" str (1+ i)) (1+ i)) + (setq j (match-end 0)) + (setq j (1+ i))) + (if (and (< j len) + (eq (char-charset (egg-string-to-char-at str j)) + 'chinese-sisheng)) + (setq j (max (1+ i) (- j 6)))) + (setq lang nil)) + ((eq cset 'composition) + (setq j (+ i (egg-char-bytes c)) + lang (egg-charset-to-language + (char-charset + (car (decompose-composite-char c 'list)))))) + (t + (string-match (concat "[" (list (make-char cset 32 32)) + "-" (list (make-char cset 127 127)) + "]+") + str i) + (setq j (match-end 0) + lang (egg-charset-to-language cset)))) + (if lang + (put-text-property i j 'egg-lang lang str))) + (setq i j)) ;; 2nd pass -- set language property - (goto-char start) - (while (< (point) end) - (setq lang (get-text-property (point) 'egg-lang)) + (setq i 0) + (while (< i len) + (setq lang (get-text-property i 'egg-lang str)) (cond ((null lang) (setq lang (or last-lang - (egg-next-part-lang end)))) - ((equal lang "Chinese") + (egg-next-part-lang str i)))) + ((equal lang 'Chinese) (setq lang (or last-chinese - (egg-next-chinese-lang end))))) + (egg-next-chinese-lang str i))))) (setq last-lang lang) - (if (or (equal lang "Chinese-GB") (equal lang "Chinese-CNS")) + (if (or (eq lang 'Chinese-GB) (eq lang 'Chinese-CNS)) (setq last-chinese lang)) - (setq p (point)) - (goto-char (next-single-property-change (point) 'egg-lang nil end)) - (set-text-properties p (point) (list 'egg-lang lang))))) + (setq j i + i (egg-next-single-property-change i 'egg-lang str len)) + (set-text-properties j i (list 'egg-lang lang) str)))) +;;; Should think again the interface to language-info-alist (defun egg-charset-to-language (charset) (let ((list language-info-alist)) (while (and list (null (memq charset (assq 'charset (car list))))) (setq list (cdr list))) - (car (car list)))) - -(defun egg-next-part-lang (end) - (let* ((p (next-single-property-change (point) 'egg-lang nil end)) - (lang (get-text-property p 'egg-lang))) - (if (equal lang "Chinese") - (egg-next-chinese-lang end) + (if list + (intern (car (car list)))))) + +(defun egg-next-part-lang (str pos) + (let ((lang (get-text-property + (egg-next-single-property-change pos 'egg-lang str (length str)) + 'egg-lang str))) + (if (eq lang 'Chinese) + (egg-next-chinese-lang str pos) (or lang its-current-language egg-default-language)))) -(defun egg-next-chinese-lang (end) - (let (p lang) - (setq p (point)) - (while (and (< p end) (null lang)) - (setq p (next-single-property-change p 'egg-lang nil end)) - (setq lang (get-text-property p 'egg-lang)) - (if (null (or (equal lang "Chinese-GB") - (equal lang "Chinese-CNS"))) +(defun egg-next-chinese-lang (str pos) + (let ((len (length str)) lang) + (while (and (< pos len) (null lang)) + (setq pos (egg-next-single-property-change pos 'egg-lang str len) + lang (get-text-property pos 'egg-lang str)) + (if (null (or (eq lang 'Chinese-GB) + (eq lang 'Chinese-CNS))) (setq lang nil))) (cond (lang lang) - ((or (equal its-current-language "Chinese-GB") - (equal its-current-language "Chinese-CNS")) - its-current-language) - ((or (equal egg-default-language "Chinese-GB") - (equal egg-default-language "Chinese-CNS")) - egg-default-language) - (t "Chinese-GB")))) + ((eq its-current-language 'Chinese-GB) 'Chinese-GB) + ((eq its-current-language 'Chinese-CNS) 'Chinese-CNS) + ((eq egg-default-language 'Chinese-GB) 'Chinese-GB) + ((eq egg-default-language 'Chinese-CNS) 'Chinese-CNS) + (t 'Chinese-GB)))) -(require 'its-keydef) - (defvar egg-conversion-map (let ((map (make-sparse-keymap)) (i 33)) @@ -352,39 +369,45 @@ (define-key map [right] 'egg-forward-bunsetsu) (define-key map [left] 'egg-backward-bunsetsu) (define-key map " " 'egg-next-candidate) - (its-define-select-keys map) map) "Keymap for EGG Conversion mode.") +(fset 'egg-conversion-map egg-conversion-map) + (defun egg-exit-conversion-unread-char () (interactive) (setq unread-command-events (list last-command-event)) (egg-exit-conversion)) -(defun egg-insert-bunsetsu (bunsetsu-info last) - (let ((bunsetsu (egg-get-bunsetsu-converted bunsetsu-info)) - (p (point)) p1) - (insert bunsetsu) - (setq p1 (point)) +(defun egg-make-bunsetsu (bunsetsu-info last) + (let ((bunsetsu (copy-sequence (egg-get-bunsetsu-converted bunsetsu-info))) + len len1) + (setq len1 (length bunsetsu)) (if (null (eq last t)) - (insert egg-conversion-separator)) - (set-text-properties p (point) + (setq bunsetsu (concat bunsetsu egg-conversion-separator))) + (setq len (length bunsetsu)) + (set-text-properties 0 len (list 'read-only t (egg-bunsetsu-info) bunsetsu-info 'egg-backend egg-conversion-backend 'egg-lang egg-current-language 'egg-bunsetsu-last last - 'local-map egg-conversion-map)) + 'local-map 'egg-conversion-map) + bunsetsu) (if egg-conversion-face - (put-text-property p p1 'face (egg-get-conversion-face))))) + (egg-set-face 0 len1 (egg-get-conversion-face) bunsetsu)) + bunsetsu)) (defun egg-insert-bunsetsu-list (bunsetsu-info-list &optional last) (let ((l bunsetsu-info-list) - bunsetsu-info) + bunsetsu-info bunsetsu) (while l (setq bunsetsu-info (car l) - l (cdr l)) - (egg-insert-bunsetsu bunsetsu-info (and (null l) last))))) + l (cdr l) + bunsetsu (cons (egg-make-bunsetsu bunsetsu-info + (and (null l) last)) + bunsetsu))) + (apply 'insert (nreverse bunsetsu)))) ; XXX: Should avoid apply and reverse (defun egg-beginning-of-conversion-buffer (n) (interactive "p") @@ -431,13 +454,13 @@ (egg-get-bunsetsu-info (- p 2)))) (defun egg-separate-characters (str) - (let* ((v (string-to-vector str)) + (let* ((v (egg-string-to-vector str)) (len (length v)) (i 0) (j 0) m n (nchar 0)) (while (< i len) (if (setq n (egg-chinese-syllable str j)) - (setq m (chars-in-string (substring str j (+ j n)))) - (setq m 1 n (char-bytes (aref v i)))) + (setq m (egg-chars-in-period str j n)) + (setq m 1 n (egg-char-bytes (aref v i)))) (put-text-property j (+ j n) 'egg-char-size n str) (setq nchar (1+ nchar) i (+ i m) j (+ j n))) nchar)) @@ -486,6 +509,10 @@ (if beep (ding)))) +(defvar egg-conversion-wrap-select nil + "*Candidate selection wraps around to first candidate, if non-nil. +Otherwise stop at the last candidate.") + (defun egg-next-candidate (n) (interactive "p") (let ((inhibit-read-only t) @@ -503,17 +530,21 @@ (setq i (egg-get-current-candidate-number b)) (setq i (+ n i))) (if (null max+) - (setq beep t) - (if (< i 0) ; go backward as if it is ring - (while (< i 0) - (setq i (+ i max+)))) - (if (>= i max+) ; don't go forward - (setq i (1- max+) - beep t)) + (setq beep t) + (cond + ((< i 0) ; go backward as if it is ring + (while (< i 0) + (setq i (+ i max+)))) + ((< i max+)) ; OK + (egg-conversion-wrap-select ; go backward as if it is ring + (while (>= i max+) + (setq i (- i max+)))) + ((setq i (1- max+) ; don't go forward + beep t))) (setq new (egg-decide-candidate b i)) (setq p (point)) (delete-region p (progn (forward-char) (point))) - (egg-insert-bunsetsu new last) + (insert (egg-make-bunsetsu new last)) (goto-char p)) (if beep (ding)))) @@ -559,46 +590,44 @@ (defun egg-decide-before-point () (interactive) (let ((inhibit-read-only t) - (len (length egg-conversion-open)) - bunsetsu-list bl (p (point)) source lang s) - (save-restriction - (if (null (get-text-property (1- (point)) 'egg-start)) - (goto-char (previous-single-property-change (point) 'egg-start))) - (narrow-to-region (- (point) len) p) - (setq bunsetsu-list (setq bl (list nil))) - (while (< (point) (point-max)) - ;; delete sparator/open marker - (delete-region (- (point) len) (point)) - (setq len 1 - bl (setcdr bl (list (egg-get-bunsetsu-info (point))))) - (if (get-text-property (point) 'egg-bunsetsu-last) - (progn - (egg-end-conversion (cdr bunsetsu-list)) - (setq bunsetsu-list (setq bl (list nil))))) - (setq p (point)) - (forward-char) - (set-text-properties p (point) nil))) - (if (cdr bunsetsu-list) - (egg-end-conversion (cdr bunsetsu-list))) - (if (get-text-property (point) 'egg-end) + start end len decided undecided bunsetsu source) + (setq start (if (get-text-property (1- (point)) 'egg-start) + (point) + (previous-single-property-change (point) 'egg-start)) + end (if (get-text-property (point) 'egg-end) + (point) + (next-single-property-change (point) 'egg-end)) + decided (buffer-substring start (point)) + undecided (buffer-substring (point) end)) + (delete-region (- start (length egg-conversion-open)) + (+ end (length egg-conversion-close))) + (setq i 0 + len (length decided)) + (while (< i len) + (setq bunsetsu (cons (egg-get-bunsetsu-info i decided) bunsetsu) + i (egg-next-single-property-change + i (egg-bunsetsu-info) decided len)) + (if (or (= i len) + (get-text-property (1- i) 'egg-bunsetsu-last decided)) + (progn + (setq bunsetsu (nreverse bunsetsu)) + (apply 'insert (mapcar (lambda (b) (egg-get-bunsetsu-converted b)) + bunsetsu)) + (egg-end-conversion bunsetsu nil) + (setq bunsetsu nil)))) + (setq len (length undecided)) + (if (= len 0) (progn - ;; delete close marker - (delete-region (point) (+ (point) (length egg-conversion-close))) (egg-do-auto-fill) (run-hooks 'input-method-after-insert-chunk-hook)) - ;; delete from last speparater - (delete-region (1- (point)) (point)) - (setq source "") - (while (null (get-text-property (point) 'egg-end)) - (setq s (egg-get-bunsetsu-source (egg-get-bunsetsu-info (point)))) - (put-text-property 0 (length s) 'egg-lang egg-current-language s) - (setq source (concat source s)) - (setq p (point)) - (forward-char) - (delete-region p (point))) - ;; delete close marker - (delete-region (point) (+ (point) (length egg-conversion-close))) - (its-restart source t)))) + (setq i 0) + (while (< i len) + (setq source (cons (egg-get-bunsetsu-source + (egg-get-bunsetsu-info i undecided)) + source) + i (egg-next-single-property-change + i (egg-bunsetsu-info) undecided len))) + (its-restart (apply 'concat (nreverse source)) t)))) (defun egg-exit-conversion () (interactive) @@ -615,7 +644,8 @@ (setq source (get-text-property (point) 'egg-source)) (delete-region (point) (+ (next-single-property-change (point) 'egg-end) (length egg-conversion-close))) - (its-restart source))) + (its-restart source) + (its-end-of-input-buffer))) (defun egg-select-candidate () (interactive) @@ -649,8 +679,21 @@ (setq new (egg-decide-candidate b i)) (setq p (point)) (delete-region p (progn (forward-char) (point))) - (egg-insert-bunsetsu new last) + (insert (egg-make-bunsetsu new last)) (goto-char p))))) +(defun egg-conversion-mode () + "\\{egg-conversion-map}" + ;; dummy function to get docstring + ) + +(defun egg-help-command () + "Display documentation for EGG Conversion mode." + (interactive) + (with-output-to-temp-buffer "*Help*" + (princ "EGG Conversion mode:\n") + (princ (documentation 'egg-conversion-mode)) + (help-setup-xref (cons #'help-xref-mode (current-buffer)) (interactive-p)))) + (provide 'egg-cnv) ;;; egg-cnv.el ends here.