Newer
Older
;;; zero-input.el --- Zero Chinese input method framework -*- lexical-binding: t -*-
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; URL: https://gitlab.emacsos.com/sylecn/zero-el
;; Package-Version: 2.0.1
;; Package-Requires: ((emacs "24.3") (s "1.2.0"))
;;; Commentary:
;; zero-input.el is auto-generated from multiple other files. see
;; zero-input.el.in and build.py for details. It's created because
;; package-lint doesn't support multi-file package yet (issue #111).
;;
;; zero-input is a Chinese input method framework for Emacs, implemented as an
;; Emacs minor mode.
;;
;; zero-input-pinyin is bundled with zero, to use pinyin input method, add to
;; ~/.emacs file:
;;
;; (require 'zero-input-pinyin)
;; (zero-input-set-default-im 'pinyin)
;; ;; Now you may bind a key to zero-input-toggle to make it easy to
;; ;; switch on/off the input method.
;; (global-set-key (kbd "<f5>") 'zero-input-toggle)
;;
;; zero-input supports Chinese punctuation mapping. There are three modes,
;; none, basic, and full. The default is basic mode, which only map most
;; essential punctuations. You can cycle zero-punctuation-level in current
;; buffer by C-c , , You can change default Chinese punctuation level:
;;
;; (setq-default zero-input-punctuation-level
;; zero-input-punctuation-level-full)
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
;;
;; zero-input supports full-width mode. You can toggle full-width mode in
;; current buffer by C-c , . You can enable full-width mode by default:
;;
;; (setq-default zero-input-full-width-mode t)
;;
;;; Code:
(require 'dbus)
(eval-when-compile (require 'cl-lib))
(require 's)
;; body of zero-input-panel.el
;;================
;; implementation
;;================
(defun zero-input-panel-error-handler (event error)
"Handle dbus errors.
EVENT and ERROR are error-handler arguments."
(when (or (string-equal "com.emacsos.zero.Panel"
(dbus-event-interface-name event))
(s-contains-p "com.emacsos.zero.Panel" (cadr error)))
(error "Zero-Input-panel dbus failed: %S" (cadr error))))
(add-hook 'dbus-event-error-functions 'zero-input-panel-error-handler)
(defun zero-input-panel-async-call (method _handler &rest args)
"Call METHOD on zero-input-panel service asynchronously.
This is a wrapper around `dbus-call-method-asynchronously'.
ARGS optional extra args to pass to the wrapped function."
(apply 'dbus-call-method-asynchronously
:session
"com.emacsos.zero.Panel1" ; well known name
"/com/emacsos/zero/Panel1" ; object path
"com.emacsos.zero.Panel1.PanelInterface" ; interface name
method nil :timeout 500 args))
;;=========================
;; public utility function
;;=========================
(defun zero-input-alist-to-asv (hints)
"Convert Lisp alist to dbus a{sv} data structure.
HINTS should be an alist of form '((k1 [v1type] v1) (k2 [v2type] v2)).
For example,
\(zero-input-alist-to-asv
'((\"name\" \"foo\")
(\"timeout\" :int32 10)))
=>
'(:array
(:dict-entry \"name\" (:variant \"foo\"))
(:dict-entry \"timeout\" (:variant :int32 10)))"
(if (null hints)
'(:array :signature "{sv}")
(let ((result '(:array)))
(dolist (item hints)
(push (list :dict-entry (car item) (cons :variant (cdr item))) result))
(reverse result))))
;;============
;; public API
;;============
(defun zero-input-panel-move (x y)
"Move panel to specific coordinate (X, Y).
Origin (0, 0) is at screen top left corner."
(zero-input-panel-async-call "Move" nil :int32 x :int32 y))
(defun zero-input-panel-show-candidates (preedit_str candidate_length candidates &optional hints)
"Show CANDIDATES.
Argument PREEDIT_STR the preedit string.
Argument CANDIDATE_LENGTH how many candidates are in candidates list."
(zero-input-panel-async-call "ShowCandidates" nil
:string preedit_str
:uint32 candidate_length
(or candidates '(:array))
(zero-input-alist-to-asv hints)))
(defun zero-input-panel-show ()
"Show panel."
(zero-input-panel-async-call "Show" nil))
(defun zero-input-panel-hide ()
"Hide panel."
(zero-input-panel-async-call "Hide" nil))
(defun zero-input-panel-quit ()
"Quit panel application."
(interactive)
(zero-input-panel-async-call "Quit" nil))
(provide 'zero-input-panel)
;; body of zero-input-framework.el
;;==============
;; dependencies
;;==============
;;=======
;; utils
;;=======
;; this function is from ibus.el
(defun zero-input--ibus-compute-pixel-position (&optional pos window)
"Return geometry of object at POS in WINDOW as a list like \(X Y H).
X and Y are pixel coordinates relative to top left corner of frame which
WINDOW is in. H is the pixel height of the object.
Omitting POS and WINDOW means use current position and selected window,
respectively."
(let* ((frame (window-frame (or window (selected-window))))
(posn (posn-at-point (or pos (window-point window)) window))
(line (cdr (posn-actual-col-row posn)))
(line-height (and line
(or (window-line-height line window)
(and (redisplay t)
(window-line-height line window)))))
(x-y (or (posn-x-y posn)
(let ((geom (pos-visible-in-window-p
(or pos (window-point window)) window t)))
(and geom (cons (car geom) (cadr geom))))
'(0 . 0)))
(ax (+ (car (window-inside-pixel-edges window))
(car x-y)))
(ay (+ (cadr (window-pixel-edges window))
(or (nth 2 line-height) (cdr x-y))))
(height (or (car line-height)
(with-current-buffer (window-buffer window)
(cond
;; `posn-object-width-height' returns an incorrect value
;; when the header line is displayed (Emacs bug #4426).
((and posn
(null header-line-format))
(cdr (posn-object-width-height posn)))
((and (bound-and-true-p text-scale-mode)
(not (zerop (with-no-warnings
text-scale-mode-amount))))
(round (* (frame-char-height frame)
(with-no-warnings
(expt text-scale-mode-step
text-scale-mode-amount)))))
(t
(frame-char-height frame)))))))
(list ax ay height)))
(defun zero-input-get-point-position ()
Loading full blame...