emacs按键绑定详解

key-binding:

https://crazylxr.github.io/spacemacas-zh_CH-doc/binding-keys.html

 


 

概述:Emacs的键绑定方式看起来花样繁多,其本质上都是同一个机制

(define-key keymap key def)

这里的key是你要绑定的键。keymap是这个key所属的集合,不同的keymap决定了这个key在什么情况下触发,什么情况下隐藏,优先级如何。def代表了这个key的定义,它可以是很多东西,常见的有

  • 一个interactive function,即一个command,这也是键绑定最直接的方式。
  • 一个key,仅对于keymap为'key-translation-map这种情况,意味着映射到另一个键。
  • 一个keymap,通过这种方式用户可以自定义prefix key。
  • 一个nil,代表注销这个key。

keymap也有很多种,如(current-global-map)返回全局keymap,(current-local-map)返回局部keymap。对于这两种情况,Emacs提供了更直接的函数:'global-set-key和'local-set-key。另外还有上面提到的key-translation-map,以及许多minor-mode下定义的keymap。

 

这四种不同种类的keymap,正代表了Emacs里常见的四种不同的快捷键设置方式。虽然看起来较为复杂繁琐,但如果配合巧妙,完全可以实现一键多用,让用户做到在不使用Ctrl键、不叠加修饰键,不连击超过两次组合键,甚至不开Evil的前提下,执行Emacs连同各种插件包里所支持的所有编辑命令。


 

一、key-translation-map,优先级最高

(define-key key-translation-map (kbd "your-key") (kbd "target-key"))

你在任何时候按下"your-key",编辑器将执行"target-key"所绑定的命令。无论当时处于何种编辑状态,是否有minor-mode触发,该映射都不受影响,属于优先级最高的键绑定方式。

特点:由于映射键是完全的跳转到了另一个键上,所以一旦目标键的定义发生了变化,该键也会随之受到影响。

注销方式:把这个key重新映射为它自己。

适用情况:

  • 常用的、重要的,但按键较为复杂的命令,如"C-x C-s"固定的绑定的'save-buffer,"C-M-i"固定绑定的'completion-at-point,"C-M-%"固定绑定的'query-replace-regexp。你可以用更简单的键来映射它们。
  • 常用的,重要的,但在不同mode下会发生变动的命令,如常规编辑中的"C-g"对应的是'keyboard-quit,在minibuffer下会变成'minibuffer-keyboard-quit。如果你将某个键绑定为'keyboard-quit,你会发现它在minibuffer下就没法用了。对于这种情况,最好的办法就是直接映射。


 

二、minor-mode-map,优先级第二

