今天下午看狗哥的 Meow ,发现其理念中有一条是极力避免 Ctrl Meta 等键。最近写代码的时候我的小拇指有一点痛,忽然就有了这个想法。
现在已经有了各种各样的模式编辑插件,解决了总是按 Ctrl Meta 等键 90% 的问题,但还有 9% 则是各种 minibuffer 导致的,一般的模式编辑里都默认在 minibuffer 中不启用。
我今天为我的 Sniem 加上了一个新模式 minibuffer-keypad-mode
,它可以让用户在 minibuffer 下依旧不需要使用 Ctrl 等按键。先放图:
使用方法就是,默认打开是输入状态,按空格后接内容也就是普通输入空格后再插入文字。按两次空格就进入或者退出 keypad 模式;可以用 ,
.
/
进行切换快捷键前缀,,
是 C-
、.
是 M-
、/
是 C-M-
,如果输入的那个字符所对应的前缀和当前前缀相同,就直接输入;否则切换当前前缀。
该模式实现很容易,就是把空格绑定一个函数,用来开关 minibuffer 下的 keypad 模式,代码如下:
(defun sniem-minibuffer-keypad-start-or-stop ()
"Start or stop the minibuffer-keypad mode."
(interactive)
(self-insert-command 1 32)
(let ((char (read-char))
command)
(if (= 32 char)
(progn
(setq-local sniem-minibuffer-keypad-on ;这个变量用于检测 keypad 模式是否打开,要自己加
(if sniem-minibuffer-keypad-on
nil
t))
(call-interactively (key-binding (read-kbd-macro (char-to-string 127)))))
(if (and sniem-minibuffer-keypad-on
(memq char '(44 46 47)))
(progn
(setq-local sniem-minibuffer-keypad-prefix
(sniem-keypad--convert-prefix char))
(call-interactively (key-binding (read-kbd-macro (char-to-string 127)))))
(execute-kbd-macro (vector char))))))
其它所有输入按键都绑定的是另一个函数:
(defun sniem-minibuffer-keypad ()
"The function to insert the input key or execute the function."
(interactive)
(if sniem-minibuffer-keypad-on
(sniem-keypad last-input-event)
(self-insert-command 1)))
这个函数用于正常输入或者调用 sniem-keypad 进行按键操作。
然后就是 sniem-keypad
function
(defun sniem-keypad (&optional external-char)
"Execute the keypad command.
EXTERNAL-CHAR is the entrance for minibuffer-keypad mode."
(interactive)
(let ((key (if external-char
(when (and (memq external-char '(44 46 47))
(/= (sniem-keypad--convert-prefix
sniem-minibuffer-keypad-prefix)
external-char))
(setq-local sniem-minibuffer-keypad-prefix ;这个变量要自己加
(sniem-keypad--convert-prefix external-char))
(setq external-char t))
(pcase last-input-event
(109 "M-") (98 "C-M-") (118 "C-"))))
tmp command prefix-used-p)
(unless (stringp key)
(setq key (if external-char
(concat sniem-minibuffer-keypad-prefix
(when (numberp external-char)
(concat (char-to-string external-char) " ")))
(concat "C-" (char-to-string last-input-event) " "))))
(message key)
(catch 'stop
(when (and (numberp external-char)
(commandp (setq command (key-binding (read-kbd-macro (substring key 0 -1))))))
(throw 'stop nil))
(while (setq tmp (read-char))
(if (= tmp 127)
(setq key (substring key 0 -2))
(when (= tmp 59)
(keyboard-quit))
(setq key (concat key
(cond ((and (= tmp 44)
(null prefix-used-p))
(setq prefix-used-p t)
"C-")
((and (= tmp 46)
(null prefix-used-p))
(setq prefix-used-p t)
"M-")
((and (= tmp 47)
(null prefix-used-p))
(setq prefix-used-p t)
"C-M-")
(t
(when prefix-used-p
(setq prefix-used-p nil))
(concat (char-to-string tmp) " "))))))
(message key)
(when (commandp (setq command (key-binding (read-kbd-macro (substring key 0 -1)))))
(throw 'stop nil))))
(call-interactively command)))
这个函数是我写 Sniem 之前看到 Meow 有这个功能后实现的,当时用的是函数写得,现在发现用函数给我省去了不少时间。不过目前还需要修改。
还有获取对应前缀的函数:
(defun sniem-keypad--convert-prefix (prefix)
"Convert PREFIX from string to char or from char to string."
(let* ((prefix-string '("C-" "M-" "C-M-"))
(prefix-char '(44 46 47))
(from (if (stringp prefix)
prefix-string
prefix-char))
(to (if (stringp prefix)
prefix-char
prefix-string))
index)
(setq index (sniem--index prefix from))
(when index
(nth index to))))
现在是解决了 99% 的问题了,剩下的就是 EAF 和输入法导致的了,目前我还没办法解决。