emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/pyim 6ce5f49b8f 01/41: Big refactor: use cl-defstruct a


From: ELPA Syncer
Subject: [elpa] externals/pyim 6ce5f49b8f 01/41: Big refactor: use cl-defstruct and cl-defgeneric.
Date: Sat, 4 Jun 2022 09:57:45 -0400 (EDT)

branch: externals/pyim
commit 6ce5f49b8f563cef1485dd27093a4e6ce1506470
Author: Feng Shu <tumashu@163.com>
Commit: Feng Shu <tumashu@163.com>

    Big refactor: use cl-defstruct and cl-defgeneric.
---
 README.org           |   2 -
 pyim-autoselector.el |   7 +-
 pyim-candidates.el   | 144 ++++++++++++++++++++--------------------
 pyim-cloudim.el      |  48 ++++++--------
 pyim-codes.el        |  36 +++++-----
 pyim-cregexp.el      |  26 ++++----
 pyim-cstring.el      | 158 ++++++++++++++++++++++++--------------------
 pyim-imobjs.el       |  36 +++++-----
 pyim-liberime.el     |  68 +++++++++++--------
 pyim-outcome.el      |  13 +---
 pyim-page.el         |  80 ++++++++++------------
 pyim-preview.el      |   4 +-
 pyim-process.el      |  44 +++++++------
 pyim-scheme.el       | 115 ++++++++++++++++++++++----------
 pyim.el              |  20 +++---
 tests/pyim-tests.el  | 183 +++++++++++++++++++++++++++++++++------------------
 16 files changed, 541 insertions(+), 443 deletions(-)

