Commit 5c7782c3 authored by Yuanle Song's avatar Yuanle Song
Browse files

v2.1.0 allow switch between sync and async mode

for zero-input-pinyin.

zero-pinyin now uses zero-input-pinyin-build-candidates-unified
to fetch candidates. It is a unified interface, supports both
sync and async mode.
parent fa27eb3a
Loading
Loading
Loading
Loading
+176 −31
Original line number Diff line number Diff line
@@ -76,6 +76,18 @@ cd ~/lisp/elisp/zero/
    without converting char to string.

    (zero-input-table-can-start-sequence) can use this.
** 2020-02-04 how to make a release?					:doc:
- update version number in zero-input-framework.el
- run tests
  make check
- build a release .el file
  make dist
- check & fix styling issues
  open zero-input.el file
  M-x checkdoc
  M-x package-lint-current-buffer
- make a git commit.
- push commits
** 2019-10-10 documents
- Using of D-Bus
  https://www.gnu.org/software/emacs/manual/html_mono/dbus.html
@@ -88,6 +100,59 @@ complete registered im symbols.
** 2019-10-23 checkdoc and package-lint can't ignore some non-issues.
I can't run them in git pre-commit hook.
* done                                                                :entry:
** 2020-02-04 zero-input-pinyin, allow switch between sync and async mode in runtime.
title was: zero-input-pinyin.el why sometimes it uses sync call and sometimes
it uses async call?

- debug log.

  #+BEGIN_SRC sh
    zero-input-pinyin building candidate list synchronously
    zero-input-pinyin building candidate list asynchronously
  #+END_SRC

  zero-input-pinyin.el why sometimes it uses sync call and sometimes it
  uses async call? I think every async call should chain back to sync
  call.

  I think when a call is triggered from zero-framework.el, it will always
  be sync call. when a call is triggered from zero-pinyin.el, it MAY used
  async call directly.

  who calls zero-input-pinyin-build-candidates-async

  - zero-input-pinyin-preedit-str-changed
    calls framework's version. which use default async call. and chains to
    zero-pinyin sync call.
  - zero-input-pinyin-pending-preedit-str-changed
    uses async call.
  - zero-input-pinyin-page-down
    uses async call.

  No wonder zero-pinyin sync and async performance is on par. Because sync
  call is not used much.
- How to use sync or async call in all places? I don't want to mix it.
  just enable async in IM register code? confirmed enable async will only
  use async version.

  how to switch to sync version only?
- implementation
  - added zero-input-pinyin-use-async-fetch flag variable.
  - added zero-input-pinyin-build-candidates-unified, it will call sync or
    async version based on the flag.
- problems
  - how to be able to switch between sync and async version in runtime?
    now I can switch it in build time, but how to switch it in runtime?

    It's mainly about the im register code.

    I have to provide a method to do it. a variable is not enough.
    Because I need to update the IM class method slot value.

    M-x zero-input-pinyin-enable-async
    M-x zero-input-pinyin-disable-async
  - 

** 2020-02-03 部分词组,打字时只出现词组,不能选单字。
zhiyuan 支援
zhishi 知识
@@ -221,37 +286,6 @@ weiyi 卫衣
           ;; (:build-candidates-async . zero-input-pinyin-build-candidates-async)
      #+END_SRC

    - debug log.

      #+BEGIN_SRC sh
        zero-input-pinyin building candidate list synchronously
        zero-input-pinyin building candidate list asynchronously
      #+END_SRC

      zero-input-pinyin.el why sometimes it uses sync call and sometimes it
      uses async call? I think every async call should chain back to sync
      call.

      I think when a call is triggered from zero-framework.el, it will always
      be sync call. when a call is triggered from zero-pinyin.el, it MAY used
      async call directly.

      who calls zero-input-pinyin-build-candidates-async

      - zero-input-pinyin-preedit-str-changed
	calls framework's version. which use default async call. and chains to
        zero-pinyin sync call.
      - zero-input-pinyin-pending-preedit-str-changed
	uses async call.
      - zero-input-pinyin-page-down
	uses async call.

      No wonder zero-pinyin sync and async performance is on par. Because sync
      call is not used much.
    - How to use sync or async call in all places? I don't want to mix it.
      just enable async in IM register code?
    - 

