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

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
......
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