diff --git a/README.org b/README.org
index 558ca39d18..d278dc124e 100644
--- a/README.org
+++ b/README.org
@@ -227,8 +227,6 @@ pyim 的选词框默认使用 *双行显示* 的样式,在一些特殊的情
 (setq pyim-page-style 'one-line)
 #+end_example
 
-注:用户可以添加函数 pyim-page-style:STYLENAME 来定义自己的选词框格式。
-
 ** 设置模糊音
 可以通过设置 `pyim-pinyin-fuzzy-alist' 变量来自定义模糊音。
 
diff --git a/pyim-autoselector.el b/pyim-autoselector.el
index 973d6b3a6f..acb272ce5a 100644
--- a/pyim-autoselector.el
+++ b/pyim-autoselector.el
@@ -40,13 +40,12 @@
 
 比如:五笔等型码输入法,重码率很低,90%以上的情况都是选择第一个词
 条,自动选择可以减少按空格强制选词的机会。"
-  (let* ((scheme-name (pyim-scheme-name))
-         (class (pyim-scheme-get-option scheme-name :class))
-         (n (pyim-scheme-get-option scheme-name :code-split-length))
+  (let* ((scheme (pyim-scheme-current))
+         (n (pyim-scheme-xingma-code-split-length scheme))
          (entered (pyim-process-get-entered 'point-before))
          (candidates (pyim-process-get-candidates))
          (last-candidates (pyim-process-get-last-candidates)))
-    (when (eq class 'xingma)
+    (when (pyim-scheme-xingma-p scheme)
       (cond
        ((and (= (length entered) n)
              (= (length candidates) 1)
diff --git a/pyim-candidates.el b/pyim-candidates.el
index 0aa0321f8b..0cd99f1287 100644
--- a/pyim-candidates.el
+++ b/pyim-candidates.el
@@ -50,13 +50,10 @@
   "上一轮备选词条列表,这个变量主要用于 autoselector 机制.")
 
 (defvar pyim-candidate-position nil
-  "当前选择的词条在 ‘pyim-candidates’ 中的位置.
+  "当前选择的词条在 `pyim-candidates’ 中的位置.
 
 细节信息请参考 `pyim-page-refresh' 的 docstring.")
 
-(defvar pyim-candidates-cloud-search-function nil
-  "`pyim-candidates-cloud-search' 调用的函数.")
-
 (pyim-register-local-variables
  '(pyim-candidates pyim-candidate-position))
 
@@ -65,48 +62,49 @@
   "对 CANDIDATES 进行排序。"
   (pyim-dcache-call-api 'sort-words candidates))
 
-(defun pyim-candidates-create (imobjs scheme-name &optional async)
-  "按照 SCHEME-NAME 对应的输入法方案, 从输入法内部对象列表:
-IMOBJS 获得候选词条。"
-  (when imobjs
-    (let ((class (pyim-scheme-get-option scheme-name :class)))
-      (when class
-        (funcall (intern (format "pyim-candidates-create:%S" class))
-                 imobjs scheme-name async)))))
-
-(defun pyim-candidates-get-chief (scheme-name &optional personal-words 
common-words)
-  "选取第一位候选词。"
-  (let ((class (pyim-scheme-get-option scheme-name :class)))
-    (cond ((equal class 'xingma)
-           (or
-            ;; 如果从公共词库里面获取到的第一个词条是汉字,就选择它。
-            (when (= (length (car common-words)) 1)
-              (car common-words))
-            ;; 从个人词库里面按排列的先后顺序,获取一个汉字。
-            (cl-find-if
-             (lambda (word)
-               (= (length word) 1))
-             personal-words)))
-          (t (or
-              ;; 最近输入的10个不同的词中出现一次以上。
-              (cl-find-if
-               (lambda (word)
-                 (> (or (car (pyim-dcache-get word 
'(iword2count-recent-10-words))) 0) 1))
-               personal-words)
-              ;; 最近输入的50个不同的词中出现过三次以上。
-              (cl-find-if
-               (lambda (word)
-                 (> (or (car (pyim-dcache-get word 
'(iword2count-recent-50-words))) 0) 3))
-               personal-words)
-              ;; 个人词条中的第一个词。
-              (car personal-words))))))
-
-(defun pyim-candidates-create:xingma (imobjs scheme-name &optional async)
-  "`pyim-candidates-create' 处理五笔仓颉等形码输入法的函数."
+(cl-defgeneric pyim-candidates-get-chief (scheme &optional personal-words 
common-words)
+  "PYIM 输入法第一位候选词的获取策略。")
+
+(cl-defmethod pyim-candidates-get-chief ((_scheme pyim-scheme-xingma)
+                                         &optional personal-words common-words)
+  "五笔仓颉等形码输入法第一位候选词的选择策略。"
+  (or
+   ;; 如果从公共词库里面获取到的第一个词条是汉字,就选择它。
+   (when (= (length (car common-words)) 1)
+     (car common-words))
+   ;; 从个人词库里面按排列的先后顺序,获取一个汉字。
+   (cl-find-if
+    (lambda (word)
+      (= (length word) 1))
+    personal-words)))
+
+(cl-defmethod pyim-candidates-get-chief ((_scheme pyim-scheme-quanpin)
+                                         &optional personal-words 
_common-words)
+  "PYIM 输入法第一位候选词的获取通用策略。"
+  (or
+   ;; 最近输入的10个不同的词中出现一次以上。
+   (cl-find-if
+    (lambda (word)
+      (> (or (car (pyim-dcache-get word '(iword2count-recent-10-words))) 0) 1))
+    personal-words)
+   ;; 最近输入的50个不同的词中出现过三次以上。
+   (cl-find-if
+    (lambda (word)
+      (> (or (car (pyim-dcache-get word '(iword2count-recent-50-words))) 0) 3))
+    personal-words)
+   ;; 个人词条中的第一个词。
+   (car personal-words)))
+
+(cl-defgeneric pyim-candidates-create (imobjs scheme &optional async)
+  "按照 SCHEME, 从 IMOBJS 获得候选词条。")
+
+(cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-xingma)
+                                             &optional async)
+  "按照 SCHEME, 从 IMOBJS 获得候选词条,用于五笔仓颉等形码输入法。"
   (unless async
     (let (result)
       (dolist (imobj imobjs)
-        (let* ((codes (pyim-codes-create imobj scheme-name))
+        (let* ((codes (pyim-codes-create imobj scheme))
                (last-code (car (last codes)))
                (other-codes (remove last-code codes))
                output prefix)
@@ -123,7 +121,7 @@ IMOBJS 获得候选词条。"
             (setq prefix (mapconcat
                           (lambda (code)
                             (pyim-candidates-get-chief
-                             scheme-name
+                             scheme
                              (pyim-dcache-get code '(icode2word))
                              (pyim-dcache-get code '(code2word))))
                           other-codes "")))
@@ -136,7 +134,7 @@ IMOBJS 获得候选词条。"
                 (let* ((personal-words (pyim-dcache-get last-code 
'(icode2word)))
                        (personal-words (pyim-candidates-sort personal-words))
                        (common-words (pyim-dcache-get last-code '(code2word)))
-                       (chief-word (pyim-candidates-get-chief scheme-name 
personal-words common-words))
+                       (chief-word (pyim-candidates-get-chief scheme 
personal-words common-words))
                        (common-words (pyim-candidates-sort common-words))
                        (other-words (pyim-dcache-get last-code 
'(shortcode2word))))
                   (mapcar (lambda (word)
@@ -150,24 +148,25 @@ IMOBJS 获得候选词条。"
       (when (car result)
         (delete-dups result)))))
 
-(defun pyim-candidates-create:quanpin (imobjs scheme-name &optional async)
-  "`pyim-candidates-create' 处理全拼输入法的函数."
+(cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-quanpin)
+                                             &optional async)
+  "按照 SCHEME, 从 IMOBJS 获得候选词条,用于全拼输入法。"
   (if async
       ;; 构建一个搜索中文的正则表达式, 然后使用这个正则表达式在当前 buffer 中搜
       ;; 索词条。
-      (let ((str (string-join (pyim-codes-create (car imobjs) scheme-name))))
+      (let ((str (string-join (pyim-codes-create (car imobjs) scheme))))
         (if (< (length str) 1)
             pyim-candidates
           ;; NOTE: 让第一个词保持不变是不是合理,有待进一步的观察。
           `(,(car pyim-candidates)
-            ,@(pyim-candidates-cloud-search str 'quanpin)
+            ,@(pyim-candidates-cloud-search str scheme)
             ,@(pyim-candidates-search-buffer
                (pyim-cregexp-build str 3 t))
             ,@(cdr pyim-candidates))))
     ;; 这段代码主要实现以下功能:假如用户输入 nihaomazheshi, 但词库里面找不到对
     ;; 应的词条,那么输入法自动用 nihaoma 和 zheshi 的第一个词条:"你好吗" 和 "
     ;; 这是" 连接成一个新的字符串 "你好吗这是" 做为第一个候选词。
-    (let* ((candidates (pyim-candidates-create-quanpin imobjs scheme-name))
+    (let* ((candidates (pyim-candidates-create-quanpin imobjs scheme))
            (n (length (car candidates)))
            output)
       (push (car candidates) output)
@@ -176,16 +175,18 @@ IMOBJS 获得候选词条。"
                              (mapcar (lambda (imobj)
                                        (nthcdr n imobj))
                                      imobjs))))
-        (let ((candidates (pyim-candidates-create-quanpin imobjs scheme-name)))
-          (push (car (pyim-candidates-create-quanpin imobjs scheme-name t)) 
output)
+        (let ((candidates (pyim-candidates-create-quanpin imobjs scheme)))
+          (push (car (pyim-candidates-create-quanpin imobjs scheme t)) output)
           (setq n (length (car candidates)))))
       (append (pyim-subconcat (nreverse output) "")
               candidates))))
 
-(defun pyim-candidates-cloud-search (string scheme-name)
-  "云搜索 STRING, 返回候选词条列表."
-  (ignore-errors
-    (funcall pyim-candidates-cloud-search-function string scheme-name)))
+(cl-defgeneric pyim-candidates-cloud-search (string scheme)
+  "云搜索 STRING, 返回候选词条列表.")
+
+(cl-defmethod pyim-candidates-cloud-search (_string _scheme)
+  "默认不使用云搜索."
+  nil)
 
 (defun pyim-candidates-search-buffer (regexp)
   "在当前 buffer 中使用 REGEXP 搜索词条。"
@@ -209,8 +210,8 @@ IMOBJS 获得候选词条。"
                       (> (or (gethash a counts) 0)
                          (or (gethash b counts) 0))))))))
 
-(defun pyim-candidates-create-quanpin (imobjs scheme-name &optional 
fast-search)
-  "`pyim-candidates-create:quanpin' 内部使用的函数。"
+(defun pyim-candidates-create-quanpin (imobjs scheme &optional fast-search)
+  "`pyim-candidates-create' 内部使用的函数。"
   (let (;; Let indent beautiful.
         jianpin-words znabc-words
         personal-words common-words
@@ -220,7 +221,7 @@ IMOBJS 获得候选词条。"
     (let ((codes (mapcar (lambda (x)
                            (pyim-subconcat x "-"))
                          (mapcar (lambda (imobj)
-                                   (pyim-codes-create imobj scheme-name))
+                                   (pyim-codes-create imobj scheme))
                                  imobjs))))
       (setq znabc-words
             (pyim-zip (mapcar #'pyim-dcache-get
@@ -233,13 +234,13 @@ IMOBJS 获得候选词条。"
                (> (length (car imobjs)) 1))
       (dolist (imobj imobjs)
         (let* ((w (pyim-dcache-get
-                   (string-join (pyim-codes-create imobj scheme-name 1) "-")
+                   (string-join (pyim-codes-create imobj scheme 1) "-")
                    '(ishortcode2word)))
                (regexp1 (string-join
-                         (pyim-codes-create imobj scheme-name)
+                         (pyim-codes-create imobj scheme)
                          "-"))
                (regexp2 (string-join
-                         (pyim-codes-create imobj scheme-name)
+                         (pyim-codes-create imobj scheme)
                          "[^-]*-"))
                (w1 (cl-remove-if-not
                     (lambda (cstr)
@@ -257,19 +258,19 @@ IMOBJS 获得候选词条。"
     (dolist (imobj imobjs)
       (let* (;; 个人词条
              (w1 (pyim-dcache-get
-                  (string-join (pyim-codes-create imobj scheme-name) "-")
+                  (string-join (pyim-codes-create imobj scheme) "-")
                   (if pyim-enable-shortcode
                       '(icode2word ishortcode2word)
                     '(icode2word))))
              ;; 词库词条
              (w2 (pyim-dcache-get
-                  (string-join (pyim-codes-create imobj scheme-name) "-")
+                  (string-join (pyim-codes-create imobj scheme) "-")
                   (if pyim-enable-shortcode
                       '(code2word shortcode2word)
                     '(code2word))))
              ;; 第一个汉字
              (w3 (pyim-dcache-get
-                  (car (pyim-codes-create imobj scheme-name))))
+                  (car (pyim-codes-create imobj scheme))))
              ;; 如果 w3 找不到第一个拼音对应的汉字,那就进一步使用
              ;; `pyim-pymap-py2cchar-get' 来查找,这个函数支持声母搜索。可以得到
              ;; 更多的词条。
@@ -281,7 +282,7 @@ IMOBJS 获得候选词条。"
                                       ;; 这个结论只是猜测。
                                       (car (split-string x "|")))
                                     (pyim-pymap-py2cchar-get
-                                     (car (pyim-codes-create imobj 
scheme-name)))))))))
+                                     (car (pyim-codes-create imobj 
scheme)))))))))
         (push w1 personal-words)
         (push w2 common-words)
         (push w3 pinyin-chars-1)
@@ -297,7 +298,7 @@ IMOBJS 获得候选词条。"
     ;; 比较特殊,不参与排序,具体原因请参考 `pyim-page-select-word' 中的
     ;; comment.
     (setq personal-words (pyim-candidates-sort personal-words))
-    (setq chief-word (pyim-candidates-get-chief scheme-name personal-words))
+    (setq chief-word (pyim-candidates-get-chief scheme personal-words))
 
     ;; 调试输出
     (when pyim-debug
@@ -325,12 +326,13 @@ IMOBJS 获得候选词条。"
              ,@pinyin-chars-2
              )))))
 
-(defun pyim-candidates-create:shuangpin (imobjs scheme-name &optional async)
-  "`pyim-candidates-create' 处理双拼输入法的函数."
+(cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-shuangpin)
+                                             &optional async)
+  "按照 SCHEME, 从 IMOBJS 获得候选词条,用于双拼输入法。"
   (if async
       ;; 构建一个搜索中文的正则表达式, 然后使用这个正则表达式在当前 buffer 中搜
       ;; 索词条。
-      (let ((str (string-join (pyim-codes-create (car imobjs) scheme-name))))
+      (let ((str (string-join (pyim-codes-create (car imobjs) scheme))))
         (if (< (length str) 1)
             pyim-candidates
           ;; NOTE: 让第一个词保持不变是不是合理,有待进一步的观察。
@@ -341,7 +343,7 @@ IMOBJS 获得候选词条。"
                (let ((pyim-default-scheme 'quanpin))
                  (pyim-cregexp-build str 3 t)))
             ,@(cdr pyim-candidates))))
-    (pyim-candidates-create:quanpin imobjs 'quanpin async)))
+    (cl-call-next-method)))
 
 ;; * Footer
 (provide 'pyim-candidates)
diff --git a/pyim-cloudim.el b/pyim-cloudim.el
index b08c573a45..e371c6ac76 100644
--- a/pyim-cloudim.el
+++ b/pyim-cloudim.el
@@ -42,26 +42,17 @@
           (const :tag "Use baidu cloud input method." baidu)
           (const :tag "Use google cloud input method." google)))
 
-(defun pyim-cloudim (string scheme-name)
-  "使用云输入法引擎搜索 STRING 获取词条列表.
-云输入法由 `pyim-cloudim' 设置。"
-  (when (and pyim-cloudim (symbolp pyim-cloudim))
-    (let ((func (intern (format "pyim-cloudim:%s" pyim-cloudim))))
-      (when (functionp func)
-        (funcall func string scheme-name)))))
-
-(setq pyim-candidates-cloud-search-function #'pyim-cloudim)
-
-(defun pyim-cloudim:baidu (string scheme-name)
+(cl-defmethod pyim-candidates-cloud-search
+  (string (_scheme pyim-scheme-quanpin)
+          &context (pyim-cloudim (eql 'baidu)))
   "使用 baidu 云输入法引擎搜索 STRING, 获取词条列表。"
-  (when (equal scheme-name 'quanpin)
-    (let ((buffer (pyim-cloudim-url-retrieve-sync
-                   (format "https://olime.baidu.com/py?py=%s"; string)
-                   t nil 0.2)))
-      (when (bufferp buffer)
-        (with-current-buffer buffer
-          (prog1 (pyim-cloudim-parse-baidu-buffer)
-            (kill-buffer)))))))
+  (let ((buffer (pyim-cloudim-url-retrieve-sync
+                 (format "https://olime.baidu.com/py?py=%s"; string)
+                 t nil 0.2)))
+    (when (bufferp buffer)
+      (with-current-buffer buffer
+        (prog1 (pyim-cloudim-parse-baidu-buffer)
+          (kill-buffer))))))
 
 (defun pyim-cloudim-url-retrieve-sync (url &optional silent inhibit-cookies 
timeout)
   "Pyim 版本的 `url-retrieve-synchronously'.
@@ -134,16 +125,17 @@
     (when (> (length word) 0)
       (list (propertize word :comment "(云)")))))
 
-(defun pyim-cloudim:google (string scheme-name)
+(cl-defmethod pyim-candidates-cloud-search
+  (string (_scheme pyim-scheme-quanpin)
+          &context (pyim-cloudim (eql 'google)))
   "使用 google 云输入法引擎搜索 STRING, 获取词条列表。"
-  (when (eq scheme-name 'quanpin)
-    (let ((buffer (pyim-cloudim-url-retrieve-sync
-                   (format 
"https://www.google.cn/inputtools/request?ime=pinyin&text=%s"; string)
-                   t nil 0.2)))
-      (when (bufferp buffer)
-        (with-current-buffer buffer
-          (prog1 (pyim-cloudim-parse-google-buffer)
-            (kill-buffer)))))))
+  (let ((buffer (pyim-cloudim-url-retrieve-sync
+                 (format 
"https://www.google.cn/inputtools/request?ime=pinyin&text=%s"; string)
+                 t nil 0.3)))
+    (when (bufferp buffer)
+      (with-current-buffer buffer
+        (prog1 (pyim-cloudim-parse-google-buffer)
+          (kill-buffer))))))
 
 (defun pyim-cloudim-parse-google-buffer ()
   "解析 `pyim-cloudim-url-retrieve-sync' 返回的 google buffer."
diff --git a/pyim-codes.el b/pyim-codes.el
index a7476b3bff..2f59429411 100644
--- a/pyim-codes.el
+++ b/pyim-codes.el
@@ -32,25 +32,23 @@
 (require 'pyim-imobjs)
 (require 'pyim-dcache)
 
-(defun pyim-codes-create (imobj scheme-name &optional first-n)
-  "按照 SCHEME-NAME 对应的输入法方案,从一个 IMOBJ 创建一个列表 codes, 这个列表
-包含一个或者多个 code 字符串,这些 code 字符串用于从词库中搜索词条."
-  (let ((class (pyim-scheme-get-option scheme-name :class)))
-    (when class
-      (funcall (intern (format "pyim-codes-create:%S" class))
-               imobj scheme-name first-n))))
-
-(defun pyim-codes-create:quanpin (imobj _scheme-name &optional first-n)
+(cl-defgeneric pyim-codes-create (imobj scheme &optional first-n)
+  "按照 SCHEME 对应的输入法方案,从一个 IMOBJ 创建一个列表 codes.
+
+这个列表包含一个或者多个 code 字符串,这些 code 字符串用于从词库
+中搜索词条.")
+
+(cl-defmethod pyim-codes-create (imobj (_scheme pyim-scheme-quanpin) &optional 
first-n)
   "从IMOBJ 创建一个 code 列表:codes.
 
 列表 codes 中包含一个或者多个 code 字符串,这些 code 字符串用于从
 词库中搜索相关词条。
 
-    (pyim-codes-create '((\"w\" \"o\" \"w\" \"o\")
-                         (\"\" \"ai\" \"\" \"ai\")
-                         (\"m\" \"ei\" \"m\" \"ei\")
-                         (\"n\"  \"v\" \"n\"  \"v\"))
-                       'quanpin)
+    (pyim-codes-create (quote ((\"w\" \"o\" \"w\" \"o\")
+                               (\"\" \"ai\" \"\" \"ai\")
+                               (\"m\" \"ei\" \"m\" \"ei\")
+                               (\"n\"  \"v\" \"n\"  \"v\")))
+                       (pyim-scheme-get (quote quanpin)))
 
 结果为:
 
@@ -64,12 +62,10 @@
          py)))
    imobj))
 
-(defun pyim-codes-create:shuangpin (imobj _scheme-name &optional first-n)
-  (pyim-codes-create:quanpin imobj 'quanpin first-n))
-
-(defun pyim-codes-create:xingma (imobj scheme-name &optional first-n)
-  (when scheme-name
-    (let ((code-prefix (pyim-scheme-get-option scheme-name :code-prefix)))
+(cl-defmethod pyim-codes-create (imobj (scheme pyim-scheme-xingma) &optional 
first-n)
+  "用于处理形码输入法的 `pyim-codes-create' 方法。"
+  (when scheme
+    (let ((code-prefix (pyim-scheme-common-code-prefix scheme)))
       (mapcar
        (lambda (x)
          (concat (or code-prefix "")
diff --git a/pyim-cregexp.el b/pyim-cregexp.el
index 540f2ca513..7ecab6a6a4 100644
--- a/pyim-cregexp.el
+++ b/pyim-cregexp.el
@@ -111,9 +111,8 @@ regexp, 所以搜索单字的时候一般可以搜到生僻字,但搜索句子
 
 (defun pyim-cregexp-build-1 (str &optional char-level-num chinese-only)
   (let* ((num (pyim-cregexp-char-level-num char-level-num))
-         (scheme-name (pyim-scheme-name))
-         (class (pyim-scheme-get-option scheme-name :class))
-         (code-prefix (pyim-scheme-get-option scheme-name :code-prefix))
+         (scheme (pyim-scheme-current))
+         (code-prefix (pyim-scheme-common-code-prefix scheme))
          (sep "#####&&&&#####")
          (lst (remove "" (split-string
                           (replace-regexp-in-string
@@ -121,22 +120,23 @@ regexp, 所以搜索单字的时候一般可以搜到生僻字,但搜索句子
                           sep))))
     ;; 确保 pyim 词库加载
     (pyim-dcache-init-variables)
-    ;; pyim 暂时只支持全拼和双拼搜索
-    (when (not (member class '(quanpin shuangpin xingma)))
-      (setq scheme-name pyim-cregexp-fallback-scheme))
+    (unless (or (pyim-scheme-quanpin-p scheme)
+                (pyim-scheme-shuangpin-p scheme)
+                (pyim-scheme-xingma-p scheme))
+      (setq scheme (pyim-scheme-get pyim-cregexp-fallback-scheme)))
     (mapconcat
      (lambda (string)
        (if (or (pyim-string-match-p "[^a-z']+" string)
                (equal string ""))
            string
          (let* ((string1 (replace-regexp-in-string "'" "" string))
-                (imobjs (pyim-imobjs-create string1 scheme-name))
+                (imobjs (pyim-imobjs-create string1 scheme))
                 (regexp-list
                  (mapcar
                   (lambda (imobj)
-                    (if (eq class 'xingma)
-                        (pyim-cregexp-build:xingma imobj nil nil nil 
code-prefix)
-                      (pyim-cregexp-build:quanpin imobj nil nil nil num)))
+                    (if (pyim-scheme-xingma-p scheme)
+                        (pyim-cregexp-build-xingma imobj nil nil nil 
code-prefix)
+                      (pyim-cregexp-build-quanpin imobj nil nil nil num)))
                   imobjs))
                 (regexp
                  (when regexp-list
@@ -152,7 +152,7 @@ regexp, 所以搜索单字的时候一般可以搜到生僻字,但搜索句子
            (format "\\(?:%s\\)" regexp))))
      lst "")))
 
-(defun pyim-cregexp-build:quanpin (imobj &optional match-beginning
+(defun pyim-cregexp-build-quanpin (imobj &optional match-beginning
                                          first-equal all-equal char-level-num)
   "从 IMOBJ 创建一个搜索中文的 regexp."
   (let* ((num (pyim-cregexp-char-level-num char-level-num))
@@ -184,7 +184,7 @@ regexp, 所以搜索单字的时候一般可以搜到生僻字,但搜索句子
     (unless (equal regexp "")
       (concat (if match-beginning "^" "") regexp))))
 
-(defun pyim-cregexp-build:xingma (imobj &optional match-beginning
+(defun pyim-cregexp-build-xingma (imobj &optional match-beginning
                                         first-equal _all-equal code-prefix)
   "从 IMOBJ 创建一个搜索中文的 regexp."
   (cl-flet ((build-regexp
@@ -209,7 +209,7 @@ regexp, 所以搜索单字的时候一般可以搜到生僻字,但搜索句子
                                          (if first-equal
                                              (substring x 0 1)
                                            x))))
-                       (build-regexp (pyim-dcache-get code))))
+                       (build-regexp (pyim-dcache-get code '(code2word)))))
                    imobj "")))
       (unless (equal regexp "")
         (concat (if match-beginning "^" "") regexp)))))
diff --git a/pyim-cstring.el b/pyim-cstring.el
index a392c58aa7..92801c5cbb 100644
--- a/pyim-cstring.el
+++ b/pyim-cstring.el
@@ -112,7 +112,7 @@ ADJUST-DUO-YIN-Zi 设置为 t 时, `pyim-cstring-to-pinyin' 会使用 
pyim 已
 2. 多音字校正速度比较慢,实时转换会产生卡顿。
 
 BUG: 当 STRING 中包含其它标点符号,并且设置 SEPERATER 时,结果会
-包含多余的连接符:比如: '你=好' --> 'ni-=-hao'"
+包含多余的连接符:比如: \"你=好\" --> \"ni-=-hao\""
   (if (not (pyim-string-match-p "\\cc" string))
       (if return-list
           (list string)
@@ -167,85 +167,103 @@ BUG: 当 STRING 中包含其它标点符号,并且设置 SEPERATER 时,结
   (pyim-cstring-to-pinyin string shou-zi-mu separator return-list t))
 
 ;; ** 中文字符串到形码的转换工具
-(defun pyim-cstring-to-xingma (string scheme-name &optional return-list)
-  "返回汉字 STRING 对应形码方案 SCHEME-NAME 的 code (不包括
-code-prefix)。当RETURN-LIST 设置为 t 时,返回一个 code list。"
+(cl-defgeneric pyim-cstring-to-xingma (string scheme &optional return-list)
+  "将中文 STRING 转换为 SCHEME 方案对应的形码。")
+
+(cl-defmethod pyim-cstring-to-xingma (string (scheme pyim-scheme-xingma)
+                                             &optional return-list)
+  "将中文 STRING 转换为 SCHEME 方案对应的形码。
+
+返回的形码不包括 code-prefix。当 RETURN-LIST 设置为 t 时,返回一
+个形码 list。"
   (when (string-match-p "^\\cc+\\'" string)
-    (let* ((prefix (pyim-scheme-get-option scheme-name :code-prefix))
-           (func (intern (concat "pyim-cstring-to-xingma:" (symbol-name 
scheme-name))))
-           (dcache-codes (mapcar (lambda (x)
-                                   (when (string-prefix-p prefix x)
-                                     (string-remove-prefix prefix x)))
-                                 (sort (cl-copy-list (pyim-dcache-call-api 
'search-word-code string))
-                                       (lambda (a b) (> (length a) (length 
b))))))
-           (codes (or (remove nil dcache-codes)
-                      (and (functionp func)
-                           (funcall func string scheme-name)))))
+    (let* ((prefix (pyim-scheme-common-code-prefix scheme))
+           (dcache-codes
+            (mapcar (lambda (x)
+                      (when (string-prefix-p prefix x)
+                        (string-remove-prefix prefix x)))
+                    (sort (cl-copy-list (pyim-dcache-call-api 
'search-word-code string))
+                          (lambda (a b)
+                            (> (length a) (length b))))))
+           (codes (remove nil dcache-codes)))
       (when codes
         (if return-list
             codes
           ;; 如果要返回一个字符串,那就返回第一个,也就是最长的那个编码。
           (car codes))))))
 
-(defun pyim-cstring-to-xingma:wubi (string &optional scheme-name)
-  "返回汉字 STRING 的五笔编码 (不包括 code-prefix) 编码列表。"
-  (let ((length (length string))
-        (string (split-string string "" t)))
-    (cond
-     ;; 双字词,分别取两个字的前两个编码
-     ((eq length 2)
-      (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme-name))
-            (s2 (pyim-cstring-to-xingma (nth 1 string) scheme-name)))
-        (when (and s1 s2)
-          (list (concat (substring s1 0 2)
-                        (substring s2 0 2))))))
-     ;; 三字词,取前二字的首编码,及第三个字的前两个编码
-     ((eq length 3)
-      (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme-name))
-            (s2 (pyim-cstring-to-xingma (nth 1 string) scheme-name))
-            (s3 (pyim-cstring-to-xingma (nth 2 string) scheme-name)))
-        (when (and s1 s2 s3)
-          (list (concat (substring s1 0 1)
-                        (substring s2 0 1)
-                        (substring s3 0 2))))))
-     ;; 四字词及以上,分别前三个字及最后一个字的首编码
-     ((> length 3)
-      (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme-name))
-            (s2 (pyim-cstring-to-xingma (nth 1 string) scheme-name))
-            (s3 (pyim-cstring-to-xingma (nth 2 string) scheme-name))
-            (s4 (pyim-cstring-to-xingma (nth (1- length) string) scheme-name)))
-        (when (and s1 s2 s3 s4)
-          (list (concat (substring s1 0 1)
-                        (substring s2 0 1)
-                        (substring s3 0 1)
-                        (substring s4 0 1))))))
-     (t nil))))
-
-(defun pyim-cstring-to-codes (string scheme-name &optional criteria)
-  "将 STRING 转换为 SCHEME-NAME 对应的 codes.
-
-当 pyim class 为拼音,并且提供 CRITERIA 字符串时,检索到的所有
-codes 会和这个字符串进行比较,然后选择一个相似度最高的 code 作为
-输出,这种处理方式适合拼音输入法,形码输入法一般不需要类似的操作。
+(cl-defmethod pyim-cstring-to-xingma (string (scheme pyim-scheme-wubi)
+                                             &optional return-list)
+  "将中文 STRING 转换为五笔编码。
+
+得到的五笔编码包括 code-prefix。当 RETURN-LIST 设置为 t 时,返回
+一个五笔编码 list。"
+  (or (cl-call-next-method)
+      (let ((length (length string))
+            (string (split-string string "" t))
+            code)
+        (cond
+         ;; 双字词,分别取两个字的前两个编码
+         ((eq length 2)
+          (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme))
+                (s2 (pyim-cstring-to-xingma (nth 1 string) scheme)))
+            (when (and s1 s2)
+              (setq code (concat (substring s1 0 2)
+                                 (substring s2 0 2))))))
+         ;; 三字词,取前二字的首编码,及第三个字的前两个编码
+         ((eq length 3)
+          (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme))
+                (s2 (pyim-cstring-to-xingma (nth 1 string) scheme))
+                (s3 (pyim-cstring-to-xingma (nth 2 string) scheme)))
+            (when (and s1 s2 s3)
+              (setq code (concat (substring s1 0 1)
+                                 (substring s2 0 1)
+                                 (substring s3 0 2))))))
+         ;; 四字词及以上,分别前三个字及最后一个字的首编码
+         ((> length 3)
+          (let ((s1 (pyim-cstring-to-xingma (nth 0 string) scheme))
+                (s2 (pyim-cstring-to-xingma (nth 1 string) scheme))
+                (s3 (pyim-cstring-to-xingma (nth 2 string) scheme))
+                (s4 (pyim-cstring-to-xingma (nth (1- length) string) scheme)))
+            (when (and s1 s2 s3 s4)
+              (setq code (concat (substring s1 0 1)
+                                 (substring s2 0 1)
+                                 (substring s3 0 1)
+                                 (substring s4 0 1))))))
+         (t nil))
+        (when code
+          (if return-list
+              (list code)
+            code)))))
+
+(cl-defgeneric pyim-cstring-to-codes (string scheme &optional criteria)
+  "将 STRING 转换为 SCHEME 对应的 codes.")
+
+(cl-defmethod pyim-cstring-to-codes (string (scheme pyim-scheme-xingma) 
&optional _)
+  "将中文字符串 STRING 转换为对应的形码."
+  (pyim-cstring-to-xingma string scheme t))
+
+(cl-defmethod pyim-cstring-to-codes (string (_scheme pyim-scheme-quanpin) 
&optional criteria)
+  "将中文字符串 STRING 转换为对应的拼音。
+
+如果用户提供 CRITERIA 字符串,那么检索到的所有 codes 会和这个字符
+串进行字符串相似度比较,然后选择一个相似度最高的 code 作为输出,
+这种处理方式适合拼音输入法,形码输入法一般不需要类似的操作。
 
 CRITERIA 字符串一般是通过 imobjs 构建的,它保留了用户原始的输入信
 息。"
-  (let ((class (pyim-scheme-get-option scheme-name :class)))
-    (cond ((eq class 'xingma)
-           (pyim-cstring-to-xingma string scheme-name t))
-          ;;拼音使用了多音字校正
-          (t (let ((codes (pyim-cstring-to-pinyin string nil "-" t nil t))
-                   codes-sorted)
-               (if (< (length criteria) 1)
-                   codes
-                 ;; 将 所有 codes 与 criteria 字符串比对,选取相似度最高的一个
-                 ;; code. 这种处理方式适合拼音输入法。
-                 (setq codes-sorted
-                       (sort codes
-                             (lambda (a b)
-                               (< (pyim-string-distance a criteria)
-                                  (pyim-string-distance b criteria)))))
-                 (list (car codes-sorted))))))))
+  (let ((codes (pyim-cstring-to-pinyin string nil "-" t nil t))
+        codes-sorted)
+    (if (< (length criteria) 1)
+        codes
+      ;; 将 所有 codes 与 criteria 字符串比对,选取相似度最高的一个
+      ;; code. 这种处理方式适合拼音输入法。
+      (setq codes-sorted
+            (sort codes
+                  (lambda (a b)
+                    (< (pyim-string-distance a criteria)
+                       (pyim-string-distance b criteria)))))
+      (list (car codes-sorted)))))
 
 ;; PYIM 重构以前使用的一些函数名称,alias 一下,便于兼容。
 (defalias 'pyim-hanzi2pinyin-simple 'pyim-cstring-to-pinyin-simple)
diff --git a/pyim-imobjs.el b/pyim-imobjs.el
index f606e67bae..d22fbf1adc 100644
--- a/pyim-imobjs.el
+++ b/pyim-imobjs.el
@@ -81,21 +81,17 @@ imobj 组合构成在一起,构成了 imobjs 这个概念。比如:
 
 (pyim-register-local-variables '(pyim-imobjs))
 
-(defun pyim-imobjs-create (entered &optional scheme-name)
-  "按照 SCHEME-NAME 对应的输入法方案,从 ENTERED 字符串中创建一个
-或者多个 imobj 组成的列表,不同的输入法,imobj 的结构也是不一样的。"
-  (let ((class (pyim-scheme-get-option scheme-name :class)))
-    (when class
-      (funcall (intern (format "pyim-imobjs-create:%S" class))
-               entered scheme-name))))
-
-(defun pyim-imobjs-create:quanpin (entered &optional _)
+(cl-defgeneric pyim-imobjs-create (entered scheme)
+  "按照 SCHEME 对应的输入法方案,从 ENTERED 字符串中创建一个
+或者多个 imobj 组成的列表,不同的输入法,imobj 的结构也是不一样的。")
+
+(cl-defmethod pyim-imobjs-create (entered (scheme pyim-scheme-quanpin))
   "从用户输入的字符串 ENTERED 创建一个输入法内部对象列表: imobjs.
 
 这个 imobjs 可能包含一个 imobj, 也可能包含多个,每个 imobj 都包含
 声母和韵母的相关信息,比如:
 
-    (pyim-imobjs-create:quanpin \"woaimeinv\" 'quanpin)
+    (pyim-imobjs-create \"woaimeinv\" (pyim-scheme-get (quote quanpin)))
 
 结果为:
 
@@ -106,7 +102,7 @@ imobj 组合构成在一起,构成了 imobjs 这个概念。比如:
 
 如果字符串无法正确处理,则返回 nil, 比如:
 
-   (pyim-imobjs-create \"ua\" 'quanpin)
+   (pyim-imobjs-create \"ua\" (pyim-scheme-get (quote quanpin)))
 
 全拼输入法的 imelem 是四个字符串组成的 list, 类似:
 
@@ -141,11 +137,11 @@ imobj 组合构成在一起,构成了 imobjs 这个概念。比如:
                     (concat "'" (nth 2 (car x)))))
             (setq output (append output x)))))
       (when output
-        (pyim-imobjs-find-fuzzy:quanpin (list output))))))
+        (pyim-imobjs-find-fuzzy (list output) scheme)))))
 
 ;; "nihc" -> (((\"n\" \"i\" \"n\" \"i\") (\"h\" \"ao\" \"h\" \"c\")))
-(defun pyim-imobjs-create:shuangpin (entered &optional scheme-name)
-  (let ((keymaps (pyim-scheme-get-option scheme-name :keymaps))
+(cl-defmethod pyim-imobjs-create (entered (scheme pyim-scheme-shuangpin))
+  (let ((keymaps (pyim-scheme-shuangpin-keymaps scheme))
         (list (string-to-list (replace-regexp-in-string "-" "" entered)))
         results)
     (while list
@@ -167,11 +163,10 @@ imobj 组合构成在一起,构成了 imobjs 这个概念。比如:
 
         (when (and one-word-pinyins (> (length one-word-pinyins) 0))
           (push one-word-pinyins results))))
-    (pyim-imobjs-find-fuzzy:quanpin
-     (pyim-permutate-list (nreverse results)))))
+    (pyim-imobjs-find-fuzzy (pyim-permutate-list (nreverse results)) scheme)))
 
-(defun pyim-imobjs-create:xingma (entered &optional scheme-name)
-  (let ((n (pyim-scheme-get-option scheme-name :code-split-length)))
+(cl-defmethod pyim-imobjs-create (entered (scheme pyim-scheme-xingma))
+  (let ((n (pyim-scheme-xingma-code-split-length scheme)))
     (let (output)
       (mapc (lambda (x)
               (while (not (string-empty-p x))
@@ -184,7 +179,10 @@ imobj 组合构成在一起,构成了 imobjs 这个概念。比如:
             (split-string entered "'"))
       (list (nreverse output)))))
 
-(defun pyim-imobjs-find-fuzzy:quanpin (imobjs)
+(cl-defgeneric pyim-imobjs-find-fuzzy (imobjs scheme)
+  "用于处理模糊音的函数。")
+
+(cl-defmethod pyim-imobjs-find-fuzzy (imobjs (_scheme pyim-scheme-quanpin))
   "用于处理模糊音的函数。"
   (let (fuzzy-imobjs result1 result2)
     (dolist (imobj imobjs)
diff --git a/pyim-liberime.el b/pyim-liberime.el
index b7167796a8..cb20312df9 100644
--- a/pyim-liberime.el
+++ b/pyim-liberime.el
@@ -46,6 +46,15 @@
 (require 'pyim)
 (require 'liberime nil t)
 
+(cl-defstruct (pyim-scheme-rime
+               (:include pyim-scheme-common)
+               (:constructor pyim-scheme-rime-create)
+               (:copier nil))
+  "Rime 输入法方案。"
+  code-prefix-history
+  code-split-length
+  code-maximum-length)
+
 (pyim-scheme-add
  '(rime
    :document
@@ -94,28 +103,35 @@
 (declare-function liberime-process-key "liberime" (keycode &optional mask))
 (declare-function liberime-select-candidate "liberime" (num))
 
-(defun pyim-liberime-scheme-name (orig_func &optional default)
-  "Advice function of `pyim-scheme-name'."
-  (let* ((scheme-name (funcall orig_func default))
-         (class (pyim-scheme-get-option scheme-name :class)))
-    (if (eq class 'rime)
+(defun pyim-liberime-scheme (orig_func &optional default)
+  "Advice function of `pyim-scheme-current'."
+  (let* ((scheme (funcall orig_func default)))
+    (if (pyim-scheme-rime-p scheme)
         (if (featurep 'liberime-core)
-            scheme-name
-          'quanpin)
-      scheme-name)))
+            scheme
+          (pyim-scheme-get 'quanpin))
+      scheme)))
 
-(advice-add 'pyim-scheme-name :around #'pyim-liberime-scheme-name)
+(advice-add 'pyim-scheme-current :around #'pyim-liberime-scheme)
 
-(defun pyim-imobjs-create:rime (entered &optional _)
+(cl-defmethod pyim-imobjs-create (entered (_scheme pyim-scheme-rime))
   (list (list entered)))
 
-(defun pyim-codes-create:rime (imobj scheme-name &optional first-n)
-  (pyim-codes-create:xingma imobj scheme-name first-n))
-
-(defun pyim-candidates-create:rime (imobjs scheme-name &optional async)
+(cl-defmethod pyim-codes-create (imobj (scheme pyim-scheme-rime) &optional 
first-n)
+  (when scheme
+    (let ((code-prefix (pyim-scheme-common-code-prefix scheme)))
+      (mapcar
+       (lambda (x)
+         (concat (or code-prefix "")
+                 (if (numberp first-n)
+                     (substring x 0 (min first-n (length x)))
+                   x)))
+       imobj))))
+
+(cl-defmethod pyim-candidates-create (imobjs (scheme pyim-scheme-rime) 
&optional async)
   "`pyim-candidates-create' 处理 rime 输入法的函数."
-  (let* ((code (car (pyim-codes-create (car imobjs) scheme-name)))
-         (code-prefix (pyim-scheme-get-option scheme-name :code-prefix))
+  (let* ((code (car (pyim-codes-create (car imobjs) scheme)))
+         (code-prefix (pyim-scheme-common-code-prefix scheme))
          (s (replace-regexp-in-string "-" "" code))
          ;; `liberime-search' 搜索的时候不需要 code-prefix, 去除。
          (s (if code-prefix
@@ -126,20 +142,19 @@
                                      (* pyim-page-length 2)))))
     words))
 
-(defun pyim-page-preview-create:rime (&optional separator)
+(cl-defmethod pyim-page-preview-create ((_scheme pyim-scheme-rime) &optional 
separator)
   (let* ((preedit (or (liberime-get-preedit)
                       (pyim-entered-get 'point-before))))
     (pyim-process-with-entered-buffer
-     (if (equal 1 (point))
-         (concat "|" preedit)
-       (concat (replace-regexp-in-string (concat separator "'") "'" preedit)
-               " |" (buffer-substring-no-properties (point) (point-max)))))))
+      (if (equal 1 (point))
+          (concat "|" preedit)
+        (concat (replace-regexp-in-string (concat separator "'") "'" preedit)
+                " |" (buffer-substring-no-properties (point) (point-max)))))))
 
 (defvar pyim-liberime-code-log nil)
 (defvar pyim-liberime-word-log nil)
-(defun pyim-select-word:rime ()
+(cl-defmethod pyim-select-word-really ((_scheme pyim-scheme-rime))
   "从选词框中选择当前词条,然后删除该词条对应拼音。"
-  (interactive)
   (pyim-process-outcome-handle 'candidate)
   (let* ((entered (pyim-entered-get 'point-before))
          (word (string-remove-prefix
@@ -174,9 +189,8 @@
 
 (defun pyim-autoselector-rime (&rest _args)
   "适用于RIME的自动上屏器."
-  (let* ((scheme-name (pyim-scheme-name))
-         (class (pyim-scheme-get-option scheme-name :class)))
-    (when (eq class 'rime)
+  (let* ((scheme (pyim-scheme-current)))
+    (when (pyim-scheme-rime-p scheme)
       (let* ((commit (liberime-get-commit))
              (context (liberime-get-context))
              (composition (alist-get 'composition context))
@@ -270,7 +284,7 @@ Please see: https://github.com/rime/librime/issues/349";
    ;; 找不到通用的处理方式的话就不做截取处理。
    (t input)))
 
-(defun pyim-process-terminate:rime ()
+(cl-defmethod pyim-process-terminate-really :after ((_scheme pyim-scheme-rime))
   (liberime-clear-commit)
   (liberime-clear-composition))
 
diff --git a/pyim-outcome.el b/pyim-outcome.el
index 55963409d9..d30434f439 100644
--- a/pyim-outcome.el
+++ b/pyim-outcome.el
@@ -165,16 +165,9 @@ pyim 的 translate-trigger-char 要占用一个键位,为了防止用户
               (char-to-string user-trigger)
             (when (= (length user-trigger) 1)
               user-trigger)))
-         (first-char (pyim-scheme-get-option
-                      (pyim-scheme-name)
-                      :first-chars))
-         (prefer-triggers (or (pyim-scheme-get-option
-                               (pyim-scheme-name)
-                               :prefer-triggers)
-                              ;; 向后兼容
-                              (list (pyim-scheme-get-option
-                                     (pyim-scheme-name)
-                                     :prefer-trigger-chars)))))
+         (first-char (pyim-scheme-common-first-chars (pyim-scheme-current)))
+         (prefer-triggers (pyim-scheme-common-prefer-triggers
+                           (pyim-scheme-current))))
     (if (pyim-string-match-p (regexp-quote user-trigger) first-char)
         (progn
           ;; (message "注意:pyim-outcome-trigger 设置和当前输入法冲突,使用推荐设置:\"%s\""
diff --git a/pyim-page.el b/pyim-page.el
index 923dfd2d6b..289dce6bba 100644
--- a/pyim-page.el
+++ b/pyim-page.el
@@ -219,17 +219,21 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
                       (length candidates))
                  start))
          (page-info (make-hash-table))
-         (tooltip (pyim-page-get-valid-tooltip)))
+         (tooltip (pyim-page-get-valid-tooltip))
+         (style (or (cdr (assoc tooltip pyim-page-tooltip-style-alist))
+                    pyim-page-style)))
+    (puthash :scheme (pyim-scheme-current) page-info)
     (puthash :current-page (pyim-page-current-page) page-info)
     (puthash :total-page (pyim-page-total-page) page-info)
     (puthash :candidates candidate-showed page-info)
     (puthash :position pos page-info)
     (puthash :hightlight-current hightlight-current page-info)
+    (puthash :assistant-enable pyim-assistant-scheme-enable page-info)
     ;; Show page.
     (when (and (null unread-command-events)
                (null unread-post-input-method-events))
       (pyim-page-show
-       (pyim-page-info-format page-info tooltip)
+       (pyim-page-info-format style page-info)
        (funcall pyim-process-ui-position-function)
        tooltip))))
 
@@ -274,17 +278,13 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
   (interactive "p")
   (pyim-page-next-word (- arg)))
 
-(defun pyim-page-preview-create (&optional separator)
+(cl-defgeneric pyim-page-preview-create (scheme &optional separator)
   "这个函数用于创建在 page 中显示的预览字符串。
 
 这个预览是在 page 中显示,而 `pyim-preview-refresh' 对应的预览
-是在 buffer 光标处显示,两者要做区别。"
-  (let* ((scheme-name (pyim-scheme-name))
-         (class (pyim-scheme-get-option scheme-name :class)))
-    (when class
-      (funcall (intern (format "pyim-page-preview-create:%S" class)) 
separator))))
+是在 buffer 光标处显示,两者要做区别。")
 
-(defun pyim-page-preview-create:quanpin (&optional separator)
+(cl-defmethod pyim-page-preview-create ((_scheme pyim-scheme-quanpin) 
&optional separator)
   (let* ((separator (or separator " "))
          (translated (string-join (mapcar (lambda (w)
                                             (concat (nth 0 w) (nth 1 w)))
@@ -296,20 +296,10 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
        (if (equal 1 (point))
            (concat "|" translated)
          (concat (replace-regexp-in-string (concat separator "'") "'" 
translated)
-                 " |" (buffer-substring-no-properties (point) (point-max)))))
-     ;; 用于标记辅助输入法
-     (when (and (eq pyim-assistant-scheme 'quanpin)
-                (eq pyim-assistant-scheme-enable t))
-       (let ((code (pyim-cstring-to-xingma
-                    (nth (1- (pyim-process-get-candidate-position))
-                         (pyim-process-get-candidates))
-                    (pyim-scheme-name 'default))))
-         (if (> (length code) 0)
-             (format " [%s](辅)" code)
-           " (辅)"))))))
-
-(defun pyim-page-preview-create:shuangpin (&optional separator)
-  (let ((keymaps (pyim-scheme-get-option (pyim-scheme-name) :keymaps))
+                 " |" (buffer-substring-no-properties (point) 
(point-max))))))))
+
+(cl-defmethod pyim-page-preview-create ((scheme pyim-scheme-shuangpin) 
&optional separator)
+  (let ((keymaps (pyim-scheme-shuangpin-keymaps scheme))
         result)
     (dolist (w (pyim-process-get-first-imobj))
       (let ((sm (nth 0 w))
@@ -331,7 +321,7 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
            result))))
     (string-join (reverse result) (or separator " "))))
 
-(defun pyim-page-preview-create:xingma (&optional _separator)
+(cl-defmethod pyim-page-preview-create ((_scheme pyim-scheme-xingma) &optional 
_separator)
   ;; | 显示光标位置的字符
   (pyim-process-with-entered-buffer
     (if (equal (point) (point-max))
@@ -364,16 +354,10 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
          result)))
     (string-join (nreverse result) (or separator ""))))
 
-(defun pyim-page-info-format (page-info tooltip)
-  "将 PAGE-INFO 按照 `pyim-page-style' 格式化为选词框中显示的字符串。"
-  (let ((style (or (cdr (assoc tooltip pyim-page-tooltip-style-alist))
-                   pyim-page-style)))
-    (let ((func (intern (format "pyim-page-style:%S" style))))
-      (if (functionp func)
-          (funcall func page-info)
-        (pyim-page-style:two-lines page-info)))))
+(cl-defgeneric pyim-page-info-format (style page-info)
+  "将 PAGE-INFO 按照 STYLE 格式化为选词框中显示的字符串。")
 
-(defun pyim-page-style:two-lines (page-info)
+(cl-defmethod pyim-page-info-format (_style page-info)
   "将 PAGE-INFO 格式化为选词框中显示的字符串.
 
 样式类似:
@@ -382,8 +366,10 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
 | ni hao [1/9]               |
 | 1.你好 2.你号 ...          |
 +----------------------------+"
-  (format "=> %s [%s/%s]: \n%s"
-          (pyim-page-preview-create)
+  (format "=> %s%s [%s/%s]: \n%s"
+          (pyim-page-preview-create
+           (gethash :scheme page-info))
+          (if (gethash :assistant-enable page-info) " (辅)" "")
           (gethash :current-page page-info)
           (gethash :total-page page-info)
           (pyim-page-menu-create
@@ -392,7 +378,7 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
            nil
            (gethash :hightlight-current page-info))))
 
-(defun pyim-page-style:one-line (page-info)
+(cl-defmethod pyim-page-info-format ((_style (eql 'one-line)) page-info)
   "将 PAGE-INFO 格式化为选词框中显示的字符串.
 
 样式类似:
@@ -400,8 +386,10 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
 +-----------------------------------+
 | [ni hao]: 1.你好 2.你号 ... (1/9) |
 +-----------------------------------+"
-  (format "[%s]: %s(%s/%s)"
-          (pyim-page-preview-create " ")
+  (format "[%s%s]: %s(%s/%s)"
+          (pyim-page-preview-create
+           (gethash :scheme page-info) " ")
+          (if (gethash :assistant-enable page-info) " (辅)" "")
           (pyim-page-menu-create
            (gethash :candidates page-info)
            (gethash :position page-info)
@@ -410,7 +398,7 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
           (gethash :current-page page-info)
           (gethash :total-page page-info)))
 
-(defun pyim-page-style:vertical (page-info)
+(cl-defmethod pyim-page-info-format ((_style (eql 'vertical)) page-info)
   "将 PAGE-INFO 格式化为选词框中显示的字符串.
 
 样式类似:
@@ -420,8 +408,10 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
 | 1.你好       |
 | 2.你号 ...   |
 +--------------+"
-  (format "=> %s [%s/%s]: \n%s"
-          (pyim-page-preview-create)
+  (format "=> %s%s [%s/%s]: \n%s"
+          (pyim-page-preview-create
+           (gethash :scheme page-info))
+          (if (gethash :assistant-enable page-info) " (辅)" "")
           (gethash :current-page page-info)
           (gethash :total-page page-info)
           (pyim-page-menu-create
@@ -430,7 +420,7 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
            "\n"
            (gethash :hightlight-current page-info))))
 
-(defun pyim-page-style:minibuffer (page-info)
+(cl-defmethod pyim-page-info-format ((_style (eql 'minibuffer)) page-info)
   "将 PAGE-INFO 格式化为选词框中显示的字符串.
 
 样式类似:
@@ -440,8 +430,10 @@ page 的概念,比如,上面的 “nihao” 的 *待选词列表* 就可以
 +------------------------------------+"
   ;; 在 minibuffer 中显示 page 的时候,page 字符串直接插入到 minibuffer 现有的内
   ;; 容中, 为了便于区分,在 page 后面添加一个显眼的字符。
-  (format "[%-15s]: %s(%s/%s) $ "
-          (pyim-page-preview-create)
+  (format "[%-15s%s]: %s(%s/%s) $ "
+          (pyim-page-preview-create
+           (gethash :scheme page-info))
+          (if (gethash :assistant-enable page-info) " (辅)" "")
           (pyim-page-menu-create
            (gethash :candidates page-info)
            (gethash :position page-info)
diff --git a/pyim-preview.el b/pyim-preview.el
index 823198747a..a2afaa9eea 100644
--- a/pyim-preview.el
+++ b/pyim-preview.el
@@ -76,13 +76,13 @@
 pyim 会使用 Emacs overlay 机制在 *待输入buffer* 光标处高亮显示一
 个预览字符串,让用户可以查看将要输入的字符串,这个函数用于更新这
 个字符串的内容。"
-  (let* ((class (pyim-scheme-get-option (pyim-scheme-name) :class))
+  (let* ((scheme (pyim-scheme-current))
          (candidates (pyim-process-get-candidates))
          (pos (1- (min (pyim-process-get-candidate-position)
                        (length candidates))))
          (preview (concat (pyim-process-get-outcome)
                           (nth pos candidates))))
-    (when (memq class '(quanpin))
+    (when (pyim-scheme-quanpin-p scheme)
       (let ((rest (mapconcat
                    (lambda (py)
                      (concat (nth 0 py) (nth 1 py)))
diff --git a/pyim-process.el b/pyim-process.el
index c807e0aa22..319174ab46 100644
--- a/pyim-process.el
+++ b/pyim-process.el
@@ -189,11 +189,11 @@ entered (nihaom) 的第一个候选词。
 
 如果 SEARCH-FORWARD 为 t, 则向前搜索,反之,向后搜索。"
   (pyim-entered-with-entered-buffer
-    (let* ((scheme-name (pyim-scheme-name))
+    (let* ((scheme (pyim-scheme-current))
            (start (or start (point)))
            (end-position start)
            (string (buffer-substring-no-properties (point-min) start))
-           (orig-imobj-len (length (car (pyim-imobjs-create string 
scheme-name))))
+           (orig-imobj-len (length (car (pyim-imobjs-create string scheme))))
            imobj pos)
       (if search-forward
           ;; "ni|haoshijie" -> "nihao|shijie"
@@ -201,7 +201,7 @@ entered (nihaom) 的第一个候选词。
             (setq pos (point-max))
             (while (and (> pos start) (= end-position start))
               (setq string (buffer-substring-no-properties (point-min) pos)
-                    imobj (car (pyim-imobjs-create string scheme-name)))
+                    imobj (car (pyim-imobjs-create string scheme)))
               (if (>= (+ orig-imobj-len num) (length imobj))
                   (setq end-position pos)
                 (cl-decf pos))))
@@ -211,7 +211,7 @@ entered (nihaom) 的第一个候选词。
           (setq pos start)
           (while (and (>= pos (point-min)) (= end-position start))
             (setq string (buffer-substring-no-properties (point-min) pos)
-                  imobj (car (pyim-imobjs-create string scheme-name)))
+                  imobj (car (pyim-imobjs-create string scheme)))
             (if (= (- orig-imobj-len num) (length imobj))
                 (setq end-position pos)
               (cl-decf pos)))))
@@ -242,9 +242,9 @@ entered (nihaom) 的第一个候选词。
 
 (defun pyim-process-input-chinese-p ()
   "确定 pyim 是否需要启动中文输入模式."
-  (let* ((scheme-name (pyim-scheme-name))
-         (first-chars (pyim-scheme-get-option scheme-name :first-chars))
-         (rest-chars (pyim-scheme-get-option scheme-name :rest-chars)))
+  (let* ((scheme (pyim-scheme-current))
+         (first-chars (pyim-scheme-common-first-chars scheme))
+         (rest-chars (pyim-scheme-common-rest-chars scheme)))
     (and (or (pyim-process-force-input-chinese-p)
              (and (not pyim-process-input-ascii)
                   (not (pyim-process-auto-switch-english-input-p))))
@@ -278,13 +278,13 @@ entered (nihaom) 的第一个候选词。
 
 (defun pyim-process-run-1 ()
   "查询 `pyim-entered-buffer' 光标前的拼音字符串(如果光标在行首则为光标后的), 显示备选词等待用户选择。"
-  (let* ((scheme-name (pyim-scheme-name))
+  (let* ((scheme (pyim-scheme-current))
          entered-to-translate)
     (setq entered-to-translate
           (pyim-entered-get 'point-before))
-    (setq pyim-imobjs (pyim-imobjs-create entered-to-translate scheme-name))
+    (setq pyim-imobjs (pyim-imobjs-create entered-to-translate scheme))
     (setq pyim-candidates
-          (or (delete-dups (pyim-candidates-create pyim-imobjs scheme-name))
+          (or (delete-dups (pyim-candidates-create pyim-imobjs scheme))
               (list entered-to-translate)))
     (pyim-process-run-async-timer-reset)
     ;; 当用户选择词条时,如果停顿超过1秒,就激活异步流程,不同的输入法异步流程定
@@ -361,8 +361,8 @@ entered (nihaom) 的第一个候选词。
 
 (defun pyim-process-run-async ()
   "Function used by `pyim-process-run-async-timer'"
-  (let* ((scheme-name (pyim-scheme-name))
-         (words (delete-dups (pyim-candidates-create pyim-imobjs scheme-name 
t))))
+  (let* ((scheme (pyim-scheme-current))
+         (words (delete-dups (pyim-candidates-create pyim-imobjs scheme t))))
     (when words
       (setq pyim-candidates words)
       (pyim-process-ui-refresh))))
@@ -592,7 +592,7 @@ alist 列表。"
   (setq pyim-process-code-criteria
         (let ((str (string-join
                     (pyim-codes-create (pyim-process-get-first-imobj)
-                                       (pyim-scheme-name)))))
+                                       (pyim-scheme-current)))))
           (if (> (length pyim-process-code-criteria)
                  (length str))
               pyim-process-code-criteria
@@ -629,10 +629,10 @@ BUG:拼音无法有效地处理多音字。"
     ;; 记录最近创建的词条,用于快速删词功能。
     (setq pyim-process-last-created-words
           (cons word (remove word pyim-process-last-created-words)))
-    (let* ((scheme-name (pyim-scheme-name))
-           (code-prefix (pyim-scheme-get-option scheme-name :code-prefix))
+    (let* ((scheme (pyim-scheme-current))
+           (code-prefix (pyim-scheme-common-code-prefix scheme))
            (codes (pyim-cstring-to-codes
-                   word scheme-name
+                   word scheme
                    (or criteria pyim-process-code-criteria))))
       ;; 保存对应词条的词频
       (when (> (length word) 0)
@@ -664,6 +664,12 @@ BUG:拼音无法有效地处理多音字。"
 
 (defun pyim-process-terminate ()
   "Terminate the translation of the current key."
+  (pyim-process-terminate-really (pyim-scheme-current)))
+
+(cl-defgeneric pyim-process-terminate-really (scheme)
+  "Terminate the translation of the current key.")
+
+(cl-defmethod pyim-process-terminate-really (_scheme)
   (setq pyim-process-translating nil)
   (pyim-entered-erase-buffer)
   (setq pyim-process-code-criteria nil)
@@ -671,11 +677,7 @@ BUG:拼音无法有效地处理多音字。"
   (setq pyim-candidates nil)
   (setq pyim-candidates-last nil)
   (pyim-process-run-async-timer-reset)
-  (pyim-process-ui-hide)
-  (let* ((class (pyim-scheme-get-option (pyim-scheme-name) :class))
-         (func (intern (format "pyim-process-terminate:%S" class))))
-    (when (and class (functionp func))
-      (funcall func))))
+  (pyim-process-ui-hide))
 
 (defun pyim-process-ui-hide ()
   "隐藏 pyim 相关 UI."
diff --git a/pyim-scheme.el b/pyim-scheme.el
index da6369ef66..8d9d2f9d6e 100644
--- a/pyim-scheme.el
+++ b/pyim-scheme.el
@@ -53,10 +53,56 @@
 (defvar pyim-schemes nil
   "Pyim 支持的所有拼音方案.")
 
+(cl-defstruct (pyim-scheme-common
+               (:constructor pyim-scheme-common-create)
+               (:copier nil))
+  "输入法方案通用的 slots."
+  class
+  name
+  document
+  first-chars
+  rest-chars
+  code-prefix
+  prefer-triggers)
+
+(cl-defstruct (pyim-scheme-quanpin
+               (:include pyim-scheme-common)
+               (:constructor pyim-scheme-quanpin-create)
+               (:copier nil))
+  "全拼输入法方案类型。")
+
+(cl-defstruct (pyim-scheme-shuangpin
+               (:include pyim-scheme-quanpin)
+               (:constructor pyim-scheme-shuangpin-create)
+               (:copier nil))
+  "双拼输入法方案类型。
+
+在 PYIM 中,双拼输入法是建立在全拼输入法的基础上的,所以将其定义
+为全拼输入法类型的子类型。"
+  keymaps)
+
+(cl-defstruct (pyim-scheme-xingma
+               (:include pyim-scheme-common)
+               (:constructor pyim-scheme-xingma-create)
+               (:copier nil))
+  "形码输入法方案类型。"
+  code-prefix-history
+  code-split-length
+  code-maximum-length)
+
+(cl-defstruct (pyim-scheme-wubi
+               (:include pyim-scheme-xingma)
+               (:constructor pyim-scheme-wubi-create)
+               (:copier nil))
+  "五笔输入法方案类型。
+
+单独创建五笔方案类型,是为了支持五笔反查功能,因为1到4字的中文词
+语, 五笔编码有固定的规则,其它形码没有类似特点。" )
+
 ;;;###autoload
 (defun pyim-default-scheme (&optional scheme-name)
   (interactive)
-  (let* ((scheme-names (mapcar #'car pyim-schemes))
+  (let* ((scheme-names (mapcar #'pyim-scheme-common-name pyim-schemes))
          (scheme-name
           (or scheme-name
               (intern (completing-read "PYIM: 将 pyim-default-scheme 设置为:" 
scheme-names)))))
@@ -68,45 +114,42 @@
       (message "PYIM: %s 不是一个有效的 scheme 名称, 继续使用 %s." scheme-name 
pyim-default-scheme)
       nil)))
 
-(defun pyim-scheme-add (scheme)
+(defun pyim-scheme-add (scheme-config)
   "Add SCHEME to `pyim-schemes'"
-  (if (listp scheme)
-      (let ((scheme-name (car scheme)))
-        (when (symbolp scheme-name)
-          (setq pyim-schemes
-                (remove (assoc scheme-name pyim-schemes)
-                        pyim-schemes)))
-        (push scheme pyim-schemes))
+  (if (listp scheme-config)
+      (let* ((scheme-name (car scheme-config))
+             (scheme-type (plist-get (cdr scheme-config) :class))
+             (func (intern (format "pyim-scheme-%s-create" scheme-type)))
+             (scheme (apply func :name scheme-name (cdr scheme-config)))
+             schemes update-p)
+        (when (and (symbolp scheme-name)
+                   (functionp func))
+          (dolist (x pyim-schemes)
+            (push (if (equal (pyim-scheme-common-name x) scheme-name)
+                      (progn (setq update-p t)
+                             scheme)
+                    x)
+                  schemes))
+          (unless update-p
+            (push scheme schemes))
+          (setq pyim-schemes (reverse schemes))))
     (message "PYIM: Invalid pyim scheme config!")))
 
+(defun pyim-scheme-current ()
+  "获取当前正在使用的 scheme。"
+  (or (pyim-scheme-get
+       (if pyim-assistant-scheme-enable
+           pyim-assistant-scheme
+         pyim-default-scheme))
+      (pyim-scheme-get 'quanpin)))
+
 (defun pyim-scheme-get (scheme-name)
-  "获取名称为 SCHEME-NAME 的输入法方案。"
+  "获取名称为 SCHEME-NAME 的 scheme."
   (when scheme-name
-    (assoc scheme-name pyim-schemes)))
-
-(defun pyim-scheme-name (&optional default)
-  "获取输入法 scheme"
-  (let (scheme-name)
-    (if (and pyim-assistant-scheme-enable
-             (not default))
-        (setq scheme-name
-              (or pyim-assistant-scheme
-                  pyim-default-scheme))
-      (setq scheme-name pyim-default-scheme))
-    (if (assq scheme-name pyim-schemes)
-        scheme-name
-      'quanpin)))
-
-(defun pyim-scheme-get-option (scheme-name option)
-  "获取名称为 SCHEME-NAME 的输入法方案,并提取其属性 OPTION 。"
-  (when scheme-name
-    (let* ((scheme (pyim-scheme-get scheme-name))
-           (scheme-inherit
-            (car (pyim-scheme-get
-                  (plist-get (cdr scheme) :inherit)))))
-      (if (member option (cdr scheme))
-          (plist-get (cdr scheme) option)
-        (pyim-scheme-get-option scheme-inherit option)))))
+    (cl-find-if
+     (lambda (x)
+       (equal (pyim-scheme-common-name x) scheme-name))
+     pyim-schemes)))
 
 (pyim-scheme-add
  '(quanpin
@@ -119,7 +162,7 @@
 (pyim-scheme-add
  '(wubi
    :document "五笔输入法。"
-   :class xingma
+   :class wubi
    :first-chars "abcdefghijklmnopqrstuvwxyz"
    :rest-chars "abcdefghijklmnopqrstuvwxyz'"
    :code-prefix "wubi/" ;五笔词库中所有的 code 都以 "wubi/" 开头,防止和其它词库冲突。
diff --git a/pyim.el b/pyim.el
index 5be5f4c66b..b8bdd19416 100644
--- a/pyim.el
+++ b/pyim.el
@@ -514,15 +514,12 @@ FILE 的格式与 `pyim-dcache-export' 生成的文件格式相同,
       (progn
         (pyim-process-outcome-handle 'last-char)
         (pyim-process-terminate))
-    (let* ((class (pyim-scheme-get-option (pyim-scheme-name) :class))
-           (func (intern (format "pyim-select-word:%S" class))))
-      (if (and class (functionp func))
-          (funcall func)
-        (call-interactively #'pyim-select-word:pinyin)))))
+    (pyim-select-word-really (pyim-scheme-current))))
 
-(defun pyim-select-word:pinyin ()
+(cl-defgeneric pyim-select-word-really (scheme))
+
+(cl-defmethod pyim-select-word-really ((_scheme pyim-scheme-quanpin))
   "从选词框中选择当前词条,然后删除该词条对应拼音。"
-  (interactive)
   (pyim-process-outcome-handle 'candidate)
   (let* ((imobj (pyim-process-get-first-imobj))
          (length-selected-word
@@ -579,9 +576,8 @@ FILE 的格式与 `pyim-dcache-export' 生成的文件格式相同,
       ;; pyim 使用这个 hook 来处理联想词。
       (run-hooks 'pyim-select-finish-hook))))
 
-(defun pyim-select-word:xingma ()
+(cl-defmethod pyim-select-word-really ((_scheme pyim-scheme-xingma))
   "从选词框中选择当前词条,然后删除该词条对应编码。"
-  (interactive)
   (pyim-process-outcome-handle 'candidate)
   (if (pyim-process-with-entered-buffer
         (and (> (point) 1)
@@ -751,9 +747,9 @@ FILE 的格式与 `pyim-dcache-export' 生成的文件格式相同,
   (unless (equal input-method-function 'pyim-input-method)
     (activate-input-method 'pyim))
   (let* ((case-fold-search nil)
-         (scheme-name (pyim-scheme-name))
-         (first-chars (pyim-scheme-get-option scheme-name :first-chars))
-         (rest-chars (pyim-scheme-get-option scheme-name :rest-chars))
+         (scheme (pyim-scheme-current))
+         (first-chars (pyim-scheme-common-first-chars scheme))
+         (rest-chars (pyim-scheme-common-rest-chars scheme))
          (string (if mark-active
                      (buffer-substring-no-properties
                       (region-beginning) (region-end))
diff --git a/tests/pyim-tests.el b/tests/pyim-tests.el
index 82ed76af8b..d80cd76078 100644
--- a/tests/pyim-tests.el
+++ b/tests/pyim-tests.el
@@ -59,23 +59,69 @@
 ;; ** pyim-schemes 相关单元测试
 (ert-deftest pyim-tests-pyim-schemes ()
   (let ((pyim-default-scheme 'wubi))
-    (should (equal (pyim-scheme-name) 'wubi)))
+    (should (equal (pyim-scheme-common-name
+                    (pyim-scheme-current))
+                   'wubi)))
 
   (let ((pyim-default-scheme 'wuci))
-    (should (equal (pyim-scheme-name) 'quanpin)))
+    (should (equal (pyim-scheme-common-name
+                    (pyim-scheme-current))
+                   'quanpin)))
 
   (let ((pyim-default-scheme 'wubi)
         (pyim-assistant-scheme 'cangjie)
         (pyim-assistant-scheme-enable t))
-    (should (equal (pyim-scheme-name) 'cangjie)))
+    (should (equal (pyim-scheme-common-name
+                    (pyim-scheme-current))
+                   'cangjie)))
 
   (let ((pyim-default-scheme 'wubi)
         (pyim-assistant-scheme 'cangjie)
         (pyim-assistant-scheme-enable nil))
-    (should (equal (pyim-scheme-name) 'wubi)))
-
-  (should (equal (pyim-scheme-get-option 'quanpin :class) 'quanpin))
-  (should (equal (pyim-scheme-get-option 'wubi :class) 'xingma)))
+    (should (equal (pyim-scheme-common-name
+                    (pyim-scheme-current))
+                   'wubi)))
+
+  (should (equal (pyim-scheme-common-name
+                  (pyim-scheme-get 'quanpin))
+                 'quanpin))
+
+  (should-not (pyim-scheme-get 'quanpin1))
+
+  (should (equal (pyim-scheme-common-name
+                  (pyim-scheme-get 'wubi))
+                 'wubi)))
+
+(ert-deftest pyim-tests-pyim-scheme-add ()
+  (let ((pyim-schemes nil))
+    (pyim-scheme-add
+     '(quanpin
+       :document "test1"
+       :class quanpin
+       :first-chars "abcdefghijklmnopqrstuwxyz"
+       :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a"
+       :prefer-triggers ("v")))
+
+    (pyim-scheme-add
+     '(quanpin
+       :document "test2"
+       :class quanpin
+       :first-chars "abcdefghijklmnopqrstuwxyz"
+       :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a"
+       :prefer-triggers ("v")))
+
+    (pyim-scheme-add
+     '(quanpin1
+       :document "test3"
+       :class quanpin
+       :first-chars "abcdefghijklmnopqrstuwxyz"
+       :rest-chars "vmpfwckzyjqdltxuognbhsrei'-a"
+       :prefer-triggers ("v")))
+
+    (pyim-scheme-add "error")
+
+    (should (equal (mapcar #'pyim-scheme-common-document pyim-schemes)
+                   '("test2" "test3")))))
 
 ;; ** pyim-common 相关单元测试
 (ert-deftest pyim-tests-pyim-char-before/after-to-string ()
@@ -351,49 +397,57 @@
 (ert-deftest pyim-tests-pyim-imobjs ()
   (let ((pyim-pinyin-fuzzy-alist '(("en" "eng")
                                    ("in" "ing")
-                                   ("un" "ong"))))
-    (should (equal (pyim-imobjs-create "nihao" 'quanpin)
+                                   ("un" "ong")))
+        (quanpin (pyim-scheme-get 'quanpin))
+        (wubi (pyim-scheme-get 'wubi))
+        (cangjie (pyim-scheme-get 'cangjie))
+        (pyim-shuangpin (pyim-scheme-get 'pyim-shuangpin)))
+    (should (equal (pyim-imobjs-create "nihao" quanpin)
                    '((("n" "i" "n" "i") ("h" "ao" "h" "ao")))))
-    (should (equal (pyim-imobjs-create "nh" 'quanpin)
+    (should (equal (pyim-imobjs-create "nh" quanpin)
                    '((("n" "" "n" "") ("h" nil "h" nil)))))
-    (should (equal (pyim-imobjs-create "xi'an" 'quanpin)
+    (should (equal (pyim-imobjs-create "xi'an" quanpin)
                    '((("x" "i" "x" "i") ("'" "an" "'" "an")))))
-    (should (equal (pyim-imobjs-create "xian" 'quanpin)
+    (should (equal (pyim-imobjs-create "xian" quanpin)
                    '((("x" "ian" "x" "ian")))))
-    (should (equal (pyim-imobjs-create "fenyun" 'quanpin)
+    (should (equal (pyim-imobjs-create "fenyun" quanpin)
                    '((("f" "en" "f" "en") ("y" "un" "y" "un"))
                      (("f" "en" "f" "en") ("y" "ong" "y" "un"))
                      (("f" "eng" "f" "en") ("y" "un" "y" "un"))
                      (("f" "eng" "f" "en") ("y" "ong" "y" "un")))))
-    (should (equal (pyim-imobjs-create "xian" 'wubi)
+    (should (equal (pyim-imobjs-create "xian" wubi)
                    '(("xian"))))
-    (should (equal (pyim-imobjs-create "xian" 'cangjie)
+    (should (equal (pyim-imobjs-create "xian" cangjie)
                    '(("xian"))))
-    (should (equal (pyim-imobjs-create "nihc" 'pyim-shuangpin)
+    (should (equal (pyim-imobjs-create "nihc" pyim-shuangpin)
                    '((("n" "i" "n" "i") ("h" "ao" "h" "c")))))))
 
 ;; ** pyim-codes 相关单元测试
 (ert-deftest pyim-tests-pyim-codes ()
-  (should (equal (pyim-codes-create
-                  (car (pyim-imobjs-create "nihao" 'quanpin))
-                  'quanpin)
-                 '("ni" "hao")))
-  (should (equal (pyim-codes-create
-                  (car (pyim-imobjs-create "aaaa" 'wubi))
-                  'wubi)
-                 '("wubi/aaaa")))
-  (should (equal (pyim-codes-create
-                  (car (pyim-imobjs-create "aaaa" 'wubi))
-                  'wubi 2)
-                 '("wubi/aa")))
-  (should (equal (pyim-codes-create
-                  (car (pyim-imobjs-create "aaaa" 'wubi))
-                  'wubi 1)
-                 '("wubi/a")))
-  (should (equal (pyim-codes-create
-                  (car (pyim-imobjs-create "aaaa" 'cangjie))
-                  'cangjie)
-                 '("cangjie/aaaa"))))
+  (let ((quanpin (pyim-scheme-get 'quanpin))
+        (wubi (pyim-scheme-get 'wubi))
+        (cangjie (pyim-scheme-get 'cangjie))
+        (pyim-shuangpin (pyim-scheme-get 'pyim-shuangpin)))
+    (should (equal (pyim-codes-create
+                    (car (pyim-imobjs-create "nihao" quanpin))
+                    quanpin)
+                   '("ni" "hao")))
+    (should (equal (pyim-codes-create
+                    (car (pyim-imobjs-create "aaaa" wubi))
+                    wubi)
+                   '("wubi/aaaa")))
+    (should (equal (pyim-codes-create
+                    (car (pyim-imobjs-create "aaaa" wubi))
+                    wubi 2)
+                   '("wubi/aa")))
+    (should (equal (pyim-codes-create
+                    (car (pyim-imobjs-create "aaaa" wubi))
+                    wubi 1)
+                   '("wubi/a")))
+    (should (equal (pyim-codes-create
+                    (car (pyim-imobjs-create "aaaa" cangjie))
+                    cangjie)
+                   '("cangjie/aaaa")))))
 
 ;; ** pyim-candidates 相关单元测试
 (ert-deftest pyim-tests-pyim-candidates-search-buffer ()
@@ -405,16 +459,7 @@
       (should (equal (get-text-property 0 :comment (car words)) "(Buf)")))))
 
 (ert-deftest pyim-tests-pyim-candidates-cloud-search ()
-  (let ((pyim-candidates-cloud-search-function
-         (lambda (x y)
-           (list x y "b"))))
-    (should (equal (pyim-candidates-cloud-search "a" 'quanpin) '("a" quanpin 
"b"))))
-
-  (let ((pyim-candidates-cloud-search-function nil))
-    (should (not (pyim-candidates-cloud-search "a" 'quanpin))))
-
-  (let ((pyim-candidates-cloud-search-function "xxx"))
-    (should (not (pyim-candidates-cloud-search "a" 'quanpin)))))
+  (should-not (pyim-candidates-cloud-search "a" t)))
 
 ;; ** pyim-cstring 相关单元测试
 (ert-deftest pyim-tests-pyim-cstring-partition ()
@@ -528,15 +573,20 @@
                            "Hello -yin-hang-hen-hang- Hi")))))
 
 (ert-deftest pyim-tests-pyim-cstring-to-xingma ()
-  (let ((pyim-dhashcache-word2code (make-hash-table :test #'equal)))
+  (let ((pyim-dhashcache-word2code (make-hash-table :test #'equal))
+        (wubi (pyim-scheme-get 'wubi))
+        (cangjie (pyim-scheme-get 'cangjie)))
     (puthash "工" (list "wubi/aaaa" "cangjie/mlm" "gong") 
pyim-dhashcache-word2code)
     (puthash "房" (list "wubi/yny") pyim-dhashcache-word2code)
     (puthash "丛" (list "wubi/wwg") pyim-dhashcache-word2code)
-    (should (equal (pyim-cstring-to-xingma "工" 'wubi) "aaaa"))
-    (should (equal (pyim-cstring-to-xingma "工房" 'wubi) "aayn"))
-    (should (equal (pyim-cstring-to-xingma "工房丛" 'wubi) "ayww"))
-    (should (equal (pyim-cstring-to-xingma "工房丛房" 'wubi) "aywy"))
-    (should (equal (pyim-cstring-to-xingma "工" 'wubi t) '("aaaa")))))
+    (should (equal (pyim-cstring-to-xingma "工" cangjie) "mlm"))
+    (should-not (pyim-cstring-to-xingma "工房" cangjie))
+    (should (equal (pyim-cstring-to-xingma "工" wubi) "aaaa"))
+    (should (equal (pyim-cstring-to-xingma "工房" wubi) "aayn"))
+    (should (equal (pyim-cstring-to-xingma "工房丛" wubi) "ayww"))
+    (should (equal (pyim-cstring-to-xingma "工房丛房" wubi) "aywy"))
+    (should (equal (pyim-cstring-to-xingma "工" wubi t) '("aaaa")))
+    (should (equal (pyim-cstring-to-xingma "工房" wubi t) '("aayn")))))
 
 (ert-deftest pyim-tests-pyim-cstring-words-at-point ()
   (let ((pyim-dhashcache-code2word (make-hash-table :test #'equal)))
@@ -633,8 +683,8 @@
     (should-not (string-match-p regexp2 str)))
 
   (let* ((imobj '(("d" "a" "d" "a") ("w" "ang" "w" "ang")))
-         (regexp1 (pyim-cregexp-build:quanpin imobj))
-         (regexp2 (pyim-cregexp-build:quanpin imobj nil nil t)))
+         (regexp1 (pyim-cregexp-build-quanpin imobj))
+         (regexp2 (pyim-cregexp-build-quanpin imobj nil nil t)))
     (should (string-match-p regexp1 "大王"))
     (should (string-match-p regexp1 "当王"))
     (should (string-match-p regexp2 "大王"))
@@ -1070,20 +1120,25 @@ Transfer-Encoding: chunked
     (should (equal (get-text-property 0 :comment (car 
(pyim-cloudim-parse-google-buffer))) "(云)")))
 
   (when (not noninteractive)
-    (should (equal (pyim-cloudim:baidu "nihao" 'quanpin) '("你好")))
-    (should (equal (pyim-cloudim:google "nihao" 'quanpin) '("你好")))
+    (let ((wubi (pyim-scheme-get 'wubi)))
+      (should (equal (pyim-candidates-cloud-search "nihao" wubi) nil))
+      (should (equal (pyim-candidates-cloud-search "nihao" wubi) nil)))
 
-    (let ((pyim-cloudim 'baidu))
-      (should (equal (pyim-cloudim "nihao" 'quanpin) '("你好"))))
+    (let ((pyim-cloudim 'baidu)
+          (quanpin (pyim-scheme-get 'quanpin)))
+      (should (equal (pyim-candidates-cloud-search "nihao" quanpin) '("你好"))))
 
-    (let ((pyim-cloudim 'google))
-      (should (equal (pyim-cloudim "nihao" 'quanpin) '("你好"))))
+    (let ((pyim-cloudim 'google)
+          (quanpin (pyim-scheme-get 'quanpin)))
+      (should (equal (pyim-candidates-cloud-search "nihao" quanpin) '("你好"))))
 
-    (let ((pyim-cloudim 'xxx))
-      (should (not (pyim-cloudim "nihao" 'quanpin))))
+    (let ((pyim-cloudim 'xxx)
+          (quanpin (pyim-scheme-get 'quanpin)))
+      (should (not (pyim-candidates-cloud-search "nihao" quanpin))))
 
-    (let ((pyim-cloudim nil))
-      (should (not (pyim-cloudim "nihao" 'quanpin))))))
+    (let ((pyim-cloudim nil)
+          (quanpin (pyim-scheme-get 'quanpin)))
+      (should (not (pyim-candidates-cloud-search "nihao" quanpin))))))
 
 (ert-run-tests-batch-and-exit)
 ;; * Footer



reply via email to

[Prev in Thread] Current Thread [Next in Thread]