Created
February 14, 2020 09:28
-
-
Save QiangF/5589c66f75506b338d6e817a232448e8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require 'cl-lib) | |
(require 'popup nil t) | |
(defface rime-prompt | |
'((t (:foreground "#ffff00" :background "gray44"))) | |
"选词框") | |
(defvar rime-title "中") | |
(defvar rime-probe-list | |
'(rime-probe-evil-normal-mode | |
rime-probe-program-mode | |
rime-probe-cn-en-switch)) | |
(defvar rime-local-variable-list | |
'(input-method-function | |
deactivate-current-input-method-function | |
rime-exhibit-timer | |
rime-translating | |
rime-output | |
rime-context)) | |
(dolist (var rime-local-variable-list) | |
(defvar var nil) | |
(make-variable-buffer-local var) | |
(put var 'permanent-local t)) | |
(defvar rime-auxiliary-map | |
(let ((map (make-sparse-keymap))) | |
(dolist (i (number-sequence 32 255)) | |
(define-key map (char-to-string i) 'rime-self-insert-command)) | |
(define-key map "\C-d" 'rime-input-delete-forward) | |
(define-key map "\C-h" 'rime-input-delete-backward) | |
(define-key map "\C-f" 'rime-input-forward-point) | |
(define-key map "\C-b" 'rime-input-backward-point) | |
(define-key map "\C-e" 'rime-input-end-of-line) | |
(define-key map "\C-a" 'rime-input-beginning-of-line) | |
(define-key map "\C-n" 'rime-prompt--next-word) | |
(define-key map "\C-p" 'rime-prompt--previous-word) | |
(define-key map "\M-n" 'rime-prompt--next-page) | |
(define-key map "\M-p" 'rime-prompt--previous-page) | |
map) | |
"serves as a lookup table, not used as a mode map") | |
(defun rime-probe-program-mode () | |
"中文输入限制在字符串和 comment 中" | |
(interactive) | |
(when (derived-mode-p 'prog-mode) | |
(let* ((ppss (syntax-ppss (point)))) | |
(not | |
(or (car (setq ppss (nthcdr 3 ppss))) | |
(car (setq ppss (cdr ppss))) | |
(nth 3 ppss)))))) | |
(defun rime-probe-evil-normal-mode () | |
(evil-normal-state-p)) | |
(defun rime-probe-cn-en-switch () | |
(unless (exwm-mode-buffer-p) | |
(let ((str-1 (rime-char-before-to-string 0)) | |
(str-2 (rime-char-before-to-string 1))) | |
;; exclude exwm mode buffer | |
(when str-1 | |
(if (rime-string-match-p " " str-1) | |
;; 中文后面紧接1个空格切换到英文输入 | |
(rime-string-match-p "\\cc" str-2) | |
;; 输入数字或英文标点等不经过输入法转换的字符 | |
;; 或强制输入英文字符后切换到英文输入 | |
(and (not (rime-string-match-p "\\cc" str-1)) | |
;; exclue punctuation | |
(not (looking-back "[[:punct:]]+")) | |
rime-context)))))) | |
(defun rime-english-context-p () | |
(cl-some #'(lambda (x) | |
(if (functionp x) (funcall x) nil)) | |
rime-probe-list)) | |
(defun rime-register-input-method () | |
(register-input-method "rime" "euc-cn" 'rime-activate rime-title)) | |
(defun rime-activate (name) | |
(interactive) | |
(mapc 'make-local-variable rime-local-variable-list) | |
(setq input-method-function 'rime-input-method) | |
(setq deactivate-current-input-method-function #'rime-deactivate) | |
(when (eq (selected-window) (minibuffer-window)) | |
(add-hook 'minibuffer-exit-hook 'rime-exit-from-minibuffer))) | |
(defun rime-deactivate () | |
(mapc 'kill-local-variable rime-local-variable-list)) | |
(defun rime-exit-from-minibuffer () | |
(deactivate-input-method) | |
(when (<= (minibuffer-depth) 1) | |
(remove-hook 'minibuffer-exit-hook 'rime-exit-from-minibuffer))) | |
(defun rime-input-method (key) | |
(if (or buffer-read-only | |
(not enable-multibyte-characters) | |
overriding-terminal-local-map | |
overriding-local-map) | |
(list key) | |
(with-silent-modifications | |
(unwind-protect | |
(let ((input-string (rime-start-translation key))) | |
(when (and (stringp input-string) | |
(> (length input-string) 0)) | |
(mapcar 'identity input-string))))))) | |
(defun rime-start-translation (key) | |
(let* ((echo-keystrokes 0) | |
(help-char nil) | |
(overriding-terminal-local-map rime-auxiliary-map) | |
(input-method-function nil) | |
(input-method-exit-on-first-char nil) | |
(buffer-undo-list t) | |
(input-method-use-echo-area nil) | |
(modified-p (buffer-modified-p)) | |
(inhibit-modification-hooks t) | |
(inhibit-quit t) | |
last-command-event last-command this-command result) | |
(setq rime-translating t) | |
(liberime-clear-composition) | |
;; Push back the last event on the event queue. | |
(and key (push key unread-command-events)) | |
(while rime-translating | |
(let* ((keyseq (read-key-sequence-vector nil nil nil t)) | |
(rime-cmd (lookup-key rime-auxiliary-map keyseq))) | |
(if (and (not (rime-english-context-p)) | |
(if rime-context | |
;; ignore command other than self-insert when composition is empty | |
(eq rime-cmd 'rime-self-insert-command) | |
(commandp rime-cmd))) | |
(progn | |
(set-buffer-modified-p modified-p) | |
(setq current-input-method-title rime-title) | |
(setq last-command-event (aref keyseq (1- (length keyseq))) | |
last-command this-command | |
this-command rime-cmd) | |
(condition-case-unless-debug err | |
(progn | |
(call-interactively rime-cmd) | |
(rime-prompt--refresh)) | |
(error (message "Input method error: %S" err) | |
(beep))) | |
(setq result rime-output)) | |
; keyseq doen't have any meaning in the context of the input method | |
(setq current-input-method-title "英") | |
(rime-quit-no-clear) | |
;; option 1: just return the keyseq string | |
(message "keyseq: %s rime-cmd: %s (rime-english-context-p): %s rime-context: %s" | |
keyseq rime-cmd (rime-english-context-p) rime-context) | |
(setq result (this-command-keys))))) | |
result)) | |
(defun rime-self-insert-command () | |
(interactive "*") | |
(liberime-process-key last-command-event) | |
(when (setq rime-output (liberime-get-commit)) | |
;; previous key is a commit key (space or number) | |
(rime-terminate))) | |
(defun rime-terminate () | |
(setq rime-translating nil) | |
(setq rime-output nil) | |
(when rime-exhibit-timer | |
(cancel-timer rime-exhibit-timer)) | |
(setq rime-context nil) | |
(liberime-clear-composition)) | |
(defun rime-prompt--refresh () | |
;; Show page. | |
(when (and (null unread-command-events) | |
(null unread-post-input-method-events)) | |
;; update context | |
(setq rime-context (liberime-get-context)) | |
(liberime-commit-composition) | |
(message "%s" rime-context) | |
(if (eq (selected-window) (minibuffer-window)) | |
;; minibuffer 中输入中文时,使用当前输入的下一行来显示候选词。 | |
(rime-prompt--minibuffer-message | |
(concat "\n" (rime-prompt--format-prompt))) | |
;; 普通 buffer | |
(let ((message-log-max nil)) | |
(cond | |
;; exwm-xim uses " *temp*" buffer for input, page should be showed in minibuffer. | |
((equal (buffer-name) " *temp*") | |
(message (rime-prompt--format-prompt))) | |
(t | |
(popup-tip (rime-prompt--format-prompt) | |
:point (point) | |
:margin 1))))))) | |
(defun rime-prompt--minibuffer-message (string) | |
"minibuffer 中需要将原来显示的信息和选词框整合在一起显示" | |
(message nil) | |
(let ((inhibit-quit t) | |
point-1) | |
(save-excursion | |
(insert string) | |
(setq point-1 (point))) | |
(sit-for 1000000) | |
(delete-region (point) point-1) | |
(when quit-flag | |
(setq quit-flag nil | |
unread-command-events '(7))))) | |
(defun rime-prompt--create-candidate-list (candidates index) | |
"这个函数用于创建在 page 中显示的备选词条菜单。" | |
(let ((i 0) | |
result) | |
(dolist (candidate candidates) | |
(when (> i 0) | |
(push " " result)) | |
;; 高亮当前选择的词条 | |
(push (if (= i index) | |
(propertize (format "[%d.%s]" (1+ i) candidate) | |
'face 'rime-prompt) | |
(format "%d.%s" (1+ i) candidate)) | |
result) | |
(setq i (1+ i))) | |
(mapconcat #'identity (reverse result) ""))) | |
(defun rime-prompt--format-prompt () | |
(let* ((composition (alist-get 'composition rime-context)) | |
(menu (alist-get 'menu rime-context)) | |
(page-no (alist-get 'page-no menu)) | |
(index (alist-get 'highlighted-candidate-index menu)) | |
(candidates (alist-get 'candidates menu))) | |
(format "%s\n%s" | |
(alist-get 'preedit composition) | |
(rime-prompt--create-candidate-list candidates index)))) | |
(defun rime-input-forward-point () | |
(interactive) | |
;; send right | |
(liberime-process-key 39)) | |
(defun rime-input-backward-point () | |
(interactive) | |
;; send left | |
(liberime-process-key 37)) | |
(defun rime-input-end-of-line () | |
(interactive) | |
;; send end | |
(liberime-process-key 35)) | |
(defun rime-input-beginning-of-line () | |
(interactive) | |
;; send home | |
(liberime-process-key 36)) | |
(defun rime-input-delete-backward (&optional n) | |
(interactive) | |
;; send backspace | |
(liberime-process-key 8)) | |
(defun rime-input-delete-forward () | |
"在rime-preedit中向前删除1个字符" | |
(interactive) | |
;; send delete | |
(liberime-process-key 127)) | |
(defun rime-prompt--next-page (arg) | |
(interactive) | |
(liberime-process-key 34)) | |
(defun rime-prompt--previous-page (arg) | |
(interactive) | |
(liberime-process-key 33)) | |
(defun rime-prompt--next-word (arg) | |
(interactive) | |
;; send down | |
(liberime-process-key 40)) | |
(defun rime-prompt--previous-word (arg) | |
(interactive) | |
;; send up | |
(liberime-process-key 38)) | |
(add-hook 'emacs-startup-hook 'rime-register-input-method) | |
(rime-register-input-method) | |
(provide 'rime) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment