Commit d91d0f6b authored by Yuanle Song's avatar Yuanle Song
Browse files

v2.1.0 zero pinyin supports sync and async mode.

- bugfix on zero-input-pinyin: sometimes after GetCandidate dbus call,
  zero-input-fetch-size and zero-input-candidates is not updated. This
  was because the async function callback didn't update the metadata in
  some places.
- zero pinyin supports sync and async mode.
  to switch between them, run
  M-x zero-input-pinyin-enable-async
  M-x zero-input-pinyin-disable-async
parent cd075a5f
......@@ -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.7")
(setq zero-input-version "2.1.0")
;; FSM state
(defconst zero-input--state-im-off 'IM-OFF)
......@@ -306,11 +306,14 @@ Change will be effective only in new `zero-input-mode' buffer."
:group 'zero
:type 'integer)
(defvar-local zero-input-current-page 0 "Current page number. count from 0.")
(defvar-local zero-input-initial-fetch-size 20
"How many candidates to fetch for the first call to GetCandidates.")
(defvar-local zero-input-initial-fetch-size 21
"How many candidates to fetch for the first call to GetCandidates.
It's best set to (1+ (* zero-input-candidates-per-page N)) where
N is number of pages you want to fetch in initial fetch.")
;; zero-input-fetch-size is reset to 0 when preedit-str changes.
;; zero-input-fetch-size is set to fetch-size in build-candidates-async complete-func
;; lambda.
;; zero-input-fetch-size is set to fetch-size in build-candidates-async
;; complete-func lambda.
(defvar-local zero-input-fetch-size 0 "Last GetCandidates call's fetch-size.")
(defvar zero-input-previous-page-key ?\- "Previous page key.")
(defvar zero-input-next-page-key ?\= "Next page key.")
......@@ -419,8 +422,9 @@ enough elements, return lst as it is."
(defun zero-input-show-candidates (&optional candidates)
"Show CANDIDATES using zero-input-panel via IPC/RPC."
(let ((candidates-on-page (zero-input-candidates-on-page (or candidates
zero-input-candidates))))
(let ((candidates-on-page
(zero-input-candidates-on-page (or candidates
zero-input-candidates))))
(cl-destructuring-bind (x y) (zero-input-get-point-position)
(zero-input-panel-show-candidates
(funcall zero-input-get-preedit-str-for-panel-func)
......@@ -438,19 +442,15 @@ enough elements, return lst as it is."
(defun zero-input-build-candidates (preedit-str fetch-size)
"Build candidates list synchronously.
Try to find at least FETCH-SIZE number of candidates for PREEDIT-STR."
Try to find at least FETCH-SIZE number of candidates for PREEDIT-STR.
Return a list of candidates."
;; (zero-input-debug "zero-input-build-candidates\n")
(unless (functionp zero-input-build-candidates-func)
(signal 'wrong-type-argument (list 'functionp zero-input-build-candidates-func)))
(prog1 (funcall zero-input-build-candidates-func preedit-str fetch-size)
(setq zero-input-fetch-size (max fetch-size (length zero-input-candidates)))))
(defun zero-input-build-candidates-complete (candidates)
"Called when `zero-input-build-candidates-async' return.
CANDIDATES is returned candidates list from async call."
(setq zero-input-candidates candidates)
(zero-input-show-candidates candidates))
;; Note that zero-input-candidates and zero-input-fetch-size is updated in
;; async complete callback. This function only care about building the
;; candidates.
(funcall zero-input-build-candidates-func preedit-str fetch-size))
(defun zero-input-build-candidates-async-default (preedit-str fetch-size complete-func)
"Build candidate list, when done show it via `zero-input-show-candidates'.
......@@ -459,6 +459,7 @@ PREEDIT-STR the preedit-str.
FETCH-SIZE try to find at least this many candidates for preedit-str.
COMPLETE-FUNC the function to call when build candidates completes."
;; (zero-input-debug "zero-input-build-candidates-async-default\n")
;; default implementation just call sync version `zero-input-build-candidates'.
(let ((candidates (zero-input-build-candidates preedit-str fetch-size)))
;; update cache to make SPC and digit key selection possible.
(funcall complete-func candidates)))
......@@ -574,23 +575,27 @@ Return CH's Chinese punctuation if CH is converted. Return nil otherwise."
(let ((len (length zero-input-candidates)))
(when (> len (* zero-input-candidates-per-page (1+ zero-input-current-page)))
(setq zero-input-current-page (1+ zero-input-current-page))
(zero-input-debug "showing candidates on page %s\n" zero-input-current-page)
(zero-input-show-candidates))))
(defun zero-input-page-down ()
"If there is still candidates to be displayed, show candidates on next page."
(interactive)
(let ((len (length zero-input-candidates))
(new-fetch-size (* zero-input-candidates-per-page (+ 2 zero-input-current-page))))
(new-fetch-size (1+ (* zero-input-candidates-per-page (+ 2 zero-input-current-page)))))
(zero-input-debug "decide whether to fetch more candidates, has %s candidates, last fetch size=%s, new-fetch-size=%s\n" len zero-input-fetch-size new-fetch-size)
(if (and (< len new-fetch-size)
(< zero-input-fetch-size new-fetch-size))
(funcall zero-input-build-candidates-async-func
zero-input-preedit-str
new-fetch-size
(lambda (candidates)
(zero-input-build-candidates-complete candidates)
(setq zero-input-fetch-size (max new-fetch-size
(length candidates)))
(zero-input-just-page-down)))
(progn
(zero-input-debug "will fetch more candidates")
(funcall zero-input-build-candidates-async-func
zero-input-preedit-str
new-fetch-size
(lambda (candidates)
(setq zero-input-candidates candidates)
(setq zero-input-fetch-size (max new-fetch-size
(length candidates)))
(zero-input-just-page-down))))
(zero-input-just-page-down))))
(defun zero-input-handle-preedit-char-default (ch)
......@@ -644,11 +649,26 @@ N is the argument passed to `self-insert-command'."
(zero-input-debug "unexpected state: %s\n" zero-input-state)
(self-insert-command n)))))
(defun zero-input-get-initial-fetch-size ()
"Return initial fetch size."
(cond
((<= zero-input-initial-fetch-size zero-input-candidates-per-page)
(1+ zero-input-candidates-per-page))
((zerop (mod zero-input-initial-fetch-size zero-input-candidates-per-page))
(1+ zero-input-initial-fetch-size))
(t zero-input-initial-fetch-size)))
(defun zero-input-preedit-str-changed ()
"Called when preedit str is changed and not empty. Update and show candidate list."
(setq zero-input-fetch-size 0)
(setq zero-input-current-page 0)
(funcall zero-input-build-candidates-async-func zero-input-preedit-str zero-input-initial-fetch-size 'zero-input-build-candidates-complete))
(let ((new-fetch-size (zero-input-get-initial-fetch-size)))
(funcall zero-input-build-candidates-async-func
zero-input-preedit-str new-fetch-size
(lambda (candidates)
(setq zero-input-candidates candidates)
(setq zero-input-fetch-size (max new-fetch-size (length candidates)))
(zero-input-show-candidates candidates)))))
(defun zero-input-backspace-default ()
"Handle backspace key in `zero-input--state-im-preediting' state."
......@@ -1162,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
......@@ -1208,10 +1231,14 @@ 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)))
(setq zero-input-fetch-size (max fetch-size (length (cl-first result))))
;; update zero-input-candidates and zero-input-fetch-size is done in async
;; complete callback. This function only care about building the
;; candidates and updating zero-input-pinyin specific.
(setq zero-input-pinyin-used-preedit-str-lengths (cl-second result))
(setq zero-input-pinyin-candidates-pinyin-indices (cl-third result))
(cl-first result)))
......@@ -1228,9 +1255,10 @@ COMPLETE-FUNC the callback function when async call completes. it's called with
preedit-str
fetch-size
(lambda (candidates matched_preedit_str_lengths candidates_pinyin_indices)
(setq zero-input-candidates candidates)
(setq zero-input-fetch-size (max fetch-size (length candidates)))
(setq zero-input-pinyin-used-preedit-str-lengths matched_preedit_str_lengths)
(setq zero-input-pinyin-candidates-pinyin-indices candidates_pinyin_indices)
(setq zero-input-fetch-size (max fetch-size (length candidates)))
;; Note: with dynamic binding, this command result in (void-variable
;; complete-func) error.
(funcall complete-func candidates))))
......@@ -1243,11 +1271,34 @@ 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)
(zero-input-pinyin-build-candidates-async zero-input-pinyin-pending-preedit-str zero-input-initial-fetch-size 'zero-input-build-candidates-complete))
(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)
"Commit Nth candidate and return true if it exists, otherwise, return false."
......@@ -1333,16 +1384,24 @@ 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 (* zero-input-candidates-per-page (+ 2 zero-input-current-page))))
(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)
(if (and (< len new-fetch-size)
(< zero-input-fetch-size 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
(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-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-build-candidates-complete candidates)
(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)
......@@ -1420,24 +1479,42 @@ DIGIT 0 means delete 10th candidate."
;; register IM to zero framework
;;===============================
(zero-input-register-im
'pinyin
'((: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)
(:handle-backspace . zero-input-pinyin-backspace)
(:init . zero-input-pinyin-init)
(:shutdown . zero-input-pinyin-shutdown)
(:preedit-start . zero-input-pinyin-preedit-start)
(:preedit-end . zero-input-pinyin-preedit-end)))
(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)
(: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)
(:handle-backspace . zero-input-pinyin-backspace)
(:init . zero-input-pinyin-init)
(:shutdown . zero-input-pinyin-shutdown)
(:preedit-start . zero-input-pinyin-preedit-start)
(: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)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment