惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
月光博客
月光博客
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
Vercel News
Vercel News
MyScale Blog
MyScale Blog
爱范儿
爱范儿
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
H
Help Net Security
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LangChain Blog
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
宝玉的分享
宝玉的分享
博客园 - 聂微东
云风的 BLOG
云风的 BLOG
J
Java Code Geeks
博客园 - 叶小钗
D
Docker

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日
读:右键菜单——Elisp 开发的隐藏利器 - 暗无天日
2026-05-17 · via 暗无天日

原文来自 Charles Choi 的 Enhancing Elisp Development with Context Menus

Elisp 开发的快捷键负担

写 Elisp 的时候,调试是最让人头疼的环节。用 Edebug 调试要先跑 M-x edebug-defun 把函数标记一下,然后 j 步入、 h 步过、 g 继续、 e 求值表达式。这几个快捷键散落在不同的 keymap 里,不天天用的话根本记不住哪个是哪个。

Emacs 28 给了一个低调的解法: context-menu-mode 。开启之后,在代码上右键就能根据光标位置弹出不同的操作菜单。不需要记快捷键,看菜单就知道能干什么。

一行配置开启右键菜单

(context-menu-mode 1)

加到配置文件里就行。开启后,在 Elisp 文件里右键点击,菜单内容会根据光标位置自动调整。

内置菜单已经不少

Emacs 自带了 20 多个右键菜单钩子函数,都挂在 context-menu-functions 这个列表上。在 Elisp 文件里,默认生效的就有这些:

菜单函数 作用 触发条件
elisp-context-menu 查看符号文档、查手册 光标在符号上
prog-context-menu Xref 跳转(找定义、找引用) 编程模式
context-menu-region 复制、剪切、粘贴、搜索选中区域 选中了文本
context-menu-ffap 打开光标处的文件路径 光标在文件路径上
context-menu-vc 版本控制操作(commit、diff、log) 文件受 VC 管理
context-menu-undo 撤销、重做 始终显示

其余十几个按需加载,比如 dictionary-context-menu 在字典模式激活时才出现, hi-lock-context-menu 在高亮模式里才有效。

其中 elisp-context-menu 的实现值得细看。它用 thing-at-mouse 检测鼠标位置下的符号,然后判断这个符号是函数、变量还是 face,分别提供"查看文档"和"查手册"两个操作。下面是简化版的源码。

(defun elisp-context-menu (menu click)
  (when (thing-at-mouse click 'symbol)
    (let* ((string (thing-at-mouse click 'symbol t))
           (symbol (intern string))
           (title (cond
                   ((and (fboundp symbol) (not (boundp symbol)))
                    "Function")
                   ((and (boundp symbol) (not (fboundp symbol)))
                    "Variable"))))
      (when title
        (define-key-after menu [describe-symbol]
          `(menu-item ,(format "Describe %s" title)
                      (lambda (_click) (describe-symbol ',symbol)))
          'elisp-separator))))
  menu)

thing-at-mouse 获取鼠标位置的符号,用 define-key-after 往菜单里加条目,就这两招。

Anju:给 Elisp 右键菜单装上调试器

Charles Choi 的 Anju 包(v1.3.0 起,MELPA 可装)在内置菜单基础上加了两层:

  1. 更细的场景感知:区分光标是在普通符号上、函数定义上、ERT 测试上、还是 lambda 上,每种情况给不同的菜单项
  2. Edebug 集成:当函数被插桩(instrument,就是用 edebug-defun 标记一下)后,右键菜单自动切换为 Edebug 命令:步入、步过、设断点、继续执行

安装和配置:

(use-package anju
  :ensure t
  :hook (emacs-lisp-mode . anju-mode))

日常写配置改点 Elisp,不需要记住那些调试快捷键,右键就能操作。

写一个自己的右键菜单

写自己的菜单项只需要知道一件事:往 context-menu-functions 列表里加一个函数,这个函数接收 menuclick 两个参数,在函数里用 define-key-after 往菜单加条目,最后返回 menu

下面是一个实际例子:右键在 Elisp 符号上时,加一个"复制符号名到剪贴板"的菜单项。

(defun my-elisp-copy-symbol-menu (menu click)
  "在右键菜单中添加「复制符号名」选项。"
  (when (and (derived-mode-p 'emacs-lisp-mode)
             (thing-at-mouse click 'symbol))
    (let* ((sym (thing-at-mouse click 'symbol t)))
      (define-key-after menu [my-copy-symbol]
        `(menu-item ,(format "复制符号名: %s" sym)
                    (lambda () (interactive)
                      (kill-new ,sym)
                      (message "已复制: %s" ,sym)))
        'elisp-separator)))
  menu)

(add-hook 'context-menu-functions #'my-elisp-copy-symbol-menu)

加载后,在 Elisp 文件里右键点击任何符号,菜单里就会出现"复制符号名"选项。注意 lambda 里的 ,sym 在定义时就展开成实际值了,不是运行时才取值,所以菜单项被点击时 sym 的值还在。

右键菜单(光标在 foo 上,实际顺序可能不同):
┌──────────────────────────┐
│ 复制符号名: foo          │  ← 新增的菜单项
│──────────────────────────│
│ Describe Function        │  ← 内置
│ Look up in Manual        │  ← 内置
│──────────────────────────│
│ 撤销                     │
│ 剪切                     │
│ ...                      │
└──────────────────────────┘

为什么是右键菜单,不是 Transient

Charles Choi 在设计这个功能时试了三种方案:

  1. Transient:窗口管理冲突。Transient 弹出时会重新布局窗口,和 Edebug 的窗口管理打架,导致布局乱跳
  2. Toolbar:macOS 上有 bug,布局也不灵活(按钮只能横排,没法做分组和折叠)
  3. Context Menu:不干扰窗口管理,右键弹出用完即消,和任何 mode 的窗口布局都不冲突

如果你的 Emacs 包 UI 需要和 Edebug 这样的窗口管理机制共存,右键菜单比 Transient 更稳妥。

小结

context-menu-mode 是 Emacs 28 起内置的全局 minor mode,开启后右键菜单会根据上下文自动调整内容。Emacs 已经为编程模式、Elisp 符号、区域操作、版本控制等场景预置了菜单项,第三方包(如 Anju)可以在其基础上继续扩展。内置菜单够日常使用,常用 Edebug 的话装上 Anju 会顺手不少。