changeset 26891:651d521c8f52

(quail-install-map): New optional arg NAME. (quail-get-translation): If DEF is a symbol but not a function, ignore it. (quail-start-translation): Put a key sequence undefined in the translation keymap in unread-command-events, not generated-events. Return parameterized event (compose-last-chars N) if the input characters should be composed. (quail-map-definition): If DEF is t, treat it as nil. (quail-delete-last-char): Delete the quail region. (quail-show-translations): Don't show list of translations if the quail package is deterministic. (quail-completion-max-depth): New variable. (quail-completion-1): Pay attention to the above variable. Fix for the case that a translation is a function. (quail-map-from-table, quail-map-from-table-1, quail-map-from-table-2): New functions. (quail-lookup-map-and-concat): New function
author Kenichi Handa <handa@m17n.org>
date Wed, 15 Dec 1999 00:42:43 +0000
parents 4cd9407a4683
children fce3871ada53
files lisp/international/quail.el
diffstat 1 files changed, 160 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/international/quail.el	Wed Dec 15 00:42:14 1999 +0000
+++ b/lisp/international/quail.el	Wed Dec 15 00:42:43 1999 +0000
@@ -673,8 +673,12 @@
 	map)))
 
 ;;;###autoload
-(defun quail-install-map (map)
+(defun quail-install-map (map &optional name)
   "Install the Quail map MAP in the current Quail package.
+
+Optional 2nd arg NAME, if non-nil, is a name of Quail package for
+which to install MAP.
+
 The installed map can be referred by the function `quail-map'."
   (if (null quail-current-package)
       (error "No current Quail package"))
@@ -786,8 +790,10 @@
 the translation, and INDEX points into VECTOR to specify the currently
 selected translation."
   (if (and def (symbolp def))
-      ;; DEF is a symbol of a function which returns valid translation.
-      (setq def (funcall def key len)))
+      (if (functionp def)
+	  ;; DEF is a symbol of a function which returns valid translation.
+	  (setq def (funcall def key len))
+	(setq def nil)))
   (if (and (consp def) (not (vectorp (cdr def))))
       (setq def (car def)))
 
@@ -955,17 +961,33 @@
 		    (quail-error (message "%s" (cdr err)) (beep))))
 	      ;; KEYSEQ is not defined in the translation keymap.
 	      ;; Let's return the event(s) to the caller.
-	      (setq generated-events
+	      (setq unread-command-events
 		    (string-to-list (this-single-command-raw-keys)))
 	      (setq quail-translating nil))))
 	(quail-delete-region)
 	(if (and quail-current-str (> (length quail-current-str) 0))
-	    (setq generated-events
-		  (append (string-to-list
-			   (if enable-multibyte-characters
-			       quail-current-str
-			     (string-make-unibyte quail-current-str)))
-			  generated-events)))
+	    (let* ((len (length quail-current-str))
+		   (idx 0)
+		   (val (find-composition 0 len quail-current-str))
+		   char)
+	      ;; Push characters in quail-current-str one by one to
+	      ;; generated-events while interleaving it with a special
+	      ;; event (compose-last-chars LEN) at each composition
+	      ;; end.
+	      (while (<= idx len)
+		(when (and val (= idx (nth 1 val)))
+		  (setq generated-events
+			(cons (list 'compose-last-chars (- idx (car val)))
+			      generated-events))
+		  (setq val (find-composition idx len quail-current-str)))
+		(when (< idx len)
+		  (setq char (aref quail-current-str idx))
+		  (or enable-multibyte-characters
+		      (setq char (multibyte-char-to-unibyte char)))
+		  (setq generated-events (cons char generated-events)))
+		(setq idx (1+ idx)))
+	      ;; Reorder generated-events.
+	      (setq generated-events (nreverse generated-events))))
 	(if (and input-method-exit-on-first-char generated-events)
 	    (list (car generated-events))
 	  generated-events))
@@ -1125,6 +1147,8 @@
   (let ((def (car map)))
     (if (and (consp def) (not (vectorp (cdr def))))
 	(setq def (car def)))
+    (if (eq def t)
+	(setq def nil))
     def))
 
 ;; Return a string to be shown as the current translation of key
@@ -1339,6 +1363,7 @@
   (if (= (length quail-current-key) 1)
       (quail-abort-translation)
     (setq quail-current-key (substring quail-current-key 0 -1))
+    (quail-delete-region)
     (quail-update-translation (quail-translate-key))))
 
 ;; For conversion mode.
@@ -1636,7 +1661,8 @@
 	    (insert "]")))
 
       ;; Show list of translations.
-      (if current-translations
+      (if (and current-translations
+	       (not (quail-deterministic)))
 	  (let* ((indices (car current-translations))
 		 (cur (car indices))
 		 (start (nth 1 indices))
@@ -1657,10 +1683,13 @@
 	      (setq idx (1+ idx)))))
       )))
 
+(defvar quail-completion-max-depth 5
+  "The maximum depth of Quail completion list.")
+
 (defun quail-completion ()
   "List all completions for the current key.
 All possible translations of the current key and whole possible longer keys
- are shown."
+are shown (at most to the depth specified `quail-completion-max-depth')."
   (interactive)
   (quail-setup-completion-buf)
   (let ((win (get-buffer-window quail-completion-buf 'visible))
@@ -1700,10 +1729,12 @@
 	(quail-completion-list-translations map key (+ indent len 1))
       (insert " -\n"))
     (setq indent (+ indent 2))
-    (if (cdr map)
+    (if (and (cdr map) (< (/ (1- indent) 2) quail-completion-max-depth))
 	(let ((l (cdr map))
 	      (newkey (make-string (1+ len) 0))
 	      (i 0))
+	  (if (functionp l)
+	      (setq l (funcall l)))
 	  ;; Set KEY in the first LEN characters of NEWKEY.
 	  (while (< i len)
 	    (aset newkey i (aref key i))
@@ -1965,6 +1996,122 @@
 	  (message nil)
 	  (quail-update-guidance)
 	  ))))
+
+;; Quail map generator from state transition table.
+
+(defun quail-map-from-table (table)
+  "Make quail map from state transition table TABLE.
+
+TABLE is an alist, the form is:
+  ((STATE-0 TRANSITION-0-1 TRANSITION-0-2 ...) (STATE-1 ...) ...)
+
+STATE-n are symbols to denote state.  STATE-0 is the initial state.
+
+TRANSITION-n-m are transition rules from STATE-n, and have the form
+\(RULES . STATE-x) or RULES, where STATE-x is one of STATE-n above,
+RULES is a symbol whose value is an alist of keys \(string) vs the
+correponding characters or strings.  The format of the symbol value of
+RULES is the same as arguments to `quail-define-rules'.
+
+If TRANSITION-n-m has the form (RULES . STATE-x), it means that
+STATE-n transits to STATE-x when keys in RULES are input.  Recursive
+transition is allowed, i.e. STATE-x may be STATE-n.
+
+If TRANSITION-n-m has the form RULES, the transition terminates
+when keys in RULES are input.
+
+The generated map can be set for the current Quail package by the
+function `quail-install-map' (which see)."
+  (let ((state-alist (mapcar (lambda (x) (list (car x))) table))
+	tail elt)
+    ;; STATE-ALIST is an alist of states vs the correponding sub Quail
+    ;; map.  It is now initialized to ((STATE-0) (STATE-1) ...).
+    ;; Set key sequence mapping rules in cdr part of each element.
+    (while table
+      (quail-map-from-table-1 state-alist (car table))
+      (setq table (cdr table)))
+
+    ;; Now STATE-ALIST has the form ((STATE-0 MAPPING-RULES) ...).
+    ;; Elements of MAPPING-RULES may have the form (STATE-x).  Replace
+    ;; them with MAPPING-RULES of STATE-x to make elements of
+    ;; STATE-ALIST valid Quail maps.
+    (setq tail state-alist)
+    (while tail
+      (setq elt (car tail) tail (cdr tail))
+      (quail-map-from-table-2 state-alist elt))
+
+    ;; Return the Quail map for the initial state.
+    (car state-alist)))
+
+;; STATE-INFO has the form (STATE TRANSITION ...).  Set key sequence
+;; mapping rules in the element of STATE-ALIST that corresponds to
+;; STATE according to TRANSITION ...
+(defun quail-map-from-table-1 (state-alist state-info)
+  (let* ((state (car state-info))
+	 (map (assq state state-alist))
+	 (transitions (cdr state-info))
+	 elt)
+    (while transitions
+      (setq elt (car transitions) transitions (cdr transitions))
+      (let (rules dst-state key trans)
+	;; ELT has the form (RULES-SYMBOL . STATE-x) or RULES-SYMBOL.
+	;; STATE-x is one of car parts of STATE-ALIST's elements.
+	(if (consp elt)
+	    (setq rules (symbol-value (car elt))
+		  ;; Set (STATE-x) as branches for all keys in RULES.
+		  ;; It is replaced with actual branches for STATE-x
+		  ;; later in `quail-map-from-table-2'.
+		  dst-state (list (cdr elt)))
+	  (setq rules (symbol-value elt)))
+	(while rules
+	  (setq key (car (car rules)) trans (cdr (car rules))
+		rules (cdr rules))
+	  (if (stringp trans)
+	      (if (= (length trans) 1)
+		  (setq trans (aref trans 0))
+		(setq trans (string-to-vector trans))))
+	  (set-nested-alist key trans map nil dst-state))))))
+
+;; ELEMENT is one element of STATE-ALIST.  ELEMENT is a nested alist;
+;; the form is:
+;;	(STATE (CHAR NESTED-ALIST) ...)
+;; NESTED-ALIST is a nested alist; the form is:
+;;	(TRANS (CHAR NESTED-ALIST) ...)
+;; or
+;;	(TRANS (CHAR NESTED-ALIST) ... . (STATE-x))
+;; Here, the task is to replace all occurrences of (STATE-x) with:
+;;	(cdr (assq STATE-x STATE-ALIST))
+
+(defun quail-map-from-table-2 (state-alist element)
+  (let ((prev element)
+	(tail (cdr element))
+	 elt)
+    (while (cdr tail)
+      (setq elt (car tail) prev tail tail (cdr tail))
+      (quail-map-from-table-2 state-alist (cdr elt)))
+    (setq elt (car tail))
+    (if (consp elt)
+	(quail-map-from-table-2 state-alist (cdr elt))
+      (setcdr prev (cdr (assq elt state-alist))))))
+
+;; Concatenate translations for all heading substrings of KEY in the
+;; current Quail map.  Here, `heading substring' means (substring KEY
+;; 0 LEN), where LEN is 1, 2, ... (length KEY).
+(defun quail-lookup-map-and-concat (key)
+  (let* ((len (length key))
+	 (translation-list nil)
+	 map)
+    (while (> len 0)
+      (setq map (quail-lookup-key key len)
+	    len (1- len))
+      (if map
+	  (let* ((def (quail-map-definition map))
+		 (trans (if (consp def) (aref (cdr def) (car (car def)))
+			  def)))
+	    (if (integerp trans)
+		(setq trans (char-to-string trans)))
+	    (setq translation-list (cons trans translation-list)))))
+    (apply 'concat translation-list)))
 
 
 (defvar quail-directory-name "quail"