(define-key some-minor-mode-map (kbd "your-key") 'your-command)

一般而言,大部分Emacs用户没有自定义minor-mode的需求,往往也不知道怎么定义,但minor-mode-map对所有用户而言并不陌生,最常见的便是在isearch-mode下的'isearch-repeat-forward和'isearch-repeat-backward。

当你按"C-s"触发isearch-mode并搜索某段文字的时候,重复按"C-s"将跳转到下一个匹配,看起来是顺理成章的事其实对应的是两个不同的函数。之所以这里能一键多用,是因为在'isearch-mode触发同时也激活了它的minor-mode-map,也就是'isearch-mode-map,它里边将"C-s"绑定到了'isearch-repeat-forward上,在激活状态下便覆盖掉了它的初始定义'isearch-forward。

特点:仅在minor-mode激活时有效,定义方便且优先级高,不用担心键冲突。

注销方式:绑定为nil。

适用情况:

  • 各种系统自带minor-mode如'isearch-mode,'query-replace,'edmacro-mode
  • 各种常见插件如'cua--rect,'with-editor
  • 自定义minor-mode


 

三、local-set-key,优先级第三

(local-set-key (kbd "your-key") 'your-command)

local-set-key主要是在各种major-mode下使用,一般是通过hook设置

(add-hook 'some-major-mode-hook '(lambda () (local-set-key ...)))

特点:通过这种方式设置的键绑定仅在该major-mode下生效,不影响其他major-mode,实惠好用。

注销方式:绑定为nil,或者

(local-unset-key (kbd "your-key")

适用情况:

  • 在不同major-mode下调用类似的命令,如运行当前文件,当前选区,当前行等等,在不同的语言做的是类似的事情,所以可通过这种方式把不同的命令绑定到同一个键上。
  • 通过hook来local-set-key本质上修改的只是一个变量(如果该变量不存在自动创建),不需要提前加载对应的major-mode,相比直接定义该mode下的各种keymap更加安全。


 

四、global-set-key,优先级最低

(global-set-key (kbd "your-key") 'your-command)

特点:最简单的键绑定方式,一行搞定,无须关心到底是哪个keymap。然而需小心在某些major-mode时会被覆盖。

注销方式:绑定为nil,或者

(global-unset-key (kbd "your-key")

适用情况:

  • 一些不常用的命令
  • 一些冷门的按键


 

需要注意的是

对于上述不同优先级的键绑定方式,其对应的逆操作(即注销键)也遵循同样的优先级,例如注销了minor-mode的快捷键,它便会恢复为当前major-mode下的定义,如果当前major-mode下没有定义,那便执行全局默认的命令。


 

键冲突问题

尽管已有如此多的键绑定方式,由于Emacs默认的键布局已十分紧张,用户往往容易碰到各种各样的键冲突问题。

比如你想设置一个快捷键,使它在任何情况下都绑定为一个固定的命令。如果你用global-set-key,那它有可能会被其他major-mode覆盖;如果你用key-translation-map,它所映射的那个键同样可能被覆盖;如果你用local-set-key,那你不得不在所有出问题的major-mode里挨个设置。你该怎么办?——可以暂时参考本专栏之前的一篇文章:快捷键(一)

又比如你写了一个minor-mode,你想定义一个快捷键让它执行"C-g"的功能,正常编辑时为'keyboard-quit,在minibuffer下则为'minibuffer-keyboard-quit。但遗憾的是minor-mode里是不支持键的映射的,你又该怎么办?——我会在新的文章中分享解决方案。


 

相关文章

快捷键篇:

Emacs常见键绑定方式汇总

快捷键(一)(待整合)

 

快捷键(二) (待整合)


 

个人配置文件

https://github.com/wolray/emacs.d

 

 

在emacs中我们可以将一个交互式的命令绑定到一个按键序列中。比如C-x C-f就绑定了命令find-file,而一般的字母和数字则绑定到了self-insert命令。使用这一个方式我们就可以做很灵活的绑定,让那些我们经常使用的命令绑定到非常方便的key sequence上面。这种命令绑定是通过key-map数据结构实现的。但是我们知道在emacs之中存在不同的major mode和minor mode,而且不同key-sequence的长度也不相同,那么这些因素对键盘绑定有什么影响呢?

1. 存在不同major mode和minor mode对命令绑定的影响 

 一个很明显的需求就是同样的key sequence在不同的major mode和minor mode中绑定不同的命令。这样就产生了一个全局key-map和局部key-map的需求,全局key-map只有一个,但是不同的major mode 和 minor mode都有一个自己的key-map。当你编辑的文件处于某个major-mode,并启用了一些minor-mode时,只有相关的minor-mode key-map,major-mode key-map和global key-map是可以影响到key-sequence的解释的。当需要给出一个key-sequence所绑定的命令时,首先搜索minor-mode的key-map,然后是major-mode的key-map,最后是global-key-map;当在前一个key-map中找不到时,才会到后一个key-map中寻找。当需要定义全局的key-map时可以使用global-set-key这个函数,如果需要定义局部key-map,使用local-set-key。

2. key-sequence长度对键盘映射的影响

 有些键盘操作只需一次即可完成某个命令,比如C-f,C-b;但是另外一些则需要多次的按键,比如打开文件的命令C-x C-f就需要两个键盘操作。一个key-map数据结构只能对一个按键操作映射,因此需要多个键盘操作的命令需要多个key-map,而且第一个键盘操作绑定的不是一个命令,而是另外一个key-map,后面的按键就是根据这个key-map来找到要绑定对象。对于C-x C-f操作,定义了一个global key-map,将C-x绑定到ctl-x-map中,注意这个ctl-x-map并不是一个可执行的emacs函数,而是一个key-map,在这个key-map里面,C-f绑定到了命令find-file,因此按下C-x C-f这个key-sequence时,有两个key-map,而且涉及到了两个绑定。这里C-x就被叫做prefix-key,这里的意思就是这个key只是命令的前缀,但是具体的是那个命令还需要继续给出其他的key才可以。

在emacs中定义了很多这样的prefix-key,比如C-x,Esc,C-x 4,C-x 5,M-g,C-c等等,每一个prefix-key都绑定到一个key-map上面。在相应的key-map用于解释紧接着prefix-key的绑定,这样一直循环下去,直到最后一个key-map将一个key绑定到一个命令上,输入完成之后就执行。

那么global key-map,local key-map跟这些prefix-key绑定到的key-map有什么区别和联系吗?首先这些都是key-map数据结构,作用都是为了完成键的映射。不同的major mode和minor mode都有自己的local key-map,global key-map则只有一个。可以在local key-map里创建prefix-key,也可以在global key-map里创建prefix-key。(note!prefix-key所绑定的是一个key-map,但是prefix-key同样也是一个key,也必须在某个local key-map或者global key-map里创建才行)。

3. 如何创建prefix-key

简单一个函数(define-prefix-command 'key-map-name),然后绑定键值到新建的key-map就可以了。加入我们想把C-r C-t C-z a绑定到find-file命令。a. (define-prefix-command 'ctl-r-map); (local-set-key (kbd "C-r") 'ctl-r-map); (local-set-key (kbd "C-r C-t C-z a") 'find-file);这样就可以使用C-r C-t C-z a来打开文件了。但是在这里需要说明几点a. 如果已经存在相应的prefix-key定义,不需要重新重新创建,如果不存在,那么必须首先创建prefix-key  b. 可以看到C-r C-t也是一个prefix-key,C-r C-t C-z也是prefix-key,这些都是emacs自动创建的,当我们也可以自己动手。所以对于一连串的key sequence,只需要对第一个key创建prefix-key就可以了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值