** 2019-11-10 space doesn't work in full-width mode.
全角和半角 - 维基百科,自由的百科全书
https://zh.wikipedia.org/wiki/%E5%85%A8%E5%BD%A2%E5%92%8C%E5%8D%8A%E5%BD%A2
@@ -631,3 +665,114 @@ https://github.com/melpa/melpa/blob/master/CONTRIBUTING.org#preparing-a-pull-req
    fixed.

* wontfix                                                             :entry:
** 2020-02-04 zero-input-pinyin-pending-preedit-str="erduo" not correct?
- zero-input-pinyin-pending-preedit-str="erduo"

  zero-input-pinyin-pending-preedit-str
  this variable may not be cleared at proper place.

  #+BEGIN_SRC sh
    synchronously
    candidates: 摩尔, 莫尔, 末儿, 模, 默, 麽, 莫, 摸, 末, 磨
    user typed: d
    still preediting
    appended d, preedit str is: moerd
    zero-input-pinyin building candidate list synchronously
    candidates: 摸耳朵, 莫尔德, 摩尔, 莫尔, 末儿, 模, 默, 麽, 莫, 摸
    user typed: u
    still preediting
    appended u, preedit str is: moerdu
    zero-input-pinyin building candidate list synchronously
    candidates: 摩尔, 莫尔, 末儿, 模, 默, 麽, 莫, 摸, 末, 磨
    user typed: o
    still preediting
    appended o, preedit str is: moerduo
    zero-input-pinyin building candidate list synchronously
    candidates: 摸耳朵, 摩尔, 莫尔, 末儿, 模, 默, 麽, 莫, 摸, 末
    user typed:  
    still preediting
    zero-input-pinyin-commit-nth-candidate
        n=0 candidate=摸耳朵 used-len=7 zero-input-pinyin-pending-preedit-str="erduo"
    commit in full
    set state to IM-WAITING-INPUT
    zero-input-disable-preediting-map
    commit text: 摸耳朵
    hide candidate list
    user typed: d
    can start sequence, state=IM_PREEDITING
    set state to IM-PREEDITING
    zero-input-enable-preediting-map
    appended d, preedit str is: d
    zero-input-pinyin building candidate list synchronously
    candidates: 的, 都, 到, 等, 第, 带, 大, 对, 当, 低
    user typed: u
    still preediting
    appended u, preedit str is: du
    zero-input-pinyin building candidate list synchronously
    candidates: 度, 赌, 读, 独, 毒, 都, 肚, 督, 渡, 杜
    user typed: i
    still preediting
    appended i, preedit str is: dui
    zero-input-pinyin building candidate list synchronously
    candidates: 对, 队, 堆, 對, 兑, 隊, 怼, 碓, 桘, 憝
    user typed: b
    still preediting
    appended b, preedit str is: duib
    zero-input-pinyin building candidate list synchronously
    candidates: 对比, 对白, 对本, 对不, 对吧, 对被, 对表, 对半, 对把, 对边
    user typed: u
    still preediting
    appended u, preedit str is: duibu
    zero-input-pinyin building candidate list synchronously
    candidates: 对不, 队部, 对, 队, 堆, 對, 兑, 隊, 怼, 碓
    user typed: q
    still preediting
    appended q, preedit str is: duibuq
    zero-input-pinyin building candidate list synchronously
    candidates: 对不起, 对不, 队部, 对, 队, 堆, 對, 兑, 隊, 怼
    user typed: i
    still preediting
    appended i, preedit str is: duibuqi
    zero-input-pinyin building candidate list synchronously
    candidates: 对不起, 对不, 队部, 对, 队, 堆, 對, 兑, 隊, 怼
    user typed:  
    still preediting
    zero-input-pinyin-commit-nth-candidate
        n=0 candidate=对不起 used-len=7 zero-input-pinyin-pending-preedit-str="erduo"
    commit in full
    set state to IM-WAITING-INPUT
    zero-input-disable-preediting-map
    commit text: 对不起
    hide candidate list
  #+END_SRC

  I can redproduce it.
  just delete the user phrase, then type it again.
  #+BEGIN_SRC sh
    user typed: o
    still preediting
    appended o, preedit str is: moerduo
    zero-input-pinyin building candidate list synchronously
    candidates: 摸耳朵, 摩尔, 莫尔, 末儿, 模, 默, 麽, 莫, 摸, 末
    zero-input-pinyin building candidate list synchronously
    candidates: 摩尔, 莫尔, 末儿, 模, 默, 麽, 莫, 摸, 末, 磨
    user typed: 8
    still preediting
    zero-input-pinyin-commit-nth-candidate
        n=7 candidate=摸 used-len=2 zero-input-pinyin-pending-preedit-str=""
    partial commit, in partial commit mode now.
    zero-input-pinyin building candidate list synchronously
    candidates: 耳朵, 尔多, 而多, 尔, 耳, 而, 儿, 二, 兒, 爾
    user typed:  
    still preediting
    zero-input-pinyin-commit-nth-candidate
        n=0 candidate=耳朵 used-len=5 zero-input-pinyin-pending-preedit-str="erduo"
    finishes partial commit
    set state to IM-WAITING-INPUT
    zero-input-disable-preediting-map
    commit text: 摸耳朵
    hide candidate list
  #+END_SRC
  This is not a bug. zero-input-pinyin-pending-preedit-str is not used
  when IM has not go to partial commit mode. it will always be set to
  correct value when it does go to partial commit mode.
