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就可以了。
總結
以上是生活随笔為你收集整理的emacs按键绑定详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 先奇家用投影仪是不是杂牌?
- 下一篇: 麒麟芯片还能挺多久?