为现有Emacs模式添加键盘绑定

8 投票
2 回答
2736 浏览
提问于 2025-04-15 20:20

我正在尝试第一次修改Emacs。我录制了一个小的键盘宏,然后让Emacs把它输出成elisp,结果是:

(setq add-docstring
    "\C-rdef\C-n\C-a\C-m\C-p\C-i\C-u6\"\C-u3\C-b")
(global-set-key "\C-c\C-d" 'add-docstring)

不过,在查阅Emacs的参考资料时,我发现C-c C-d在diff模式下已经被绑定了。我并不打算使用diff模式,但未来的事情谁也说不准,我不想给自己埋下一个陷阱。所以我希望这个快捷键只在python模式下有效,这样它可以帮助我添加文档字符串。

在我的/usr/share/emacs/23.whatever/list/progmodes目录下,我找到了python.elcpython.el.gz。我解压了python.el.gz,得到了一个可读的elisp文件。不过,现在文档对我来说变得难以理解了。

我该如何把我的快捷键绑定添加到python模式,而不是全局生效呢?

如果能在不重启emacs或关闭打开文件的情况下,将这些更改应用到python模式,那就更好了。我觉得作为一个自我修改的编辑器,这应该是有可能的。

2 个回答

4

首先,不要去修改python.el文件。你需要做的是为python模式创建自己的自定义快捷键。这通常是在你家目录下的.emacs文件中完成的。

在这个文件中添加类似下面的内容(我没有测试过这个,所以可能会有语法错误,而且我自己也不使用python)

(add-hook 'python-mode-hook
     '(lambda () (define-key python-mode-map "\C-c\C-d" 'add-doc-string)))

这里使用了钩子机制。每次你启动python模式时,这个函数都会被调用。这个函数只是把C-c C-d这个快捷键绑定到你的add-doc-string函数上。

这个回答很简短。可以去emacs的文档中了解一下关于.emacs文件、自定义设置和钩子的内容。

16

原来,C-c C-dpython-mode 中已经被绑定到 'python-pdbtrack-toggle-stack-tracking 这个功能上了,所以你可能需要重新考虑一下你的按键绑定选择。

注意:如果你只是想直接复制/粘贴一个解决方案,可以跳到答案的最后部分。继续阅读可以了解如何达到这个目的,以防你想再做一次。

这个宏是个不错的开始,但你现在的内容可能不太能用。要得到可以绑定到按键上的东西,可以试试 M-x insert-kbd-macro 来插入那个宏,你会得到:

(fset 'add-docstring
   (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ("def ...unprintable characters...6\"3" 0 "%d")) arg)))

(嗯……有些不可打印的字符,我不能直接复制粘贴到SO上,但你可以自己操作一下,得到正确的内容)。经过一些处理,你得到的结果相当于这个:

(fset 'add-docstring
      (lambda (&optional arg)
        "Keyboard macro."
        (interactive "p")
        (kmacro-exec-ring-item `(,(kbd "C-r def C-n C-a C-m C-p C-i C-u 6 \" C-u 3 C-b") 0 "%d")
                               arg)))

这就是第一步。通过上面的内容,你可以使用 M-x add-docstring 来获得你想要的功能。

下一步就是你问的 - 如何在本地绑定按键。关于按键绑定的文档可以在这里找到,你需要关注的是本地键映射部分,这部分内容会引导你到以下内容:

(add-hook 'python-mode-hook
          (lambda () (define-key python-mode-map (kbd "C-c C-d") 'add-docstring)))

这段代码设置了一个匿名函数,当 python-mode 被开启时会被调用,而这个函数只做一件事 - 在专门为 python-mode 设置的键映射中设置你想要的按键绑定。

如果你仔细阅读键映射部分,你会发现 Emacs 遵循一个约定,只有用户可以将命令绑定到 C-c a,其中 a 可以是任何大小写字母(例如 C-c dC-c TC-c p 都可以使用),而软件包则将特定于模式的绑定限制在 C-c %,其中 % 是任何标点符号或控制键(例如 C-c C-cC-c [C-c C-z)。

所以,如果你把绑定改成 C-c d,那么几乎可以保证不会和其他软件包冲突。Emacs 自带的 python.el 也遵循这些约定,大多数(几乎所有?)随 Emacs 一起发布的软件包也是如此。

你会注意到我使用kbd 来读取按键序列。这种方式更通用,我觉得更容易阅读。

你还可以做一些进一步的清理工作:

  1. 把自定义内容放在一个命名函数
  2. 用 elisp 重写宏
  3. 使用eval-after-load 代替钩子(见这个问题)

这是我对第一个建议的做法,这样可以给你一个方便的地方来放其他自定义内容:

(add-hook 'python-mode-hook 'my-python-customizations)
(defun my-python-customizations ()
  "set up my personal customizations for python mode"
  ;; put other customizations in here
  (define-key python-mode-map (kbd "C-c C-d") 'add-docstring))
(defun add-docstring (&optional arg)
  "Keyboard macro."
  (interactive "p")
  (kmacro-exec-ring-item `(,(kbd "C-r def C-n C-a C-m C-p C-i C-u 6 \" C-u 3 C-b") 0 "%d")
                         arg))

使用命名函数会更整洁,因为你可以在需要时执行 (remove-hook 'python-mode-hook 'my-python-customizations) 来移除它。此外,如果你查看钩子的值(C-h v python-mode-hook RET),就能清楚地看到调用了什么(匿名函数比较长,不容易阅读)。

为了额外的奖励,在你把代码粘贴到 .emacs 文件后,执行 M-x eval-region,这会告诉 Emacs 评估该区域的代码。要查看你现有的 python 缓冲区中的更改,你只需打开一个新的 python 文件/缓冲区,这样就会触发按键绑定的更改 - 这对所有 python 缓冲区都是通用的。

祝你编程愉快。

撰写回答