Emacs: 定义前缀键
- TAG: 编码
本文介绍在Emacs中,如何定义前缀键、如何设置嵌套键映射。它将为你提供更多键的访问权限。
如果安装了 which-key
软件包,请打开 which-key-mode
, 它会帮助你展示
有哪些前缀键。如果没有安装可以使用所绑定的键前缀后 C-h
(<keymap> C-h
) 来显示。
我们要实现如下键绑定:
C-t t <Command> f find-file d dired b "Buffer" m buffer-menu s switch-to-buffer
以下是在emacs 29之后的版本实现,29之前的版本可能有些函数名不一样。
定义一个前缀键
keymap-set
接收3个参数,
(keymap-set KEYMAP KEY DEFINITION)
;; Emacs 29 `keymap-set', `defvar-keymap' ;;;; 定义全局键映射 C-t, 动作为nil,不做任何事 (keymap-set global-map "C-t" nil) ;;;; 定义全局键映射C-t,执行test-command函数 ;;; 定义交互式函数,回显一条消息This is a test! (defun test-command () (interactive) ; 这使用函数成为一个命令 (message "This is a test!")) (keymap-set global-map "C-t" 'test-command) ;;;; keymap-set的变体及在包管理(`use-package')中的使用 ;;; 在旧版本中会使用 keymap-set 变体 define-key (define-key global-map (kbd "C-t") 'test-command) ;;; use-package 中的键映射, 29版本后为内置包 (use-package xxx :bind ("C-t" . test-command))
嵌套键映射
当我们想要定义前缀键映射时,不想使用命令,而是绑定键映射。键映射是一个变量,像字符串一样保存键。
(defun test-command () (interactive) ; 这使用函数成为一个命令 (message "This is a test!")) ;;;; 使用defvar-keymap定义键映射 ;;; C-t t 执行test-command函数 (defvar-keymap my-test-prefix-map :doc "My prefix map." "t" 'test-command) (keymap-set global-map "C-t" my-test-prefix-map) ;;; C-t 多个键映射 f d t (defvar-keymap my-test-prefix-map :doc "My prefix map." "f" 'find-file "d" 'dired "t" 'test-command) (keymap-set global-map "C-t" my-test-prefix-map) ;;;; 使用defvar-keymap定义键映射,更友好写法 ;;; 更友好的写法 ;; #'井号加单引号写法和上面‘单引号的功能是相同的,只语义上有些不同。 ;; #'告诉阅读此内容的人或编译器接下来是一个函数,不是任何形式的 ;; 符号,而是一个特定的函数 (defvar-keymap my-test-prefix-buffer-map :doc "My prefix map for buffers." "s" #'switch-to-buffer "m" #'buffer-menu)
现在我希望能够从我的前缀映射内部访问 my-test-prefix-buffer-map
(defvar-keymap my-test-prefix-map :doc "My prefix map." "f" 'find-file "b" my-test-prefix-buffer-map "d" 'dired "h" help-map "t" 'test-command)
C-t
时which-key b 显示 +prefix
, 而没展示b的作用。
解决嵌套键时,which-key展示问题
(which-key-add-keymap-based-replacements my-test-prefix-map "b" `("Buffer" . ,my-test-prefix-buffer-map))
`( ,<var/function>)
是动态展示来的用法
(setq test-hello "Hello!") test-hello "Hello!" (message "The value is: %s" '(one two test-hello)) "The value is: (one two test-hello)" (message "The value is: %s" `(one two ,test-hello)) "The value is: (one two Hello!)"
添加帮助信息
(defvar-keymap my-test-prefix-map :doc "My prefix map." "f" 'find-file "b" my-test-prefix-buffer-map "d" 'dired "h" help-map "t" 'test-command) (keymap-set global-map "C-t" my-test-prefix-map) ;;; which-key中显示嵌套键的注释 (which-key-add-keymap-based-replacements my-test-prefix-map "b" `("Buffer" . ,my-test-prefix-buffer-map) "h" `("Help" . ,help-map))
which-key 适合做演示。一般我们忘记快捷前缀有哪些嵌套键,可以在后面追加 C-h
.
use-package 的绑定键
(use-package xxx :bind ("C-t" . test-command)) ; 相当于全局映射 global-map (use-package xxx :bind ( :map global-map ("C-t" . test-command) ("C-c l" . org-store-link) :map org-mode-map ("C-c C-M-l" . org-toggle-link-display) ))
完整内容
;; This buffer is for text that is not saved, and for Lisp evaluation. ;; To create a file, visit it with ‘C-x C-f’ and enter text in its buffer. ;; Emacs 29 `keymap-set', `defvar-keymap' ;;;; 定义全局键映射 C-t, 动作为nil,不做任何事 (keymap-set global-map "C-t" nil) ;;;; 定义全局键映射C-t,执行test-command函数 ;;; 定义交互式函数,回显一条消息This is a test! (defun test-command () (interactive) ; 这使用函数成为一个命令 (message "This is a test!")) (keymap-set global-map "C-t" 'test-command) ;;;; keymap-set的变体及在包管理(`use-package')中的使用 ;;; 在旧版本中会使用 keymap-set 变体 define-key (define-key global-map (kbd "C-t") 'test-command) ;;; use-package 中的键映射, 29版本后为内置包 (use-package xxx :bind ("C-t" . test-command)) ; 相当于全局映射 global-map (use-package xxx :bind ( :map global-map ("C-t" . test-command) ("C-c l" . org-store-link) :map org-mode-map ("C-c C-M-l" . org-toggle-link-display) )) (defun test-command () (interactive) ; 这使用函数成为一个命令 (message "This is a test!")) ;;;; 使用defvar-keymap定义键映射 ;;; C-t t 执行test-command函数 (defvar-keymap my-test-prefix-map :doc "My prefix map." "t" 'test-command) (keymap-set global-map "C-t" my-test-prefix-map) ;;;; 使用defvar-keymap定义键映射,更友好写法 ;;; 更友好的写法 ;; #'井号加单引号写法和上面‘单引号的功能是相同的,只语义上有些不同。 ;; #'告诉阅读此内容的人或编译器接下来是一个函数,不是任何形式的 ;; 符号,而是一个特定的函数 (defvar-keymap my-test-prefix-buffer-map :doc "My prefix map for buffers." "s" #'switch-to-buffer "m" #'buffer-menu) ;;; C-t 多个键映射 f d t (defvar-keymap my-test-prefix-map :doc "My prefix map." "f" 'find-file "b" my-test-prefix-buffer-map "d" 'dired "h" help-map "t" 'test-command) (keymap-set global-map "C-t" my-test-prefix-map) ;;; which-key中显示嵌套键的注释 (which-key-add-keymap-based-replacements my-test-prefix-map "b" `("Buffer" . ,my-test-prefix-buffer-map) "h" `("Help" . ,help-map)) (setq test-hello "Hello!") test-hello "Hello!" (message "The value is: %s" '(one two test-hello)) "The value is: (one two test-hello)" (message "The value is: %s" `(one two ,test-hello)) "The value is: (one two Hello!)"