From f4a20631dc69a84de1a871f0bfe8552bfa3f9d64 Mon Sep 17 00:00:00 2001 From: Yuanle Song Date: Thu, 4 Apr 2019 16:59:42 +0800 Subject: [PATCH] add zero-pinyin-service.el dbus based sync and async api both works. - added error handler for dbus client in emacs lisp. - use lexical-binding for all files - added M-x zero-reload-all this will byte compile and reload file files. --- zero-framework.el | 36 +++++++++++++++++++---------- zero-panel.el | 14 ++++++++++-- zero-pinyin-service.el | 52 ++++++++++++++++++++++++++++++++++++++++++ zero-pinyin.el | 34 ++++++++++++++++++--------- zero-quickdial.el | 1 + zero-reload-all.el | 11 +++++++++ zero-table.el | 1 + 7 files changed, 124 insertions(+), 25 deletions(-) create mode 100644 zero-pinyin-service.el create mode 100644 zero-reload-all.el diff --git a/zero-framework.el b/zero-framework.el index 3a02df0..6e2cf99 100644 --- a/zero-framework.el +++ b/zero-framework.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- ;; the zero Chinese input method framework for emacs. ;; implemented as a minor mode. ;; (load-file "~/lisp/elisp/zero/zero-panel.elc") @@ -95,11 +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-can-start-sequence-default (ch) nil) +(defun zero-build-candidates-default (_preedit-str) 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") + "contains a function to build candidates from preedit-str. The function accepts param preedit-str, 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.") (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 @@ -189,18 +192,23 @@ if t, `zero-debug' will output debug msg in *zero-debug* buffer") (defun zero-build-candidates (preedit-str) "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"))) -(defun zero-build-candidates-async (preedit-str) +(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) "build candidate list, when done show it via `zero-show-candidates'" - (zero-debug "building candidate list\n") + (zero-debug "building candidate list asynchronously\n") (let ((candidates (zero-build-candidates preedit-str))) ;; update cache to make SPC and digit key selection possible. - (setq zero-candidates candidates) - (setq zero-current-page 0) - (zero-show-candidates candidates))) + (funcall complete-func candidates))) (defun zero-convert-punctuation-basic (ch) "convert punctuation for *zero-punctuation-level-basic* @@ -323,7 +331,7 @@ 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" - (zero-build-candidates-async zero-preedit-str)) + (funcall zero-build-candidates-async-func zero-preedit-str 'zero-build-candidates-complete)) (defun zero-backspace-default () "handle backspace key in `*zero-state-im-preediting*' state" @@ -488,7 +496,7 @@ registered input method is saved in `zero-ims'" (if (not (member level (list *zero-punctuation-level-basic* *zero-punctuation-level-full* *zero-punctuation-level-none*))) - (error "level not supported: %s" level) + (error "Level not supported: %s" level) (setq zero-punctuation-level level))) (defun zero-set-punctuation-levels (levels) @@ -497,7 +505,7 @@ registered input method is saved in `zero-ims'" (if (not (member level (list *zero-punctuation-level-basic* *zero-punctuation-level-full* *zero-punctuation-level-none*))) - (error "level not supported: %s" level))) + (error "Level not supported: %s" level))) (setq zero-punctuation-levels levels)) (defun zero-cycle-punctuation-level () @@ -521,6 +529,9 @@ if im-name is nil, use default empty input method" (setq zero-build-candidates-func (or (cdr (assq :build-candidates im-functions)) 'zero-build-candidates-default)) + (setq zero-build-candidates-async-func + (or (cdr (assq :build-candidates-async im-functions)) + 'zero-build-candidates-async-default)) (setq zero-can-start-sequence-func (or (cdr (assq :can-start-sequence im-functions)) 'zero-can-start-sequence-default)) @@ -537,9 +548,10 @@ if im-name is nil, use default empty input method" (if (functionp init-func) (funcall init-func))) (set (make-local-variable 'zero-im) im-name)) - (error "input method %s not registered in zero" im-name))) + (error "Input method %s not registered in zero" im-name))) (zero-debug "using default empty input method") (setq zero-build-candidates-func 'zero-build-candidates-default) + (setq zero-build-candidates-async-func 'zero-build-candidates-async-default) (setq zero-can-start-sequence-func 'zero-can-start-sequence-default) (setq zero-handle-preedit-char-func 'zero-handle-preedit-char-default) (setq zero-get-preedit-str-for-panel-func 'zero-get-preedit-str-for-panel-default) diff --git a/zero-panel.el b/zero-panel.el index bb59298..741e060 100644 --- a/zero-panel.el +++ b/zero-panel.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- ;; provide emacs interface for zero-panel dbus service. ;;================ @@ -6,13 +7,22 @@ (require 'dbus) -(defun zero-panel-async-call (method handler &rest args) +(defun zero-panel-error-handler (event error) + "handle dbus errors" + (when (or (string-equal "com.emacsos.zero.Panel" + (dbus-event-interface-name event)) + (s-contains-p "com.emacsos.zero.Panel" (cadr error))) + (error "zero-panel dbus failed: %S" (cadr error)))) + +(add-hook 'dbus-event-error-functions 'zero-panel-error-handler) + +(defun zero-panel-async-call (method _handler &rest args) "call Method on zero-panel service asynchronously. This is a wrapper around `dbus-call-method-asynchronously'" (apply 'dbus-call-method-asynchronously :session "com.emacsos.zero.Panel" "/com/emacsos/zero/Panel" "com.emacsos.zero.Panel" - method nil args)) + method nil :timeout 500 args)) ;;============ ;; public API diff --git a/zero-pinyin-service.el b/zero-pinyin-service.el new file mode 100644 index 0000000..ee63b88 --- /dev/null +++ b/zero-pinyin-service.el @@ -0,0 +1,52 @@ +;; -*- lexical-binding: t -*- +;; provide emacs interface for zero-pinyin-service dbus service. + +;;================ +;; implementation +;;================ + +(require 'dbus) + +(defun zero-pinyin-service-error-handler (event error) + "handle dbus errors" + (when (or (string-equal "com.emacsos.zero.ZeroPinyinService" + (dbus-event-interface-name event)) + (s-contains-p "com.emacsos.zero.ZeroPinyinService" (cadr error))) + (error "zero-pinyin-service dbus failed: %S" (cadr error)))) + +(add-hook 'dbus-event-error-functions 'zero-pinyin-service-error-handler) + +(defun zero-pinyin-service-async-call (method handler &rest args) + "call Method on zero-pinin-service asynchronously. This is a wrapper around `dbus-call-method-asynchronously'" + (apply 'dbus-call-method-asynchronously + :session "com.emacsos.zero.ZeroPinyinService" + "/com/emacsos/zero/ZeroPinyinService" + "com.emacsos.zero.ZeroPinyinService" + method handler :timeout 1000 args)) + +(defun zero-pinyin-service-call (method &rest args) + "call Method on zero-pinin-service synchronously. This is a wrapper around `dbus-call-method'" + (apply 'dbus-call-method + :session "com.emacsos.zero.ZeroPinyinService" + "/com/emacsos/zero/ZeroPinyinService" + "com.emacsos.zero.ZeroPinyinService" + method :timeout 1000 args)) + +;;============ +;; public API +;;============ + +(defun zero-pinyin-service-get-candidates (preedit-str) + "get candidates for pinyin in preedit-str synchronously" + (zero-pinyin-service-call "GetCandidates" :string preedit-str)) + +(defun zero-pinyin-service-get-candidates-async (preedit-str get-candidates-complete) + "get candidates for pinyin in preedit-str asynchronously" + (zero-pinyin-service-async-call + "GetCandidates" get-candidates-complete :string preedit-str)) + +(defun zero-panel-quit () + "quit panel application" + (zero-pinyin-service-async-call "Quit" nil)) + +(provide 'zero-panel) diff --git a/zero-pinyin.el b/zero-pinyin.el index db7a663..7da9809 100644 --- a/zero-pinyin.el +++ b/zero-pinyin.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- ;; a pinyin input method for zero-framework ;;============== @@ -33,16 +34,26 @@ (make-local-variable 'zero-pinyin-state) (zero-pinyin-reset)) -(defun zero-pinyin-build-candidates (preedit-str) - (zero-pinyin-build-candidates-test preedit-str)) +(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-async (preedit-str) -;; "build candidate list, when done show it via `zero-pinyin-show-candidates'" -;; (zero-pinyin-debug "building candidate list\n") -;; (let ((candidates (zero-pinyin-build-candidates preedit-str))) -;; ;; update cache to make SPC and digit key selection possible. -;; (setq zero-pinyin-candidates candidates) -;; (zero-pinyin-show-candidates candidates))) +(defun zero-pinyin-build-candidates (preedit-str) + (if zero-pinyin--build-candidates-use-test-data + (zero-pinyin-build-candidates-test preedit-str) + (let ((result (zero-pinyin-service-get-candidates preedit-str))) + (setq zero-pinyin-used-preedit-str-lengths (second result)) + (first result)))) + +(defun zero-pinyin-build-candidates-async (preedit-str complete-func) + "build candidate list, when done call complete-func on it" + (zero-debug "building candidate list async\n") + (zero-pinyin-service-get-candidates-async + preedit-str + (lambda (candidates matched_preedit_str_lengths) + (setq zero-pinyin-used-preedit-str-lengths matched_preedit_str_lengths) + ;; Note: with dynamic binding, this command result in (void-variable + ;; complete-func) error. + (funcall complete-func candidates)))) (defun zero-pinyin-can-start-sequence (ch) "return t if char ch can start a preedit sequence." @@ -100,7 +111,7 @@ (setq zero-pinyin-pending-preedit-str (substring zero-pinyin-pending-preedit-str used-len)) (zero-pinyin-pending-preedit-str-changed) t)) - (t (error "unexpected zero-pinyin-state: %s" zero-pinyin-state)))))) + (t (error "Unexpected zero-pinyin-state: %s" zero-pinyin-state)))))) (defun zero-pinyin-commit-first-candidate-or-preedit-str () (unless (zero-pinyin-commit-nth-candidate 0) @@ -124,7 +135,7 @@ otherwise, just return nil" (zero-set-state *zero-state-im-waiting-input*) (zero-commit-text (concat zero-pinyin-pending-str candidate)) t)) - (t (error "unexpected zero-pinyin-state: %s" zero-pinyin-state)))))) + (t (error "Unexpected zero-pinyin-state: %s" zero-pinyin-state)))))) (defun zero-pinyin-handle-preedit-char (ch) "hanlde character insert in `*zero-state-im-preediting*' state. overrides `zero-handle-preedit-char-default'" @@ -171,6 +182,7 @@ otherwise, just return nil" (zero-register-im 'pinyin '((:build-candidates . zero-pinyin-build-candidates) + (: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) diff --git a/zero-quickdial.el b/zero-quickdial.el index fab7bb3..5e416db 100644 --- a/zero-quickdial.el +++ b/zero-quickdial.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- ;; a simple input method written as an emacs minor mode (defun zero-quickdial-insert-one () diff --git a/zero-reload-all.el b/zero-reload-all.el new file mode 100644 index 0000000..6412776 --- /dev/null +++ b/zero-reload-all.el @@ -0,0 +1,11 @@ +;; -*- no-byte-compile: t; -*- +(defun zero-reload-all () + (interactive) + (byte-recompile-directory "~/lisp/elisp/zero/" 0) + (dolist (f '("zero-quickdial.elc" + "zero-panel.elc" + "zero-framework.elc" + "zero-table.elc" + "zero-pinyin-service.elc" + "zero-pinyin.elc")) + (load-file f))) diff --git a/zero-table.el b/zero-table.el index 3dcf354..3f9d988 100644 --- a/zero-table.el +++ b/zero-table.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- ;; a simple input method written as an emacs minor mode ;; (load-file "~/lisp/elisp/zero/zero-panel.elc") ;; (load-file "~/lisp/elisp/zero/zero-framework.elc") -- GitLab