Commit f281fb16 authored by Yuanle Song's avatar Yuanle Song

v2.2.0 support auto convert 1。3 to 1.3.

This feature is enabled by default.
To turn off this feature,

  (setq zero-input-auto-fix-dot-between-numbers nil)
parent 5c7782c3
......@@ -100,6 +100,106 @@ 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-02 zero-el: 如果输入“。”之前和之后输入的是数字,则自动将"。"转换为小数点"."。
(setq zero-input-auto-fix-dot-between-numbers t)
enabled by default.
- is it easy to implement in elisp?
try it in self-insert-command hook.
post-self-insert-hook
(add-hook 'post-self-insert-hook #'t1-replace-chinese-dot-maybe nil t)
see ~/lisp/elisp/testing-only/auto-fix-typing-via-self-insert-command-hook.el
it works.
when I type 1a3 it will insert 1.3.
- I think this can probably work outside zero-input.
nope. zero doesn't use self-insert-command for inserting Chinese dot.
what does it use?
zero-input-pinyin-handle-preedit-char
it should be easy to implement the same thing there.
- when commit digit, just also add digit in a ring buffer. and check whether
there is a Chinese dot to be replaced.
- when commit Chinese dot, add Chinese dot in a ring buffer.
// These digits and Chinese dot is not part of key IM logic.
// zero-input-can-start-sequence will return false for them.
// I don't even need to change zero-input-commit-text.
- put the feature under a flag.
zero-input-auto-fix-dot-between-numbers
- problems
- how to get last insert char?
- how to get last 3 char from a string?
(equal (substring "abcde" -3) "cde")
(equal (substring "abc" -3) "abc")
(equal (substring "ab" -3) "ab")
how to loop characters over a string?
(mapcar (lambda (ch) ch) "abc")
- in elisp, use #'(lambda (x) x) or (lambda (x) x)?
Anonymous Functions - GNU Emacs Lisp Reference Manual
https://www.gnu.org/software/emacs/manual/html_node/elisp/Anonymous-Functions.html
use #' is better. it is short for (function (lambda (x) ...)).
- DONE return key should also insert ?\n to ring buffer.
bug reproduce:
type
25。<ret>
6
it is converted to
25。.6
where is return key handled when not in preedit mode?
debug log:
user typed: .
cannot start sequence, state=IM_WAITING_INPUT
press <ret> doesn't get any debug output.
ret is handled here:
(define-key zero-input-mode-map (kbd "RET") 'zero-input-return)
(define-key zero-input-mode-map (kbd "RET") nil)
When not in preedit-mode, I use system default self-insert-command binding
for RET key. So I still need the hook.
(add-hook 'post-self-insert-hook #'zero-input-post-self-insert nil t)
- when I do this, digit key press will insert twice into ring.
fixed. only use post-self-insert-hook, drop my explicit call.
- when type 。 it is not added to ring buf.
// it is added, just doesn't have debug log. because it uses mapc to add ch
// to ring.
The hook function should handle auto fix Chinese dot in digits.
now it works.
- WONTFIX backspace should update ring buffer. Oh, I can't restore old char.
just remove the newest item in the ring buffer.
e.g. 1<backspace>。6 should not be converted to ".6".
(define-key zero-input-mode-map (kbd "<backspace>") 'zero-input-backspace)
// I don't do anything here. auto fix doesn't work with preedit mode.
(define-key zero-input-mode-map (kbd "<backspace>") nil)
backspace doesn't run self-insert-command in many major modes.
There is nothing I can do.
Is there a hook I can use?
delete-char
- DONE only do auto fix when zero-input-mode is on.
- DONE when zero is off, clear the ring buffer.
do it in zero-input-reset.
** 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?
......
......@@ -34,7 +34,8 @@
;; dependencies
;;==============
(eval-when-compile (require 'cl-lib))
(eval-when-compile (require 'cl-lib) (require 'cl-macs))
(require 'ring)
(require 's)
(require 'zero-input-panel)
......@@ -132,7 +133,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.1.0")
(setq zero-input-version "2.2.0")
;; FSM state
(defconst zero-input--state-im-off 'IM-OFF)
......@@ -186,6 +187,15 @@ Otherwise, next double quote insert close quote.")
Used when converting single quote to Chinese quote.
If nil, next single quote insert open quote.
Otherwise, next single quote insert close quote.")
(defvar-local zero-input-recent-insert-chars (make-ring 3)
"Store recent insert characters.
Used to handle Chinese dot in digit input.
e.g. 1。3 could be converted to 1.3.")
(defcustom zero-input-auto-fix-dot-between-numbers t
"Non-nil means zero should change 1。3 to 1.3."
:group 'zero
:type 'boolean)
(defvar-local zero-input-preedit-str "")
(defvar-local zero-input-candidates nil)
(defcustom zero-input-candidates-per-page 10
......@@ -269,6 +279,12 @@ STRING and OBJECTS are passed to `format'"
;; (zero-input-debug "msg3: %s\n" 24)
;; (zero-input-debug "msg4: %s %s\n" 24 1)
(defun zero-input-add-recent-insert-char (ch)
"Insert CH to `zero-input-recent-insert-chars'."
;; (cl-assert (and (characterp ch) (not (stringp ch))))
(zero-input-debug "add char to recent chars ring: %s\n" ch)
(ring-insert zero-input-recent-insert-chars ch))
(defun zero-input-enter-preedit-state ()
"Config keymap when enter preedit state."
(zero-input-enable-preediting-map)
......@@ -385,6 +401,7 @@ If there is no full-width char for CH, return it unchanged."
(when zero-input-full-width-p
(let ((full-width-ch (zero-input-convert-ch-to-full-width ch)))
(insert full-width-ch)
(zero-input-add-recent-insert-char full-width-ch)
full-width-ch)))
(defun zero-input-convert-punctuation-basic (ch)
......@@ -437,6 +454,7 @@ Return CH's Chinese punctuation if CH is converted. Return nil otherwise."
(let ((str (zero-input-convert-punctuation ch)))
(when str
(insert str)
(mapc #'zero-input-add-recent-insert-char str)
t)))
(defun zero-input-append-char-to-preedit-str (ch)
......@@ -480,11 +498,11 @@ Return CH's Chinese punctuation if CH is converted. Return nil otherwise."
(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))))
#'(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)
......@@ -554,10 +572,10 @@ N is the argument passed to `self-insert-command'."
(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)))))
#'(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."
......@@ -582,6 +600,9 @@ N is the argument passed to `self-insert-command'."
"Commit given TEXT, reset preedit str, hide candidate list."
(zero-input-debug "commit text: %s\n" text)
(insert text)
;; insert last 3 characters (if possible) to zero-input-recent-insert-chars
(mapc #'zero-input-add-recent-insert-char
(if (>= (length text) 3) (substring text -3) text))
(setq zero-input-preedit-str "")
(setq zero-input-candidates nil)
(setq zero-input-current-page 0)
......@@ -629,6 +650,8 @@ N is the argument passed to `self-insert-command'."
(setq zero-input-preedit-str "")
(setq zero-input-candidates nil)
(setq zero-input-current-page 0)
(while (not (ring-empty-p zero-input-recent-insert-chars))
(ring-remove zero-input-recent-insert-chars))
(zero-input-hide-candidate-list))
(defun zero-input-focus-in ()
......@@ -707,8 +730,27 @@ Otherwise, show Zero."
(add-hook 'focus-in-hook 'zero-input-focus-in)
(add-hook 'focus-out-hook 'zero-input-focus-out)
(setq zero-input-buffer (current-buffer))
(add-hook 'post-self-insert-hook #'zero-input-post-self-insert-command nil t)
(add-hook 'buffer-list-update-hook 'zero-input-buffer-list-changed))
(defun zero-input-post-self-insert-command (&optional ch)
"Run after a regular `self-insert-command' is run by zero-input.
Argument CH the character that was inserted."
;; `zero-input-auto-fix-dot-between-numbers' is the only feature that
;; requires this ring, so for now if it is nil, no need to maintain the ring
;; for `self-insert-command'.
(if (and zero-input-mode zero-input-auto-fix-dot-between-numbers)
(let ((ch (or ch (elt (this-command-keys-vector) 0))))
(zero-input-add-recent-insert-char ch)
;; if user typed digit “。” digit, auto convert “。” to “.”
(cl-flet ((my-digit-char-p (ch) (and (>= ch ?0) (<= ch ?9))))
(when (and (my-digit-char-p (ring-ref zero-input-recent-insert-chars 0))
(equal ? (ring-ref zero-input-recent-insert-chars 1))
(my-digit-char-p (ring-ref zero-input-recent-insert-chars 2)))
(delete-char -2)
(insert "." (car (ring-elements zero-input-recent-insert-chars))))))))
;;==================
;; IM developer API
;;==================
......
......@@ -29,6 +29,7 @@
;; dependencies
;;==============
(require 'ring)
(require 'zero-input-framework)
(require 'zero-input-pinyin-service)
......@@ -67,7 +68,7 @@ You can find the xml file locally at
(defvar zero-input-pinyin-pending-str "")
(defvar zero-input-pinyin-pending-preedit-str "")
(defvar zero-input-pinyin-pending-pinyin-indices nil
"Stores `zero-input-pinyin-pending-str' corresponds pinyin indices.")
"Store `zero-input-pinyin-pending-str' corresponds pinyin indices.")
;;=====================
;; key logic functions
......@@ -123,14 +124,14 @@ COMPLETE-FUNC the callback function when async call completes. it's called with
(zero-input-pinyin-service-get-candidates-async
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)
;; Note: with dynamic binding, this command result in (void-variable
;; complete-func) error.
(funcall complete-func candidates))))
#'(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)
;; Note: with dynamic binding, this command result in (void-variable
;; complete-func) error.
(funcall complete-func candidates))))
(defun zero-input-pinyin-can-start-sequence (ch)
"Return t if char CH can start a preedit sequence."
......@@ -268,8 +269,8 @@ This is different from zero-input-framework because I need to support partial co
(zero-input-pinyin-build-candidates-unified
preedit-str
new-fetch-size
(lambda (_candidates)
(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))))
......
......@@ -50,7 +50,7 @@
(defun zero-input-table-build-candidates (preedit-str &optional _fetch-size)
"Build candidates by looking up PREEDIT-STR in `zero-input-table-table'."
(mapcar 'cdr (sort (cl-remove-if-not (lambda (pair) (string-prefix-p preedit-str (car pair))) zero-input-table-table) 'zero-input-table-sort-key)))
(mapcar 'cdr (sort (cl-remove-if-not #'(lambda (pair) (string-prefix-p preedit-str (car pair))) zero-input-table-table) 'zero-input-table-sort-key)))
;; (defun zero-input-table-build-candidates-async (preedit-str)
;; "build candidate list, when done show it via `zero-input-table-show-candidates'"
......@@ -92,7 +92,7 @@ To use demo data, you can call:
(\"address\" . \"123 Happy Street\")))"
(setq zero-input-table-table alist)
(setq zero-input-table-sequence-initials
(delete-dups (mapcar (lambda (pair) (substring (car pair) 0 1))
(delete-dups (mapcar #'(lambda (pair) (substring (car pair) 0 1))
zero-input-table-table))))
(provide 'zero-input-table)
......
......@@ -12,7 +12,7 @@
;; See the License for the specific language governing permissions and
;; limitations under the License.
;; Version: 2.1.0
;; Version: 2.2.0
;; URL: https://gitlab.emacsos.com/sylecn/zero-el
;; Package-Requires: ((emacs "24.3") (s "1.2.0"))
......@@ -51,7 +51,10 @@
;;; Code:
(require 'dbus)
(eval-when-compile (require 'cl-lib))
(eval-when-compile
(require 'cl-lib)
(require 'cl-macs))
(require 'ring)
(require 's)
;; body of zero-input-panel.el
......@@ -243,7 +246,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.1.0")
(setq zero-input-version "2.2.0")
;; FSM state
(defconst zero-input--state-im-off 'IM-OFF)
......@@ -297,6 +300,15 @@ Otherwise, next double quote insert close quote.")
Used when converting single quote to Chinese quote.
If nil, next single quote insert open quote.
Otherwise, next single quote insert close quote.")
(defvar-local zero-input-recent-insert-chars (make-ring 3)
"Store recent insert characters.
Used to handle Chinese dot in digit input.
e.g. 1。3 could be converted to 1.3.")
(defcustom zero-input-auto-fix-dot-between-numbers t
"Non-nil means zero should change 1。3 to 1.3."
:group 'zero
:type 'boolean)
(defvar-local zero-input-preedit-str "")
(defvar-local zero-input-candidates nil)
(defcustom zero-input-candidates-per-page 10
......@@ -380,6 +392,12 @@ STRING and OBJECTS are passed to `format'"
;; (zero-input-debug "msg3: %s\n" 24)
;; (zero-input-debug "msg4: %s %s\n" 24 1)
(defun zero-input-add-recent-insert-char (ch)
"Insert CH to `zero-input-recent-insert-chars'."
;; (cl-assert (and (characterp ch) (not (stringp ch))))
(zero-input-debug "add char to recent chars ring: %s\n" ch)
(ring-insert zero-input-recent-insert-chars ch))
(defun zero-input-enter-preedit-state ()
"Config keymap when enter preedit state."
(zero-input-enable-preediting-map)
......@@ -496,6 +514,7 @@ If there is no full-width char for CH, return it unchanged."
(when zero-input-full-width-p
(let ((full-width-ch (zero-input-convert-ch-to-full-width ch)))
(insert full-width-ch)
(zero-input-add-recent-insert-char full-width-ch)
full-width-ch)))
(defun zero-input-convert-punctuation-basic (ch)
......@@ -548,6 +567,7 @@ Return CH's Chinese punctuation if CH is converted. Return nil otherwise."
(let ((str (zero-input-convert-punctuation ch)))
(when str
(insert str)
(mapc #'zero-input-add-recent-insert-char str)
t)))
(defun zero-input-append-char-to-preedit-str (ch)
......@@ -591,11 +611,11 @@ Return CH's Chinese punctuation if CH is converted. Return nil otherwise."
(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))))
#'(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)
......@@ -665,10 +685,10 @@ N is the argument passed to `self-insert-command'."
(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)))))
#'(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."
......@@ -693,6 +713,9 @@ N is the argument passed to `self-insert-command'."
"Commit given TEXT, reset preedit str, hide candidate list."
(zero-input-debug "commit text: %s\n" text)
(insert text)
;; insert last 3 characters (if possible) to zero-input-recent-insert-chars
(mapc #'zero-input-add-recent-insert-char
(if (>= (length text) 3) (substring text -3) text))
(setq zero-input-preedit-str "")
(setq zero-input-candidates nil)
(setq zero-input-current-page 0)
......@@ -740,6 +763,8 @@ N is the argument passed to `self-insert-command'."
(setq zero-input-preedit-str "")
(setq zero-input-candidates nil)
(setq zero-input-current-page 0)
(while (not (ring-empty-p zero-input-recent-insert-chars))
(ring-remove zero-input-recent-insert-chars))
(zero-input-hide-candidate-list))
(defun zero-input-focus-in ()
......@@ -818,8 +843,27 @@ Otherwise, show Zero."
(add-hook 'focus-in-hook 'zero-input-focus-in)
(add-hook 'focus-out-hook 'zero-input-focus-out)
(setq zero-input-buffer (current-buffer))
(add-hook 'post-self-insert-hook #'zero-input-post-self-insert-command nil t)
(add-hook 'buffer-list-update-hook 'zero-input-buffer-list-changed))
(defun zero-input-post-self-insert-command (&optional ch)
"Run after a regular `self-insert-command' is run by zero-input.
Argument CH the character that was inserted."
;; `zero-input-auto-fix-dot-between-numbers' is the only feature that
;; requires this ring, so for now if it is nil, no need to maintain the ring
;; for `self-insert-command'.
(if (and zero-input-mode zero-input-auto-fix-dot-between-numbers)
(let ((ch (or ch (elt (this-command-keys-vector) 0))))
(zero-input-add-recent-insert-char ch)
;; if user typed digit “。” digit, auto convert “。” to “.”
(cl-flet ((my-digit-char-p (ch) (and (>= ch ?0) (<= ch ?9))))
(when (and (my-digit-char-p (ring-ref zero-input-recent-insert-chars 0))
(equal ? (ring-ref zero-input-recent-insert-chars 1))
(my-digit-char-p (ring-ref zero-input-recent-insert-chars 2)))
(delete-char -2)
(insert "." (car (ring-elements zero-input-recent-insert-chars))))))))
;;==================
;; IM developer API
;;==================
......@@ -1007,7 +1051,7 @@ if IM-NAME is nil, use default empty input method"
(defun zero-input-table-build-candidates (preedit-str &optional _fetch-size)
"Build candidates by looking up PREEDIT-STR in `zero-input-table-table'."
(mapcar 'cdr (sort (cl-remove-if-not (lambda (pair) (string-prefix-p preedit-str (car pair))) zero-input-table-table) 'zero-input-table-sort-key)))
(mapcar 'cdr (sort (cl-remove-if-not #'(lambda (pair) (string-prefix-p preedit-str (car pair))) zero-input-table-table) 'zero-input-table-sort-key)))
;; (defun zero-input-table-build-candidates-async (preedit-str)
;; "build candidate list, when done show it via `zero-input-table-show-candidates'"
......@@ -1049,7 +1093,7 @@ To use demo data, you can call:
(\"address\" . \"123 Happy Street\")))"
(setq zero-input-table-table alist)
(setq zero-input-table-sequence-initials
(delete-dups (mapcar (lambda (pair) (substring (car pair) 0 1))
(delete-dups (mapcar #'(lambda (pair) (substring (car pair) 0 1))
zero-input-table-table))))
(provide 'zero-input-table)
......@@ -1198,7 +1242,7 @@ You can find the xml file locally at
(defvar zero-input-pinyin-pending-str "")
(defvar zero-input-pinyin-pending-preedit-str "")
(defvar zero-input-pinyin-pending-pinyin-indices nil
"Stores `zero-input-pinyin-pending-str' corresponds pinyin indices.")
"Store `zero-input-pinyin-pending-str' corresponds pinyin indices.")
;;=====================
;; key logic functions
......@@ -1254,14 +1298,14 @@ COMPLETE-FUNC the callback function when async call completes. it's called with
(zero-input-pinyin-service-get-candidates-async
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)
;; Note: with dynamic binding, this command result in (void-variable
;; complete-func) error.
(funcall complete-func candidates))))
#'(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)
;; Note: with dynamic binding, this command result in (void-variable
;; complete-func) error.
(funcall complete-func candidates))))
(defun zero-input-pinyin-can-start-sequence (ch)
"Return t if char CH can start a preedit sequence."
......@@ -1399,8 +1443,8 @@ This is different from zero-input-framework because I need to support partial co
(zero-input-pinyin-build-candidates-unified
preedit-str
new-fetch-size
(lambda (_candidates)
(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))))
......
......@@ -51,7 +51,10 @@
;;; Code:
(require 'dbus)
(eval-when-compile (require 'cl-lib))
(eval-when-compile
(require 'cl-lib)
(require 'cl-macs))
(require 'ring)
(require 's)
INCLUDE_ZERO_INPUT_PANEL_EL
......
Markdown is supported
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