(use-package osx-dictionary
:bind
("C-c d d" . osx-dictionary-search-word-at-point)
)
(use-package emacs
:ensure nil
:defer t
:bind
(
("C-c d" . duplicate-dwim)
)
)
以上设置会报错:
error: Key sequence C-c d d starts with non-prefix key C-c d
设置一个 ctl-c-d-map
是不是可以解决问题呢?求大佬指点迷津。感谢感谢 ![:pray: :pray:](https://emacs-china.org/images/emoji/apple/pray.png?v=12)
C-c d 绑定一个命令, 这个命令做两件事情, 一个是等用户输入字符 (read-char), 同时加一个0.5s 的计时器。
如果计时器到了就执行 C-c d 的命令, 如果计时器还没有结束, 就执行 read-char 对应的命令。
3 个赞
不知道 Emacs 中有没有类似 Vim 的递归映射/非递归映射。
很久没用 Vim 了,也不记得自己设置过这样拧巴/奇葩的俩快捷键,不过感觉这样可以“复用”快捷键的一部分的思路有点搞头。
如果最后两个按键的时间间隔(interval)以及最后一个按键和快捷键生效前的时间间隔(timeout)都是可调的话,那就完全不需要单独定义一个 prefix-map 了。
哇,这个思路简洁优美!
如果 Emacs 有按键间隔和 timeout 的概念就好了。
谢谢猫大 ![:pray: :pray:](https://emacs-china.org/images/emoji/apple/pray.png?v=12)
我是狗熊啃棒子型的,我再学学怎么把这个功能写出来。
general可以很方便地绑 C-c d d
& C-c d e
,和你的想法略有区别。不过还是多按个键比等0.5秒更快更可靠吧?
以上描述有点问题,详见general-key-dispatch
我后来又翻了不少帖子,查了一些资料,最后还是放弃了。
不是 timeout 大小的问题,也不是代码多难学多难写的问题,而是理念问题。
如果要实现“前缀”复用(随手起的名字),即让不同的 key sequence 具有相同的“前缀”,就需要把每个 sequence 的“前缀”部分变成一个特殊的 keymap/keyboard-macro。也就是要考虑所有按键序列和单个按键是不是都是特殊的 keymap/macro。
如果 Emacs 默认所有的按键序列中的每个按键都是一棵树上的分支,那么只需要一个 timeout 作为分支的末端标记点就够了,但现实情况是 Emacs 没有这么做。
如你所说,还不如利用目前可以写进 keymap 的键。
所以我今天也进行了一些快捷键的调整,摸索适合自己的键序列。
我一开始想的是如何避免 Emacs 递归映射,结果最后发现恰恰是因为 Emacs 缺少递归。
比如 ESC a
只绑定了 backward-sentence
而不是作为 esc-a-map 的 timeout, ESC e
只绑定了 fowward-sentence
而不是作为 esc-e-map 的 timeout,相当于这条路堵死了(或者说这里本来就是断头路)。
不是程序员,看不太懂 ![:rofl: :rofl:](https://emacs-china.org/images/emoji/apple/rofl.png?v=12)
做为可扩展性最强的编辑器,key sequence 里居然有断头路,这是最让我百思不得其解的。
主要是想不通 key sequence 如何判断自己已经结束了该去执行对应的 command,如果能够参与控制 key sequence 何时结束问题就简单了。猫大的思路可以解决一部分问题,最根本的问题是断头路修起来太费劲了。
timeout我试过,不太好用,我试的是“esc和其它键一起按就当作ctrl,0.5s内没有别的键被按下就发送esc”,试下来很不好用,0.5s还是0.2s这个thresh很难定,要么你等它,要么它等你,很难受。
但是我这个如果能成功还是很有用的,节约一个物理按键。键盘大小是有限的。
而你这个情况,意义不大,只节约出一个短sequence,能给C-c d
单独一个按键,这个目的你不用timeout,直接在C-c a x
这里多挤一个就能把C-c d
省出来。
至于到底哪个该用更短的键,可以用keyfreq统计自己1周/1个月每个键都按了几次
1 个赞
timeout 是任何一个无法做到全键无冲的键盘或者映射软件都有的特性,而 emacs 的 key sequen 是一颗树,只需要让它无限分叉,最后一个按键是终点,比如 C-c M-k 其实是 C-c 之后单独按下 ESC 和 k 之后 Emacs 读取的最后结果,这三次按键中间的两个间隔可以是不固定(一直等待终点按键的出现)的。
我之前在不知道 doom 是把 短时间连按 jk 作为esc在的功能在 vterm 模式禁掉了,所以以为是在 vterm 实现不了。就自己在 vterm 里糊了一个类似的功能的函数。这样子做的好处就是按 j 的时间不会卡住,而是会立即输入字母 j,然后短时间内按 k 就会退出插入模式;然后把之前的 j 给删掉。我在 vim 里面甚至也是这么配置的;而并没有利用vim支持的原生的递归映射。因为 vim 的原生递归映射会导致你按j的那一瞬间会卡0.1秒,直到你在这个时间内没有按 k,才会输入 j 字符。
我的 lisp 水平很垃圾,就是单纯的纯粹纸糊的水平。能达成功能就完事。
(defun my-vterm-k-as-switch-to-normal-state ()
"send backspace firstly (to delete char ?j previously inserted) and then switch to normal state."
(interactive)
(vterm-send-backspace)
(evil-force-normal-state))
(defun my-vterm-j-set-k-as-switch-to-normal-state ()
"After inserting ?j, map ?k to `my-vterm-k-as-switch-to-normal-state',
and after 0.1s to map ?k to its default: `vterm--self-insert'"
(interactive)
(vterm--self-insert)
(map! :map vterm-mode-map :i "k" #'my-vterm-k-as-switch-to-normal-state)
(run-with-idle-timer 0.1 nil
(lambda ()
(map! :map vterm-mode-map :i "k" #'vterm--self-insert))))
(after! vterm
(map! :map vterm-mode-map
:i "C-c <escape>" #'vterm-send-escape
:i "j" #'my-vterm-j-set-k-as-switch-to-normal-state))
Vim 的小毛病太多了,j k 转 esc 都有人专门写插件优化……
促使我转 Emacs 的第一个原因就是 Vim 记录按键历史的方法很脏很傻,不像 Emacs 插件 keyfreq 短短五六百行代码实现了很多功能。
原来还能删掉再esc来避免等它!那楼主的需求就也可以这么实现
对的, 把我这个纸糊的函数稍微改一下就可以实现递归映射了。
没看明白怎么实现,我的理解是 Emacs key sequence 没有 timeout 只有 prefix,而 C-c d
不能在作为 C-c d d
的 prefix 的同时又是一个单独的 key sequence。
我想了一下,你的这个需求其实和我遇到的场景确实不太一样,我的场景是第一件事情一定会做,然后在一段时间内做第二件事情,要不然就不做这件事情。
你的事情是第一件事情在一段时间内不做,过一段时间后啥事情都不干就去做。
我想了一个非常 hack 的办法,非常丑陋 (标准屎山代码)。
my-func1 是你想要做的第一件事情,my-func2 是你想要做的第二件事情。然后把你的第一个按键绑定为 这样的一个函数,先设定 D 为你要做的第二件事情的包裹,然后再设定一个计时器,计时器到了就会执行你做的第一件事情并且把D给取消绑定。然后第二件事情的包裹是取消掉这个计时器 (这样第一件事情就不会被执行),并且把D给取消绑定,再做第二件事情。
(defun my-func1 ()
(interactive)
(message "func1"))
(defun my-func2 ()
(interactive)
(message "func2"))
(defun my-func2-wrap ()
(interactive)
(cancel-timer my-temp-timer)
(general-define-key
:states 'normal
"D" #'evil-delete-line)
(funcall #'my-func2))
(defun my/do-two-things-first-step ()
(interactive)
(general-define-key
:states 'normal
"D" #'my-func2-wrap)
(setq my-temp-timer
(run-with-idle-timer 0.4 nil
(lambda ()
(my-func1)
(general-define-key
:states 'normal
"D" #'evil-delete-line))))
)
(general-define-key
:states 'normal
"C-c d" #'my/do-two-things-first-step)
更新一波,可以用 key-binding
函数查询得到按键对应的函数。这样取消绑定设回 fallback 命令的时候就不需要 hard-coding 原来的命令了。
1 个赞