+2 −2
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ If item is not in lst, return nil."

;; zero-input-el version
(defvar zero-input-version nil "Zero package version.")
(setq zero-input-version "2.0.7")
(setq zero-input-version "2.1.0")

;; FSM state
(defconst zero-input--state-im-off 'IM-OFF)
@@ -539,7 +539,7 @@ N is the argument passed to `self-insert-command'."
      (self-insert-command n)))))

(defun zero-input-get-initial-fetch-size ()
  "return initial fetch size"
  "Return initial fetch size."
  (cond
   ((<= zero-input-initial-fetch-size zero-input-candidates-per-page)
    (1+ zero-input-candidates-per-page))
+72 −30
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@ You can find the xml file locally at
`zero-input-pinyin-service-interface-xml-url'."
  :type 'integer
  :group 'zero-input-pinyin)
(defvar zero-input-pinyin-use-async-fetch nil
  "Non-nil means use async dbus call to get candidates.")
(setq zero-input-pinyin-use-async-fetch nil)

(defvar-local zero-input-pinyin-state nil
  "Zero-input-pinyin internal state.  could be nil or
@@ -97,7 +100,9 @@ You can find the xml file locally at
  "Synchronously build candidates list.

PREEDIT-STR the preedit string.
FETCH-SIZE fetch at least this many candidates if possible."
FETCH-SIZE fetch at least this many candidates if possible.

Return candidates list"
  (zero-input-debug "zero-input-pinyin building candidate list synchronously\n")
  (let ((result (zero-input-pinyin-service-get-candidates preedit-str fetch-size)))
    ;; update zero-input-candidates and zero-input-fetch-size is done in async
@@ -135,13 +140,33 @@ COMPLETE-FUNC the callback function when async call completes. it's called with
       (not (= ch ?u))
       (not (= ch ?v))))

(defun zero-input-pinyin-build-candidates-unified (preedit-str fetch-size complete-func)
  "Build candidate list, when done call complete-func on it.

This may call sync or async dbus method depending on
`zero-input-pinyin-use-async-fetch'.

PREEDIT-STR the preedit string.
FETCH-SIZE fetch at least this many candidates if possible.
COMPLETE-FUNC the callback function when sync/async call completes.
              it's called with fetched candidates list as parameter."
  (if zero-input-pinyin-use-async-fetch
      (zero-input-pinyin-build-candidates-async
       preedit-str fetch-size complete-func)
    (let ((candidates (zero-input-pinyin-build-candidates
		       preedit-str fetch-size)))
      (setq zero-input-candidates candidates)
      (setq zero-input-fetch-size (max fetch-size (length candidates)))
      (funcall complete-func candidates))))

(defun zero-input-pinyin-pending-preedit-str-changed ()
  "Update zero states when pending preedit string changed."
  (setq zero-input-fetch-size 0)
  (setq zero-input-current-page 0)
  (let ((new-fetch-size (zero-input-get-initial-fetch-size)))
    (zero-input-pinyin-build-candidates-async
     zero-input-pinyin-pending-preedit-str new-fetch-size
  (let ((fetch-size (zero-input-get-initial-fetch-size))
	(preedit-str zero-input-pinyin-pending-preedit-str))
    (zero-input-pinyin-build-candidates-unified
     preedit-str fetch-size
     #'zero-input-show-candidates)))

(defun zero-input-pinyin-commit-nth-candidate (n)
@@ -229,23 +254,22 @@ Otherwise, just return nil."
This is different from zero-input-framework because I need to support partial commit"
  (let ((len (length zero-input-candidates))
	(new-fetch-size (1+ (* zero-input-candidates-per-page (+ 2 zero-input-current-page)))))
    (zero-input-debug
     "fetch more candidates? on page %s, has %s candidates, last-fetch-size=%s, new-fetch-size=%s\n"
     zero-input-current-page len zero-input-fetch-size new-fetch-size)
    ;; (zero-input-debug
    ;;  "fetch more candidates? on page %s, has %s candidates, last-fetch-size=%s, new-fetch-size=%s\n"
    ;;  zero-input-current-page len zero-input-fetch-size new-fetch-size)
    (if (and (< len new-fetch-size)
	     (< zero-input-fetch-size new-fetch-size))
	(progn
	  (zero-input-debug
	   "will fetch more candidates new-fetch-size=%s\n" new-fetch-size)
	(let ((preedit-str (if (eq zero-input-pinyin-state
				   zero-input-pinyin--state-im-partial-commit)
			       zero-input-pinyin-pending-preedit-str
			     zero-input-preedit-str)))
	    (zero-input-pinyin-build-candidates-async
	  (zero-input-debug
	   "will fetch more candidates new-fetch-size=%s\n" new-fetch-size)
	  (zero-input-pinyin-build-candidates-unified
	   preedit-str
	   new-fetch-size
	   (lambda (_candidates)
	       (zero-input-just-page-down)))))
	     (zero-input-just-page-down))))
      (zero-input-debug "won't fetch more candidates\n")
      (zero-input-just-page-down))))

@@ -324,11 +348,15 @@ DIGIT 0 means delete 10th candidate."
;; register IM to zero framework
;;===============================

(defun zero-input-pinyin-register-im ()
  "Register pinyin input method in zero framework."
  (zero-input-register-im
   'pinyin
   (append
    (if zero-input-pinyin-use-async-fetch
	'((:build-candidates-async . zero-input-pinyin-build-candidates-async))
      nil)
    '((:build-candidates . zero-input-pinyin-build-candidates)
   ;; comment to use sync version, uncomment to use async version.
   ;; (:build-candidates-async . zero-input-pinyin-build-candidates-async)
      (:can-start-sequence . zero-input-pinyin-can-start-sequence)
      (:handle-preedit-char . zero-input-pinyin-handle-preedit-char)
      (:get-preedit-str-for-panel . zero-input-pinyin-get-preedit-str-for-panel)
@@ -336,12 +364,26 @@ DIGIT 0 means delete 10th candidate."
      (:init . zero-input-pinyin-init)
      (:shutdown . zero-input-pinyin-shutdown)
      (:preedit-start . zero-input-pinyin-preedit-start)
   (:preedit-end . zero-input-pinyin-preedit-end)))
      (:preedit-end . zero-input-pinyin-preedit-end)))))

;;============
;; public API
;;============

(defun zero-input-pinyin-enable-async ()
  "Use async call to fetch candidates."
  (interactive)
  (setq zero-input-pinyin-use-async-fetch t)
  (zero-input-pinyin-register-im)
  (message "Enabled async mode"))

(defun zero-input-pinyin-disable-async ()
  "Use sync call to fetch candidates."
  (interactive)
  (setq zero-input-pinyin-use-async-fetch nil)
  (zero-input-pinyin-register-im)
  (message "Disabled async mode"))

(provide 'zero-input-pinyin)

;;; zero-input-pinyin.el ends here
+77 −33
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
;; See the License for the specific language governing permissions and
;; limitations under the License.

;; Version: 2.0.6
;; Version: 2.1.0
;; URL: https://gitlab.emacsos.com/sylecn/zero-el
;; Package-Requires: ((emacs "24.3") (s "1.2.0"))

@@ -243,7 +243,7 @@ If item is not in lst, return nil."

;; zero-input-el version
(defvar zero-input-version nil "Zero package version.")
(setq zero-input-version "2.0.6")
(setq zero-input-version "2.1.0")

;; FSM state
(defconst zero-input--state-im-off 'IM-OFF)
@@ -650,7 +650,7 @@ N is the argument passed to `self-insert-command'."
      (self-insert-command n)))))

