Commit 500fd323 authored by Yuanle Song's avatar Yuanle Song
Browse files

build-candidates add fetch-size support;

- handle fetch more in page down function.
- let build-candidates sync version support fetch-size param.
- adjusted some debug log
- tested zero-pinyin and sync and async mode, both works. I can't feel the
  difference.
parent 1ac8945b
Loading
Loading
Loading
Loading
+56 −34
Original line number Diff line number Diff line
@@ -96,13 +96,13 @@ if item is not in lst, return nil"

;;; concrete input method should define these functions and set them in the
;;; corresponding *-func variable.
(defun zero-build-candidates-default (_preedit-str) nil)
(defun zero-build-candidates-default (_preedit-str _fetch-size) nil)
(defun zero-can-start-sequence-default (_ch) nil)
(defun zero-get-preedit-str-for-panel-default () zero-preedit-str)
(defvar zero-build-candidates-func 'zero-build-candidates-default
  "contains a function to build candidates from preedit-str. The function accepts param preedit-str, returns candidate list.")
  "contains a function to build candidates from preedit-str. The function accepts param preedit-str, fetch-size, returns candidate list.")
(defvar zero-build-candidates-async-func 'zero-build-candidates-async-default
  "contains a function to build candidates from preedit-str. The function accepts param preedit-str, and a complete-func that should be called on returned candidate list.")
  "contains a function to build candidates from preedit-str. The function accepts param preedit-str, fetch-size, and a complete-func that should be called on returned candidate list.")
(defvar zero-can-start-sequence-func 'zero-can-start-sequence-default
  "contains a function to decide whether a char can start a preedit sequence")
(defvar zero-handle-preedit-char-func 'zero-handle-preedit-char-default
@@ -152,6 +152,12 @@ otherwise, next single quote insert close quote")
  "how many candidates to show on each page"
  :group 'zero)
(defvar zero-current-page 0 "current page number. count from 0")
(defvar zero-initial-fetch-size 20
  "how many candidates to fetch for the first call to GetCandidates")
;; zero-fetch-size is reset to 0 when preedit-str changes.
;; zero-fetch-size is set to fetch-size in build-candidates-async complete-func
;; lambda.
(defvar zero-fetch-size 0 "last GetCandidates call's fetch-size")
(defvar zero-previous-page-key ?\- "previous page key")
(defvar zero-next-page-key ?\= "next page key")

@@ -192,23 +198,23 @@ if t, `zero-debug' will output debug msg in *zero-debug* buffer")
    (destructuring-bind (x y) (zero-get-point-position)
      (zero-panel-move x y))))

(defun zero-build-candidates (preedit-str)
(defun zero-build-candidates (preedit-str fetch-size)
  "build candidates list synchronously"
  (zero-debug "build candidates list synchronously")
  (if (functionp zero-build-candidates-func)
      (funcall zero-build-candidates-func preedit-str)
    (error "`zero-build-candidates-func' is not a function")))
  ;; (zero-debug "zero-build-candidates\n")
  (unless (functionp zero-build-candidates-func)
    (signal 'wrong-type-argument (list 'functionp zero-build-candidates-func)))
  (prog1 (funcall zero-build-candidates-func preedit-str fetch-size)
    (setq zero-fetch-size fetch-size)))

(defun zero-build-candidates-complete (candidates)
  "called when `zero-build-candidates-async' returns"
  (setq zero-candidates candidates)
  (setq zero-current-page 0)
  (zero-show-candidates candidates))

(defun zero-build-candidates-async-default (preedit-str complete-func)
(defun zero-build-candidates-async-default (preedit-str fetch-size complete-func)
  "build candidate list, when done show it via `zero-show-candidates'"
  (zero-debug "building candidate list asynchronously\n")
  (let ((candidates (zero-build-candidates preedit-str)))
  ;; (zero-debug "zero-build-candidates-async-default\n")
  (let ((candidates (zero-build-candidates preedit-str fetch-size)))
    ;; update cache to make SPC and digit key selection possible.
    (funcall complete-func candidates)))

@@ -278,13 +284,28 @@ return ch's Chinese punctuation if ch is converted. return nil otherwise"
    (setq zero-current-page (1- zero-current-page))
    (zero-show-candidates)))

