Emacs 的更多内置功能

Lobsters Hottest 工具

摘要

一篇博客文章,介绍了Emacs中不太为人所知但实用的内置功能,延续了一个旨在提高原版Emacs功能可发现性的系列。

<p>Karthik 是一位非常出色的 Emacs 博主。他非常擅长识别模式并传达如何有效使用它们,我发现他的内容对 Emacs 新手和老手都很有帮助。</p> <p>这篇文章是他关于 Emacs 内置功能系列的一部分(其他文章在文中附有链接)。快去看看吧!我使用 Emacs 已有约10年,每一篇‘内置功能’文章都让我学到新东西。考虑到 Elisp 以及第三方定义自己扩展的便捷性,Emacs 的深度就合情合理了。令人惊叹的是,Emacs 中内置了如此多的功能。我发现自己用 Emacs 内置功能替换了许多第三方包,体验非常愉快。</p> <p><a href="https://lobste.rs/s/wwbl1n/even_more_batteries_included_with_emacs">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/15 00:47

# Emacs 的更多内置功能 来源:https://karthinks.com/software/even-more-batteries-included-with-emacs/ Emacs 的功能存在可发现性难题,而我们正通过一次次的演示逐步攻克它。自从我写完上一篇这类文章以来,又发现了更多令人惊讶且实用的功能,因此是时候再次发布一份“内置功能丰富”的报告了。 **注意** 这是系列文章的第三篇,重点介绍 Emacs 中包含的有用但鲜为人知的功能。第 1 部分和第 2 部分: - [Batteries included with Emacs](https://karthinks.com/software/batteries-included-with-emacs/) - [More batteries included with emacs](https://karthinks.com/software/more-batteries-included-with-emacs/) “鲜为人知”是一个主观判断。大致来说,这意味着在撰写本文时,我在过去二十年断断续续参与在线 Emacs 讨论的过程中,看到这些功能被提及的次数少于五次——而且往往从未被提及。过去几个条目中涵盖的一些功能如今已广为人知并经常被推荐。对此我不敢居功。如果你是 Emacs 新手,**请勿从此处开始**。这不是入门指南。你最好先掌握基本的 Emacs 概念,并坚持使用最广泛推荐的包。当你体验过 Emacs 中类似于“为什么直到 1990 年才有人想到给行李箱装轮子?”这样的想法之后,本系列可能会更有帮助。 我的经验法则是:如果你还不知道 `undo-in-region`,那么还有大量唾手可得的果实等待采摘,等到那些果实摘完后,你再来读这篇文章也不迟!资深 Emacs 用户往往使用一些相对小众的 Emacs 功能,但根据我的经验,每个用户使用的小众功能子集都不同。所以,如果你已经身经百战,我保证下面仍然会有让你惊喜的内容! 规则与以前相同: - **不引入包,仅限原生 Emacs** - **没有陡峭的学习曲线。每个功能在五分钟内学会,否则拉倒。** - **没有噱头**。没有 `doctor`、`tetris`、`snake`、`dunnet`、`zone`、`butterfly`……是的,我们知道 `dissociated-press`。让我们继续。 - **只讲增量**。不涉及 Flymake、doc-view、outline-minor-mode、Gnus 或 EWW 等常见包。不涉及 Emacs 自动弹出或通用谷歌搜索能轻易找到的内容。 - 假设你使用的是现代 Emacs,28.1 及以上版本。 另外,如果你是 Emacs 新手并且还在阅读:请参考以下术语对照表: | Emacs 术语 | 现代说法 | |---|---| | `M-x` | Alt + x | | `C-x` | Ctrl + x | | Frame | Emacs 窗口 | | Windows | 分屏/窗格 | | Buffer | 连续的文本/数据块 | | Point | 缓冲区中的光标位置 | | Active Region | 文本选区 | | Region | 文本选区(未高亮) | | Face | 字体、颜色和显示属性 | 不好意思,行了吧?我们开始: ## 词典工具提示模式 开启 `dictionary-tooltip-mode`,当鼠标悬停在单词上时,可以在工具提示中看到词义: [![VIDEO: Emacs dictionary-tooltip-mode demo](https://karthinks.com/img/dictionary-tooltip-demo-01.mp4)](https://karthinks.com/img/dictionary-tooltip-demo-01.mp4) 当然,`tooltip-mode` 也需要启用,但它是默认开启的。如果你设置了本地词典,它会优先使用本地词典。请注意,Emacs 的词典也可以查找当代行话和俚语,通常是通过维基词典。 ## 使用通配符的 `find-file` 和 `dired` 两个最常用的 Emacs 命令有一个令人惊讶的鲜为人知的实用功能:你可以在交互使用 `find-file` 和 `dired` 时使用通配符。 - 使用 `find-file`(`C-x C-f`)查找文件时,可以使用像 `*foo*.txt` 这样的通配符一次打开多个文件。 - 使用 Dired 打开目录时,可以通过指定文件名通配符来生成特定文件的定制列表。 以下是一个演示,两个功能都用于清理一些(非常)旧的 TeX 编译产物,然后一次打开一堆 LaTeX 文件: [![VIDEO: Emacs Dired and Find-File wildcards demo](https://karthinks.com/img/dired-wildcard-demo-01.mp4)](https://karthinks.com/img/dired-wildcard-demo-01.mp4) 逐步说明: - 使用“两级”通配符 `*/_region_*` 运行 Dired:查找所有名称中包含 `"_region_"` 的文件,但仅限于子目录中。 - Dired 生成这些文件的列表。(这些是 AucTeX 创建的临时文件。) - 全选它们(使用 `dired-toggle-marks`,绑定到 `t`)并删除。 - 使用通配符运行 `find-file`,打开所有子目录中的 TeX 文件。 - 检查缓冲区列表,发现多个 TeX 文件已打开。(用于查看打开缓冲区列表的命令是 `consult-buffer`,补全由 `Corfu` 显示。) 从函数签名可以看出,在编程调用时这是可能的。但意识到在交互使用时也具备这一能力,需要通读完整的文档字符串,而没人有那个时间!实际上,Dired 的通配符功能已被诸如 `consult-find` 之类的现代工作流所取代(通过 `embark-export` 导出为 Dired 缓冲区),但它是开箱即用的。 ## 菜单式文件名查找 (`M-x ffap-menu`) 你可能熟悉 Emacs 的“在光标处查找文件”功能 `M-x ffap`,它会检查光标是否位于有效的文件路径上并提议打开它。与之相伴的是 `ffap-menu`,一个鲜为人知但同样方便的命令。`ffap-menu` 会扫描整个缓冲区,查找任何看起来像文件路径或 URL 的内容,并将它们全部呈现给你: [![VIDEO: Emacs ffap-menu demo](https://karthinks.com/img/ffap-menu-demo-01.mp4)](https://karthinks.com/img/ffap-menu-demo-01.mp4) 由于它提供了一个 `completing-read` 接口,这开启了一个小小的可能性宇宙:你可以将(可能经过筛选的)补全列表导出到缓冲区,复制或打开全部或任意子集,或者通过 Embark 立即对其进行操作。 ### 附注:列出带属性的链接 许多 Emacs 应用(如 EWW)将 URL 作为文本属性而非纯文本链接包含在内,而 `ffap-menu` 会遗漏它们。受 `ffap-menu` 启发,我使用了一个自制版本,也能获取此类链接。 [![VIDEO: Find all URLs demo](https://karthinks.com/img/search-occur-browse-url-01.mp4)](https://karthinks.com/img/search-occur-browse-url-01.mp4) 逐步说明: - 从 EWW 显示的一个维基百科页面开始,左侧有 imenu。 - 调用 `my/search-occur-browse-url`,这是受 `ffap-menu` 启发的自定义命令。 - 滚动浏览页面链接列表,并滚动浏览页面本身。 增强版本:搜索缓冲区中的所有 URL ```elisp (defun my/search-occur-browse-url (&optional use-generic-p) "Point browser at a URL in the buffer using completion. Which web browser to use depends on the value of the variable `browse-url-browser-function'. Also see `my/search-occur-url'." (interactive "P") (let ((match nil) (match-data nil) (context (lambda (beg &optional shrp) (let* ((before (string-replace "\n" "" (buffer-substring-no-properties beg (max (line-beginning-position) (- beg 30))))) (link (string-replace "\n" "" (buffer-substring-no-properties beg (point)))) (after (buffer-substring-no-properties (point) (min (line-end-position) (+ (point) 30))))) (concat (propertize " " 'display '(space :align-to 65)) (propertize (concat "..." before) 'face 'shadow) (if shrp (propertize link 'face '(:inherit shadow :weight bold :underline t)) link) (propertize (concat after "...") 'face 'shadow)))))) (save-excursion (goto-char (point-min)) (while (search-forward-regexp my/search-url-regexp nil t) (push (cons (match-string-no-properties 0) (funcall context (match-beginning 0))) match-data)) (goto-char (point-min)) (while (setq match (text-property-search-forward 'shr-url nil nil)) (push (cons (prop-match-value match) (funcall context (prop-match-beginning match) 'shrp)) match-data))) (let* ((completion-extra-properties `(:annotation-function ,(lambda (cand) (concat " " (cdr (assoc cand match-data)))))) (url (completing-read "Browse URL: " match-data nil t))) (if use-generic-p (browse-url-generic url) (browse-url url))))) ``` ## 比较窗口 (`M-x compare-windows`) Emacs 中有多得数不清的命令用于比较缓冲区和文件:有 `diff`、`diff-buffers`、`diff-backup`、`diff-buffer-with-file`、`dired-diff`、`vc-diff`,以及一整个 `ediff-`、`ediff-merge-` 和 `ediff-directories-` 命令的星系。我数到大约二十二个就数不过来了,而且大部分都记不住。但我最喜欢的差异比较命令是轻量级的 `compare-windows`,它以一种与上下文无关的方式做一件非常简单明了的事:它从两个窗口各自的光标位置开始比较文本,在遇到第一个不匹配处停下并报告。这两个窗口是当前活动窗口和 `other-window` 会选中的那个。功能显然不如 Ediff 或 diff 强大,但运行起来却要容易和快得多。 [![VIDEO: compare-windows Emacs demo](https://karthinks.com/img/compare-windows-demo.mp4)](https://karthinks.com/img/compare-windows-demo.mp4) 逐步说明: 1. 在两个窗口中将光标移动到要比较的文本的开头。 2. `M-x compare-windows` 3. 就这样。它会将光标移动到第一个不匹配处并报告。 `compare-windows` 只关心两个窗口中的实际文本,而不关心这些文本的来源。缓冲区类型、修改状态、文件、版本控制状态——统统无关!你甚至可以通过在同一个缓冲区中显示两个窗口,来比较缓冲区中的一段文本与同一缓冲区中稍远位置的另一段文本。 以一种愚蠢但有效的方式,它甚至可以用来比较目录内容,包括文件属性: [![VIDEO: compare-windows Emacs demo 2](https://karthinks.com/img/compare-windows-demo-02.mp4)](https://karthinks.com/img/compare-windows-demo-02.mp4) 逐步说明: 1. 两个包含一些相似文件的目录。 2. 在两个窗口中将光标放在同一个文件上。 3. `M-x compare-windows` 4. 光标停在第一个报告的不匹配处,这里是一个文件的修改时间。 是的,你可以通过前缀参数调用它来忽略空白差异。当你发现自己需要在两种视图之间玩“找不同”游戏时,`compare-windows` 就是你的选择。它是我最常用的“差异比较”命令。 ## 使用 Dired 比较目录 (`M-x dired-compare-directories`) 但是说到比较目录,Dired(当然)提供了一种不那么 hacky 的方法。在 Dired 中运行 `M-x dired-compare-directories` 会提示输入要比较的目录,并标记两个 Dired 列表中文件名不同的所有文件。这涵盖了最常见的用例,可能就是你需要的全部了。但我们刚才已经用基本的 `compare-windows` 做过了。`dired-compare-directories` 是真正的文件级比较,因此你可以提供涉及任何文件属性的自定义匹配谓词,比如修改时间或大小。例如: - 你可以用 `(> mtime2 mtime1)` 标记一个文件的最新修改版本, - 或者用 `(/= size1 size2)` 标记名称相同但大小不同的文件。 在这个例子中,`dired-compare-directories` 标记了 (i) 两个列表中不共有的文件和 (ii) 修改时间不同的文件: **每个季节都有一个 Ediff** 如果你想要更交互式/规定性的操作,还有 `ediff-directories`,因为每个场合都有一个 Ediff 命令。 ## 高亮缓冲区更改 (`M-x highlight-changes-mode`) 既然我们还在讨论发现差异,`highlight-changes-mode` 是一个方便的方法来强调对文件的更改,也是 diff 命令(如 `diff-buffer-with-file`)的“实时”替代方案: [![VIDEO: Emacs highlight-changes-mode demo](https://karthinks.com/img/highlight-changes-mode-demo-01.mp4)](https://karthinks.com/img/highlight-changes-mode-demo-01.mp4) 逐步说明: - 运行下面的代码块,将 `highlight-changes-mode` 与 `save-buffer` 同步。现在更改会在下次保存前高亮显示。 - 做一些更改。注意添加/更改的文本颜色不同。 - 保存缓冲区,同时清除高亮。 - 重复最后两步几次。 `highlight-changes` 的可视化仅由模式本身决定,更改从模式开启时高亮直到模式关闭。一般来说,这不是我们想要的。我们想要的是高亮**未保存的更改**。(有 `M-x highlight-compare-with-file`,但它不人性化到几乎不可用的地步。) 我们可以通过一些技巧来做到这一点,或者干脆加几个钩子: ```elisp (defun highlight-changes-mode-turn-off () (and highlight-changes-mode (highlight-changes-mode -1))) (defun highlight-changes-auto () (when (buffer-file-name) (highlight-changes-mode-turn-on) (add-hook 'after-save-hook #'highlight-changes-mode-turn-on nil t) (add-hook 'before-save-hook #'highlight-changes-mode-turn-off nil t))) (add-hook 'text-mode-hook #'highlight-changes-auto) ``` 现在 text-mode 缓冲区中的所有更改都会自动高亮。 ### 将 `highlight-unsaved` 作为独立功能 `highlight-changes` 的可视化可以进行自定义以使其更微妙,但你可能仍然不希望它一直开启。上面的钩子逻辑可以很容易地转变为一个独立的次要模式: ```elisp (require 'hilit-chg) (defun highlight-changes-mode-turn-off () (and highlight-changes-mode (highlight-changes-mode -1))) (define-minor-mode highlight-unsaved-mode "Highlight all changes until the buffer is saved." :lighter "H" (cond ((not (buffer-file-name)) (user-error "Highlight-until-save-mode is only meant for use in file-visiting buffers")) (highlight-until-save-mode (highlight-changes-mode 1) (add-hook 'after-save-hook #'highlight-changes-mode-turn-on nil t) (add-hook 'before-save-hook #'highlight-changes-mode-turn-off nil t)) (t (highlight-changes-mode -1) (remove-hook 'after-save-hook #'highlight-changes-mode-turn-on t) (remove-hook 'before-save-hook #'highlight-changes-mode-turn-off t)))) ``` --- 最后,`highlight-changes-mode` 提供了一个辅助功能:你可以使用 `highlight-changes-next-change` 和 `highlight-changes-previous-change` 跳转到缓冲区中的上一个和下一个更改。由于这是更改跟踪的独立结果,你可以只使用此导航,并通过 `M-x highlight-changes-remove-highlight` 关闭更改可视化。 ## 真正有用的文件备份(`vc-diff` 变体) 最后一次离题,以结束发现和比较更改的主题。这需要绕道到 Emacs 备份文件的话题,并且正在突破五分钟的限制和内置功能的理念,请耐心听我说。 ### 我们来做备份 默认情况下,Emacs 会对你编辑和保存的任何文件进行定期备份。这个备份系统通常只在“烦人且应该禁用(通过 `make-backup-files`)”的上下文中被提及。如果你想要真正的备份,你可以直接使用版本控制,对吧?如果你担心敏感文件被复制到磁盘上的其他地方,我很同情你。但除此之外,我认为这主要是人体工程学的问题。 - Emacs 用备份文件弄乱你的工作目录,并且 - 不便于你浏览和使用备份文件。 改变前者是一个用户选项(例如,参见 `backup-directory-alist`、`kept-old-versions` 和 `kept-new-versions`),但后者完全是缺少用户界面的问题。外部包 [backup-walker](https://github.com/lewang/backup-walker) 以及其他一些包提供了这种“时间机器”界面。但有一个更简单、令人满意的修复方法,同时能解决另一个问题。 ### VC(直到不版本控制) Emacs 内置的 VC 包提供了一个用于查看版本控制文件过去版本的界面: - `vc-diff`(`C-x v =`):将文件与其直接上一个版本进行比较,或者在使用前缀参数时与指定版本进行比较。 - `vc-ediff`:对文件的上一个版本或指定版本运行 Ediff。 - `vc-revision-other-window`(`C-x v ~`):在新窗口中显示文件的旧版本。

相似文章

推荐一下……理解 Emacs 的模式

Lobsters Hottest

文章解释了 Emacs 的架构模式,重点介绍了通用缓冲区数据模型和增量补全读取(ICR),并将其比作玫瑰的根与花瓣。文章强调了 Emacs 如何统一界面并通过 Elisp 实现可扩展性。

Emacs 写作机

Lobsters Hottest

一篇关于将旧 ThinkPad 改造为专用写作设备的博客文章,运行 Debian 和 Emacs,灵感来自 Veronica Explains 的 writerdeck 概念,包含配置和通过 Git 同步文件的技巧。

我可以推荐 Emacs 的创新 UI——eww 吗?

Lobsters Hottest

文章推荐使用 Emacs 的 eww 网页浏览器,强调其缺少 JavaScript 的特性改善了许多网站的体验,并指出 Emacs 提供了独特的 UI 创新,如逐张图片调整大小和键盘导航。

被低估的内置功能:Grand Unified Debugger

Lobsters Hottest

本文重点介绍了Emacs内置的Grand Unified Debugger(GUD)的功能,强调了其多调试器支持和图形化GDB界面,包括通过点击边缘设置断点以及单步执行代码等功能。