(defun zero-input-get-initial-fetch-size ()
  "return initial fetch size"
  "Return initial fetch size."
  (cond
   ((<= zero-input-initial-fetch-size zero-input-candidates-per-page)
    (1+ zero-input-candidates-per-page))
@@ -1182,6 +1182,9 @@ You can find the xml file locally at
`zero-input-pinyin-service-interface-xml-url'."
  :type 'integer
  :group 'zero-input-pinyin)
(defvar zero-input-pinyin-use-async-fetch nil
  "Non-nil means use async dbus call to get candidates.")
(setq zero-input-pinyin-use-async-fetch nil)

(defvar-local zero-input-pinyin-state nil
  "Zero-input-pinyin internal state.  could be nil or
@@ -1228,7 +1231,9 @@ You can find the xml file locally at
  "Synchronously build candidates list.

PREEDIT-STR the preedit string.
FETCH-SIZE fetch at least this many candidates if possible."
FETCH-SIZE fetch at least this many candidates if possible.

Return candidates list"
  (zero-input-debug "zero-input-pinyin building candidate list synchronously\n")
  (let ((result (zero-input-pinyin-service-get-candidates preedit-str fetch-size)))
    ;; update zero-input-candidates and zero-input-fetch-size is done in async
@@ -1266,13 +1271,33 @@ COMPLETE-FUNC the callback function when async call completes. it's called with
       (not (= ch ?u))
       (not (= ch ?v))))

(defun zero-input-pinyin-build-candidates-unified (preedit-str fetch-size complete-func)
  "Build candidate list, when done call complete-func on it.

This may call sync or async dbus method depending on
`zero-input-pinyin-use-async-fetch'.

PREEDIT-STR the preedit string.
FETCH-SIZE fetch at least this many candidates if possible.
COMPLETE-FUNC the callback function when sync/async call completes.
              it's called with fetched candidates list as parameter."
  (if zero-input-pinyin-use-async-fetch
      (zero-input-pinyin-build-candidates-async
       preedit-str fetch-size complete-func)
    (let ((candidates (zero-input-pinyin-build-candidates
		       preedit-str fetch-size)))
      (setq zero-input-candidates candidates)
      (setq zero-input-fetch-size (max fetch-size (length candidates)))
      (funcall complete-func candidates))))

(defun zero-input-pinyin-pending-preedit-str-changed ()
  "Update zero states when pending preedit string changed."
  (setq zero-input-fetch-size 0)
  (setq zero-input-current-page 0)
  (let ((new-fetch-size (zero-input-get-initial-fetch-size)))
    (zero-input-pinyin-build-candidates-async
     zero-input-pinyin-pending-preedit-str new-fetch-size
  (let ((fetch-size (zero-input-get-initial-fetch-size))
	(preedit-str zero-input-pinyin-pending-preedit-str))
    (zero-input-pinyin-build-candidates-unified
     preedit-str fetch-size
     #'zero-input-show-candidates)))

(defun zero-input-pinyin-commit-nth-candidate (n)
@@ -1360,22 +1385,23 @@ Otherwise, just return nil."
This is different from zero-input-framework because I need to support partial commit"
  (let ((len (length zero-input-candidates))
	(new-fetch-size (1+ (* zero-input-candidates-per-page (+ 2 zero-input-current-page)))))
    (zero-input-debug
     "decide whether to fetch more candidates. on page %s, has %s candidates, last-fetch-size %s, new-fetch-size=%s\n"
     zero-input-current-page len zero-input-fetch-size new-fetch-size)
    ;; (zero-input-debug
    ;;  "fetch more candidates? on page %s, has %s candidates, last-fetch-size=%s, new-fetch-size=%s\n"
    ;;  zero-input-current-page len zero-input-fetch-size new-fetch-size)
    (if (and (< len new-fetch-size)
	     (< zero-input-fetch-size new-fetch-size))
	(progn
	  (zero-input-debug
	   "will fetch more candidates new-fetch-size=%s" new-fetch-size)
	(let ((preedit-str (if (eq zero-input-pinyin-state
				   zero-input-pinyin--state-im-partial-commit)
			       zero-input-pinyin-pending-preedit-str
			     zero-input-preedit-str)))
	    (zero-input-pinyin-build-candidates-async
	  (zero-input-debug
	   "will fetch more candidates new-fetch-size=%s\n" new-fetch-size)
	  (zero-input-pinyin-build-candidates-unified
	   preedit-str
	   new-fetch-size
	     #'zero-input-just-page-down)))
	   (lambda (_candidates)
	     (zero-input-just-page-down))))
      (zero-input-debug "won't fetch more candidates\n")
      (zero-input-just-page-down))))

(defun zero-input-pinyin-handle-preedit-char (ch)
@@ -1453,11 +1479,15 @@ DIGIT 0 means delete 10th candidate."
;; register IM to zero framework
;;===============================

(defun zero-input-pinyin-register-im ()
  "Register pinyin input method in zero framework."
  (zero-input-register-im
   'pinyin
   (append
    (if zero-input-pinyin-use-async-fetch
	'((:build-candidates-async . zero-input-pinyin-build-candidates-async))
      nil)
    '((:build-candidates . zero-input-pinyin-build-candidates)
   ;; comment to use sync version, uncomment to use async version.
   ;; (:build-candidates-async . zero-input-pinyin-build-candidates-async)
      (:can-start-sequence . zero-input-pinyin-can-start-sequence)
      (:handle-preedit-char . zero-input-pinyin-handle-preedit-char)
      (:get-preedit-str-for-panel . zero-input-pinyin-get-preedit-str-for-panel)
@@ -1465,12 +1495,26 @@ DIGIT 0 means delete 10th candidate."
      (:init . zero-input-pinyin-init)
      (:shutdown . zero-input-pinyin-shutdown)
      (:preedit-start . zero-input-pinyin-preedit-start)
   (:preedit-end . zero-input-pinyin-preedit-end)))
      (:preedit-end . zero-input-pinyin-preedit-end)))))

;;============
;; public API
;;============

(defun zero-input-pinyin-enable-async ()
  "Use async call to fetch candidates."
  (interactive)
  (setq zero-input-pinyin-use-async-fetch t)
  (zero-input-pinyin-register-im)
  (message "Enabled async mode"))

(defun zero-input-pinyin-disable-async ()
  "Use sync call to fetch candidates."
  (interactive)
  (setq zero-input-pinyin-use-async-fetch nil)
  (zero-input-pinyin-register-im)
  (message "Disabled async mode"))

(provide 'zero-input-pinyin)