(defun zero-page-down ()
  "if there is still candidates to be displayed, show candidates on next page."
(defun zero-just-page-down ()
  "just page down using existing candidates"
  (let ((len (length zero-candidates)))
    (when (> len (* zero-candidates-per-page (1+ zero-current-page)))
      (setq zero-current-page (1+ zero-current-page))
      (zero-show-candidates))))

(defun zero-page-down ()
  "if there is still candidates to be displayed, show candidates on next page."
  (let ((len (length zero-candidates))
	(new-fetch-size (* zero-candidates-per-page (+ 2 zero-current-page))))
    (if (and (< len new-fetch-size)
	     (< zero-fetch-size new-fetch-size))
	(funcall zero-build-candidates-async-func
		 zero-preedit-str
		 new-fetch-size
		 (lambda (candidates)
		   (zero-build-candidates-complete candidates)
		   (setq zero-fetch-size new-fetch-size)
		   (zero-just-page-down)))
      (zero-just-page-down))))

(defun zero-handle-preedit-char-default (ch)
  "hanlde character insert in `*zero-state-im-preediting*' state"
  (cond
@@ -333,7 +354,9 @@ return ch's Chinese punctuation if ch is converted. return nil otherwise"

(defun zero-preedit-str-changed ()
  "called when preedit str is changed and not empty. update and show candidate list"
  (funcall zero-build-candidates-async-func zero-preedit-str 'zero-build-candidates-complete))
  (setq zero-fetch-size 0)
  (setq zero-current-page 0)
  (funcall zero-build-candidates-async-func zero-preedit-str zero-initial-fetch-size 'zero-build-candidates-complete))

(defun zero-backspace-default ()
  "handle backspace key in `*zero-state-im-preediting*' state"
@@ -424,10 +447,7 @@ return ch's Chinese punctuation if ch is converted. return nil otherwise"
;; minor mode
;;============

;; TODO when zero-framework is stable, move default value to defvar.
;; this will allow user to customize the keymap.
(defvar zero-mode-map nil "zero-mode keymap")
(setq zero-mode-map
(defvar zero-mode-map
  '(keymap
    (escape . zero-reset)
    (13 . zero-return)
@@ -440,7 +460,8 @@ return ch's Chinese punctuation if ch is converted. return nil otherwise"
	   ;; (forward-word . zero-forward-word)
	   ;; (backward-word . zero-backward-word)
	   ;; (delete-char . zero-delete-char)
	       )))
	   ))
  "zero-mode keymap")

(define-minor-mode zero-mode
  "a Chinese input method framework written as an emacs minor mode.
@@ -466,6 +487,7 @@ return ch's Chinese punctuation if ch is converted. return nil otherwise"
  (set (make-local-variable 'zero-candidates) nil)
  (make-local-variable 'zero-candidates-per-page)
  (make-local-variable 'zero-current-page)
  (make-local-variable 'zero-fetch-size)
  (make-local-variable 'zero-im)
  (make-local-variable 'zero-build-candidates-func)
  (make-local-variable 'zero-can-start-sequence-func)
+37 −12
Original line number Diff line number Diff line
@@ -20,8 +20,6 @@
  "accompany `zero-candidates', marks how many preedit-str chars are used for each candidate")
(defvar zero-pinyin-pending-str "")
(defvar zero-pinyin-pending-preedit-str "")
(defvar zero-pinyin-initial-fetch-size 20
  "how many candidates to fetch for the first call to GetCandidates")

;;=====================
;; key logic functions
@@ -40,21 +38,27 @@
(defvar zero-pinyin--build-candidates-use-test-data nil
  "if t, `zero-pinyin-build-candidates' will use `zero-pinyin-build-candidates-test'")

(defun zero-pinyin-build-candidates (preedit-str)
(defun zero-pinyin-build-candidates (preedit-str fetch-size)
  "zero-pinyin-build-candidates synchronous version"
  (if zero-pinyin--build-candidates-use-test-data
      (progn
	(zero-pinyin-build-candidates-test preedit-str)
    (let ((result (zero-pinyin-service-get-candidates preedit-str zero-pinyin-initial-fetch-size)))
	(setq zero-fetch-size fetch-size))
    (zero-debug "zero-pinyin building candidate list synchronously\n")
    (let ((result (zero-pinyin-service-get-candidates preedit-str fetch-size)))
      (setq zero-fetch-size fetch-size)
      (setq zero-pinyin-used-preedit-str-lengths (second result))
      (first result))))

(defun zero-pinyin-build-candidates-async (preedit-str complete-func)
(defun zero-pinyin-build-candidates-async (preedit-str fetch-size complete-func)
  "build candidate list, when done call complete-func on it"
  (zero-debug "building candidate list async\n")
  (zero-debug "zero-pinyin building candidate list asynchronously\n")
  (zero-pinyin-service-get-candidates-async
   preedit-str
   zero-pinyin-initial-fetch-size
   fetch-size
   (lambda (candidates matched_preedit_str_lengths)
     (setq zero-pinyin-used-preedit-str-lengths matched_preedit_str_lengths)
     (setq zero-fetch-size fetch-size)
     ;; Note: with dynamic binding, this command result in (void-variable
     ;; complete-func) error.
     (funcall complete-func candidates))))
@@ -77,7 +81,9 @@
  (should-not (zero-pinyin-can-start-sequence ?v)))

(defun zero-pinyin-pending-preedit-str-changed ()
  (zero-pinyin-build-candidates-async zero-pinyin-pending-preedit-str 'zero-build-candidates-complete))
  (setq zero-fetch-size 0)
  (setq zero-current-page 0)
  (zero-pinyin-build-candidates-async zero-pinyin-pending-preedit-str zero-initial-fetch-size 'zero-build-candidates-complete))

(defun zero-pinyin-commit-nth-candidate (n)
  "commit nth candidate and return true if it exists, otherwise, return false"
@@ -141,6 +147,23 @@ otherwise, just return nil"
	  t))
       (t (error "Unexpected zero-pinyin-state: %s" zero-pinyin-state))))))

(defun zero-pinyin-page-down ()
  "handle page down for zero-pinyin.

This is different from zero-framework because I need to support partial commit"
  (let ((len (length zero-candidates))
	(new-fetch-size (* zero-candidates-per-page (+ 2 zero-current-page))))
    (if (and (< len new-fetch-size)
	     (< zero-fetch-size new-fetch-size))
	(let ((preedit-str (if (eq zero-pinyin-state *zero-pinyin-state-im-partial-commit*) zero-pinyin-pending-preedit-str zero-preedit-str)))
	  (zero-pinyin-build-candidates-async
	   preedit-str
	   new-fetch-size
	   (lambda (candidates)
	     (zero-build-candidates-complete candidates)
	     (zero-just-page-down))))
      (zero-just-page-down))))

(defun zero-pinyin-handle-preedit-char (ch)
  "hanlde character insert in `*zero-state-im-preediting*' state. overrides `zero-handle-preedit-char-default'"
  (cond
@@ -154,9 +177,10 @@ otherwise, just return nil"
    (unless (zero-pinyin-commit-nth-candidate (mod (- (- ch ?0) 1) 10))
      (zero-append-char-to-preedit-str ch)
      (setq zero-pinyin-state nil)))
   ((or (= ch zero-previous-page-key)
	(= ch zero-next-page-key))
   ((= ch zero-previous-page-key)
    (zero-handle-preedit-char-default ch))
   ((= ch zero-next-page-key)
    (zero-pinyin-page-down))
   (t (let ((str (zero-convert-punctuation ch)))
	(if str
	    (when (zero-pinyin-commit-first-candidate-in-full)
@@ -186,7 +210,8 @@ otherwise, just return nil"
(zero-register-im
 'pinyin
 '((:build-candidates . zero-pinyin-build-candidates)
   (:build-candidates-async . zero-pinyin-build-candidates-async)
   ;; comment to use sync version, uncomment to use async version.
   ;; (:build-candidates-async . zero-pinyin-build-candidates-async)
   (:can-start-sequence . zero-pinyin-can-start-sequence)
   (:handle-preedit-char . zero-pinyin-handle-preedit-char)
   (:get-preedit-str-for-panel . zero-pinyin-get-preedit-str-for-panel)
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
should sort before rhs."
  (string< (car lhs) (car rhs)))

(defun zero-table-build-candidates (preedit-str)
(defun zero-table-build-candidates (preedit-str &optional _fetch-size)
  (mapcar 'cdr (sort (cl-remove-if-not (lambda (pair) (string-prefix-p preedit-str (car pair))) zero-table-table) 'zero-table-sort-key)))

(ert-deftest zero-table-build-candidates ()