Emacs常見鍵綁定方式匯總

寫在開頭

從本期開始,我會試圖整合專欄之前零零散散的內容,產出更有概覽性和指導性的文章。要做到這一點,一方面需儘力保證結構清晰,文字精鍊,文風統一,另一方面也會給出歷史文章分類目錄及超鏈接,方便大家查閱。以後的文章中,也將視情況給出有必要的配圖。

本人的配置文件Github地址一併放在最後,暫時還沒寫什麼注釋,後面會跟進改善。

這一期先對鍵綁定的內容做一下總結。

概述:Emacs的鍵綁定方式看起來花樣繁多,其本質上都是同一個機制

(define-key keymap key def)n

這裡的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"))n

你在任何時候按下"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)n

一般而言,大部分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)n

local-set-key主要是在各種major-mode下使用,一般是通過hook設置

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

特點:通過這種方式設置的鍵綁定僅在該major-mode下生效,不影響其他major-mode,實惠好用。

註銷方式:綁定為nil,或者

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

適用情況:

  • 在不同major-mode下調用類似的命令,如運行當前文件,當前選區,當前行等等,在不同的語言做的是類似的事情,所以可通過這種方式把不同的命令綁定到同一個鍵上。

  • 通過hook來local-set-key本質上修改的只是一個變數(如果該變數不存在自動創建),不需要提前載入對應的major-mode,相比直接定義該mode下的各種keymap更加安全。

四、global-set-key,優先順序最低

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

特點:最簡單的鍵綁定方式,一行搞定,無須關心到底是哪個keymap。然而需小心在某些major-mode時會被覆蓋。

註銷方式:綁定為nil,或者

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

適用情況:

  • 一些不常用的命令
  • 一些冷門的按鍵

需要注意的是

對於上述不同優先順序的鍵綁定方式,其對應的逆操作(即註銷鍵)也遵循同樣的優先順序,例如註銷了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常見鍵綁定方式匯總

快捷鍵(一)(待整合)

快捷鍵(二) (待整合)

個人配置文件

github.com/wolray/emacs


推薦閱讀:

對於新手來說 如何用atom搭建python的ide?
atom的active-power-mode插件能關掉窗口抖動嗎?
VSCode、Atom和Sublime為什麼不支持代碼標籤成對摺疊呢?
VScode如何根據不同文件類型設置諸如tab的長度、ruler位置等選項?
Emacs 有什麼奇技淫巧?

TAG:Emacs | Lisp | 文本编辑器 |