Emacs 编辑器
- TAGS: Emacs
[ 最后修订与导出时间: 2026-02-03 19:20:17 +0800 ,总字数: 59437 ]
Emacs 是一款功能先进、可扩展、可定制且自带文档的编辑器。本手册详细介绍 Emacs 的编辑使用方法及部分定制技巧,对应 GNU Emacs 30.2 版本。
GNU Emacs 官方网站:https://www.gnu.org/software/emacs/
如需查看其他格式的手册,请点击此处。
您也可通过自由软件基金会FSF商店购买纸质版本。
有关 Emacs 扩展开发的详细信息,请参阅《Emacs Lisp 参考手册》中的 “Emacs Lisp” 章节。
本文档为《GNU Emacs 手册》,已更新至 Emacs 30.2 版本。
版权所有 © 1985–2025 自由软件基金会(Free Software Foundation, Inc.)
您可以根据 GNU 自由文档许可证(GNU Free Documentation License)1.3 版或自由软件基金会发布的任何后续版本的条款,复制、分发和 / 或修改本文档;其中 “不可修改章节”(Invariant Sections)为《GNU 宣言》(The GNU Manifesto)、《发行条款》(Distribution)和《GNU 通用公共许可证》(GNU GENERAL PUBLIC LICENSE),“封面文字”(Front-Cover Texts)为 “一份 GNU 手册”(A GNU Manual),“封底文字”(Back-Cover Texts)如下(a)项所示。完整的许可证文本包含在标题为 “GNU 自由文档许可证”(GNU Free Documentation License)的章节中。
(a)自由软件基金会(FSF)的封底文字为:“您拥有复制和修改本 GNU 手册的自由。通过 FSF 购买副本将支持我们开发 GNU 软件并推广软件自由。”
发行说明
GNU Emacs 是一款自由软件,这意味着任何人都可以自由使用它,并在特定条件下自由地重新分发。GNU Emacs 并不属于公有领域,它受版权保护,其分发行为也有相关限制,但这些限制的设立,是为了保障每一位愿意遵守协作规范的使用者都能享有应有的自由。禁止的行为是,试图阻止他人进一步分享从你手中获得的任何版本的 GNU Emacs。具体的使用与分发条件详见随 Emacs 一同发布的《GNU 通用公共许可证》,本手册中也收录了该许可证的内容 1。参见《GNU 通用公共许可证》章节。
获取 GNU Emacs 副本的一种方式,是从其他已拥有该软件的人处拷贝。你无需征求我们的许可,也不必告知其他任何人,直接复制即可。若你能接入互联网,可通过匿名文件传输协议(FTP)获取 GNU Emacs 的最新分发版本;更多相关信息,请访问我们的官方网站:https://www.gnu.org/software/emacs。
你也可能在购买计算机时获得 GNU Emacs。计算机制造商可依据适用于所有用户的同一套条款,自由分发该软件的副本。这些条款要求制造商向你提供完整的源代码,其中需包含他们可能做出的任何修改,同时必须允许你依据《通用公共许可证》的常规条款,重新分发从他们那里获得的 GNU Emacs。换句话说,你获得这款程序时,它必须是自由的,这种自由不应只属于制造商。
如果你认为 GNU Emacs 对你有所帮助,不妨向自由软件基金会(Free Software Foundation)捐赠,以支持我们的工作。在美国,向自由软件基金会的捐赠可享受税收减免政策。若你在工作场所使用 GNU Emacs,建议你提议所在公司进行捐赠。捐赠渠道请访问:https://my.fsf.org/donate/。关于其他可以提供帮助的方式,详见:https://www.gnu.org/help/help.html。
我们同时发售本手册的纸质版,以及罗伯特・J・查塞尔所著《Emacs Lisp 编程入门》一书的纸质版。你可以访问我们的线上商店:https://shop.fsf.org/。销售所得收入将全部用于支持基金会的使命:开发新的自由软件,并对包括 GNU Emacs 在内的现有程序进行优化改进。
若你需要联系自由软件基金会,可访问官网联系方式页面:https://www.fsf.org/about/contact/,或写信至以下地址:
自由软件基金会
米尔克街 31 号,邮编 # 960789
马萨诸塞州 波士顿,邮编 02196
美国
引言
你正在阅读的是 GNU Emacs 的相关内容,它是 Emacs 这款高级(advanced)、自文档化(self-documenthing)、可定制(customizable)、可扩展(extensible)编辑器的 GNU 实现版本。(GNU 的全称是 “GNU’s Not Unix”,其中首字母 “G” 发音并非不发声。)
我们称 Emacs 为高级编辑器,是因为它的功能远不止简单的文本插入与删除。它可以控制子进程、自动缩进程序代码、同时显示多个文件、像编辑本地文件一样编辑远程文件,此外还有诸多强大功能。Emacs 的编辑命令可基于字符、单词、行、句子、段落和页面执行操作,同时也适配各类编程语言中的表达式与注释。
自文档化(self-documenting)指的是,你可以随时使用一类名为 “帮助命令” 的特殊指令,查看当前可用的功能选项、查询任意命令的作用,或是检索与指定主题相关的所有命令。详见 “帮助” 章节。
可定制(customizable)指的是,你能够以简单的方式轻松修改 Emacs 命令的行为。例如,若你使用的编程语言规定注释以 <** 开头、以 **> 结尾,你可以让 Emacs 的注释操作命令适配这类符号(详见 “注释操作” 章节)。再举个例子,你可以将上下左右这些基础光标移动命令,重新绑定到键盘上你觉得顺手的任意按键。详见 “自定义” 章节。
可扩展(extensible)指的是,你可以突破简单定制的范畴,创建全新的命令。新命令本质上是用 Lisp 语言编写的程序,可通过 Emacs 内置的 Lisp 解释器运行。即便是在编辑会话过程中,你也能重新定义已有命令,无需重启 Emacs。Emacs 的绝大多数编辑命令本身就是用 Lisp 编写的;仅有少数命令为追求执行效率而改用 C 语言实现,它们其实原本也可以用 Lisp 编写。编写扩展属于编程工作,但非编程人员也能直接使用现成的扩展功能。如果你想要学习 Emacs Lisp 编程,可参阅《Emacs Lisp 编程入门》一书的 “前言(Preface)” 章节。
1. 屏幕布局
在图形化显示器中(例如在 GNU/Linux 系统上使用 X 窗口系统时),Emacs 会占用一个图形化窗口。在文本终端中,Emacs 则会占据整个终端屏幕。我们将 Emacs 所占用的图形化窗口或终端屏幕统称为框架(frame)。Emacs 在这两种框架中的运行方式基本一致。默认情况下,启动 Emacs 只会打开一个框架,但你也可以根据需要创建更多框架(详见 “框架与图形化显示” 章节)。
每个框架都包含多个不同的区域(region)。框架顶部是菜单栏(menu bar),你可以通过一系列菜单调用各类命令。在图形化显示器中,菜单栏正下方是工具栏(tool bar),这是一排图标,点击即可执行相应的编辑命令。框架最底端是回显区(echo area),这里会显示提示信息,同时也是你在 Emacs 发出询问时输入信息的区域。
框架的主要区域位于工具栏(tool bar)(若存在)下方、回显区上方,该区域被称为窗口(window)。在本手册后续内容中,“窗口(window)” 一词均指代此含义。图形化显示系统中 “窗口” 的常用定义与本书不同;前文已说明,我们将这类图形化窗口称为 “框架(frames)”。
Emacs 窗口是用于显示缓冲区(buffer)的区域 —— 缓冲区即你正在编辑或查看的文本或其他图形内容。在图形化显示器中,窗口的一侧会配有滚动条,拖动滚动条即可滚动浏览缓冲区内容。窗口的最后一行是模式行(mode line),它会显示缓冲区的各类相关信息,例如是否存在未保存的修改、当前启用的编辑模式、光标所在的行号等。
启动 Emacs 时,框架中默认仅有一个窗口。不过,你可以将这个窗口进行水平或垂直分割,从而创建多个窗口,每个窗口都能独立显示一个缓冲区(详见 “多窗口” 章节)。
在任意时刻,都有且仅有一个窗口处于选中状态。在图形化显示器中,选中的窗口会显示一个更醒目的光标(通常为实心闪烁样式);其他未选中的窗口则会显示较不显眼的光标(通常为空心方块样式)。在文本终端中,屏幕上只会显示一个光标,且该光标始终位于选中的窗口内。选中窗口所显示的缓冲区被称为当前缓冲区(current buffer),所有编辑操作均在此缓冲区中进行。大多数 Emacs 命令都会默认作用于当前缓冲区;未选中窗口中显示的文本仅供参考。若你在图形化显示器中同时打开了多个框架,选中某一框架的同时,也会选中该框架内的一个窗口。
1.1. 光标位置(Point)
选中窗口中的光标标记着大多数编辑命令的生效位置,该位置被称为光标位置(point) 2。许多 Emacs 命令可以将光标位置移动到缓冲区的不同地方;例如,你可以在目标位置单击鼠标左键(通常为鼠标的第一按键),以此来定位光标位置。
默认情况下,选中窗口中的光标会显示为实心方块,看起来是停留在某个字符之上,但你应当将光标位置理解为两个字符之间的间隙—— 它 位于光标所覆盖字符的前方 。举例来说,若文本内容为 frob 且光标覆盖在字母 b 上,那么光标位置就在字母 o 和 b 之间。此时若在该位置插入字符 !,文本会变为 fro!b,光标位置则会处于 ! 和 b 之间。如此一来,光标依旧会像之前一样覆盖在字母 b 上。
若你在 Emacs 中同时编辑多个文件(每个文件对应一个独立的缓冲区),那么每个缓冲区都有其专属的光标位置。即便某个缓冲区当前未被显示,当你后续再次打开它时,该缓冲区仍会保留此前的光标位置。此外,若同一个缓冲区在多个窗口中同时显示,这些窗口的每一个也会分别拥有独立的光标位置。
有关控制 Emacs 光标显示方式的相关选项,详见 “光标显示” 章节。
1.2. 回显区(Echo Area)
框架最底端的一行区域是回显区(echo area),它被用于显示各类用途的简短文本信息。
回显区之所以得名,是因为它的用途之一是回显功能—— 也就是在你输入多字符命令时,同步显示已输入的命令字符。单字符命令不会触发回显;而多字符命令(详见 “按键” 章节),若你在输入过程中停顿超过一秒钟,Emacs 就会回显该命令当前已输入的所有字符,以此提示你继续输入剩余部分。一旦回显功能触发,后续输入的命令字符就会实时显示在回显区中。这种设计既能让操作熟练的用户获得流畅的响应速度,又能为操作不熟练的用户提供充分的反馈信息。
当某个命令无法执行时,回显区也会用于显示错误提示信息。这类错误信息通常还会伴随蜂鸣提示音,或是屏幕闪烁的提醒效果。
部分命令会在回显区显示提示性信息,告知用户该命令已执行的操作,或是提供一些特定信息。与错误信息不同,这类提示性信息不会伴随蜂鸣或屏幕闪烁。例如,按下快捷键 C-x = (按住 Ctrl 键的同时按下 x 键,松开 Ctrl 键后再按下 = 键),回显区就会显示一条信息,内容包含光标位置处的字符详情、该字符在缓冲区中的位置,以及它在窗口中对应的列数。对于执行耗时较长的命令,在运行过程中往往会在回显区显示以 '…' 结尾的提示信息(有时还会以百分比的形式标注进度),待命令执行完毕后,再在信息末尾补充显示 done(完成)。
回显区显示的所有提示性信息,都会自动保存到一个名为 *Messages* 的特殊缓冲区中。(关于缓冲区的概念,我们将在后续内容中介绍,详见 “使用多缓冲区” 章节。)如果你错过了一条一闪而过的提示信息,只需切换到 *Messages* 缓冲区,就能重新查看该信息。 *Messages* 缓冲区的存储行数存在上限,这个上限由变量 message-log-max 定义。(变量的相关概念同样会在后续说明,详见 “变量” 章节。)当缓冲区内容达到行数上限时,每在末尾新增一行信息,就会自动删除缓冲区最开头的一行旧信息。
有关控制 Emacs 回显区使用方式的相关选项,详见 “显示自定义” 章节。
回显区还会被用于显示迷你缓冲区(minibuffer)。迷你缓冲区是一个特殊的输入窗口,你可以在这里输入命令的参数,例如待编辑文件的名称。当迷你缓冲区处于激活状态时,回显区显示的文本会以提示字符串开头,同时激活状态的光标会出现在迷你缓冲区中 —— 此时迷你缓冲区会被临时认定为选中窗口。你可以随时按下 C-g 快捷键退出迷你缓冲区。详见 “迷你缓冲区” 章节。
1.3. 模式行(Mode Line)
每个窗口的底部都有一行模式行,用于显示当前缓冲区的状态信息。当框架中只有一个窗口时,模式行位于回显区(echo area)的正上方,也就是整个框架的倒数第二行。在图形化显示器中,模式行的外观呈现为一个 3D 立体方框样式。为了突出显示,Emacs 通常会将选中窗口的模式行设置为与未选中窗口不同的颜色。
模式行显示的文本遵循以下格式:
cs:ch-dfr buf pos line (major minor)
在文本终端中,上述文本的后方会显示一串连字符,一直延伸至窗口的右边缘;而在图形化显示器中,这串连字符会被省略。
各部分含义说明:
cs 及其后的冒号:
这部分用于描述当前缓冲区使用的字符编码集和换行符规则。通常情况下,Emacs 会自动处理这些设置,但有时查看这些信息也会很有帮助。
- cs 代表缓冲区中文本的字符编码集(详见 “编码系统” 章节)。如果显示为连字符('-'),表示未启用特殊的字符编码集处理(换行符规则可能除外,具体见下一段);如果显示为等号('='),表示完全不进行编码转换,这种情况通常用于编辑非文本类数据文件;其他字符则代表不同的编码系统,例如 1 代表 ISO Latin-1 编码。
- 在文本终端中,cs 前方还会显示两个额外字符,分别表示键盘输入和终端输出所使用的编码系统。此外,若你启用了输入法,cs 前方还会显示标识当前输入法的字符串(详见 “输入法” 章节)。
- cs 后方的字符通常是冒号。如果显示为其他字符,则说明该文件采用了非标准的换行符规则。文本文件的换行通常由换行符分隔,但有时也会采用另外两种规则:MS-DOS 系统的规则是用回车符加换行符表示换行,编辑这类文件时,冒号会变成反斜杠(\)或 (DOS)(具体显示取决于操作系统);早期 Macintosh 系统的规则是用回车符替代换行符,编辑这类文件时,冒号会变成正斜杠(/)或 (Mac)。在部分系统中,对于使用换行符作为分隔符的文件,Emacs 会用 (Unix) 替代冒号进行显示。
- 对于通过 emacsclient 创建的框架(详见 “调用 emacsclient” 章节),cs 后方的字符会显示为 @。这种标识常见于以守护进程模式运行的 Emacs 进程所创建的框架(详见 “将 Emacs 用作服务器” 章节)。
ch
这部分用于标识缓冲区的修改状态。如果窗口中显示的缓冲区内容与磁盘上对应的文件内容一致(即缓冲区未被修改),会显示两个连字符('–');如果缓冲区已被修改,则显示两个星号(**);对于只读缓冲区,若内容已修改会显示 %*,未修改则显示 %%。
ch 后的字符
该位置通常显示为连字符('-')。但如果当前缓冲区的 default-directory(详见 “文件名” 章节)指向远程主机,该位置会显示为 @。
d
仅当窗口被专用绑定到当前缓冲区时才会显示。若为强专用绑定,显示为大写字母 'D';若为其他类型的专用绑定,显示为小写字母 'd';若窗口未被专用绑定,则不显示该字符。详见《Emacs Lisp 参考手册》中关于专用窗口的内容。
若你按下
M-x a u TAB,此时 TAB 键会查找以 “au” 开头的补全候选项。U:**- *Completions* All L1 (Completion List)
fr
代表当前选中框架的名称(详见 “框架与图形化显示” 章节),仅在文本终端中显示。初始框架的名称为 'F1'。
buf
是窗口中显示的缓冲区名称,通常与你正在编辑的文件名一致。详见 “使用多缓冲区” 章节。
pos
用于提示窗口外的文本位置情况:若缓冲区内容较少且全部能在窗口中显示,会显示 'All';若当前查看的是缓冲区开头部分,显示 'Top';若查看的是末尾部分,显示 'Bot';其他情况则显示 'nn%',其中 'nn' 代表窗口上方的内容占整个缓冲区的百分比。启用
size-indication-mode后,还可以在模式行中显示缓冲区的大小。详见 “可选模式行功能” 章节。line
格式为字母 'L' 后接光标位置对应的行号。(启用 列号模式(
column-number-mode) 后,还可以显示当前光标所在的列数。详见 “可选模式行功能” 章节)。(major minor)
- major 代表缓冲区使用的
主模式名称。主模式是缓冲区的核心编辑模式,例如文本模式、Lisp 模式、C 语言模式等。详见 “主模式” 章节。部分主模式还会在名称后显示额外状态信息,例如编译缓冲区和 Shell 缓冲区会显示子进程的运行状态。 - minor 列出当前启用的部分
次模式。次模式是可选的编辑模式,能够在主模式的基础上提供额外功能。详见 “次模式“ 章节。
此外,部分功能即便不属于真正的次模式,只要处于开启状态,也会和次模式一同显示在该区域:
- major 代表缓冲区使用的
补充说明
若 Emacs 处于 递归编辑层级 ,包裹模式名称的圆括号会被方括号([…])包围;如果处于多层递归编辑状态,会显示双层方括号,以此类推。由于递归编辑层级是全局生效的,因此所有窗口的模式行都会显示对应的方括号标识。详见 “递归编辑层级” 章节。
你既可以修改模式行(mode line)的外观样式,也可以调整其内容格式,具体方法详见 “可选模式行功能” 章节。此外,模式行支持鼠标交互:点击模式行的不同区域可以执行对应的命令(详见 “模式行鼠标命令” 章节);将鼠标悬停在模式行的交互区域时,还会弹出工具提示框,显示该区域可触发的命令说明(详见 “工具提示” 章节)。
1.4. 菜单栏(Menu Bar)
每个 Emacs 框架(frame)的顶部通常都会有一个菜单栏(menu bar),你可以通过它执行各类常用操作。此处无需逐一列举这些操作,你自行查看会更为直观。
在支持鼠标的显示器上,你可以用鼠标从菜单栏中选择命令。菜单项右侧边缘的箭头,表示该选项会展开一个子菜单(submenu);菜单项(menu item)末尾带有 '…' 时,意味着执行该命令前,程序会提示你输入更多信息。
菜单栏中的部分命令同时配有常规的快捷键绑定(key bindings);若存在快捷键,会直接显示在对应菜单项的后方。若要查看某菜单项对应的完整命令名称及文档说明,可按下快捷键 C-h k ,随后按照常规方式用鼠标选中该菜单项即可(详见 “快捷键文档查询” 章节)。
除了使用鼠标,你也可以按下功能键 F10 来激活菜单栏的首个选项(该操作会执行 menu-bar-open 命令)。激活后,你可以通过方向键,或是快捷键 C-b(左)、C-f(右)、C-p(上)、C-n(下)来浏览菜单。按下回车键(RET)即可执行选中的菜单项;按下 C-g 或连续三次按下 ESC 键可退出菜单浏览模式。(注意:如果 Emacs 是基于图形界面工具包编译的,菜单的绘制与控制将由该工具包接管,此时退出菜单浏览模式的快捷键序列可能与上文描述不同。)
在文本终端中,你可以选择在回显区(echo area)中访问菜单栏(menu-bar)。要实现此功能,需将变量 tty-menu-open-use-tmm 自定义设置为非空值(non-nil)。完成设置后,按下 F10 键将执行 tmm-menubar 命令,而非直接展开菜单。(你也可以按下 M-` 组合键,该快捷键始终会调用 tmm-menubar 命令。) tmm-menubar 命令支持通过键盘选择菜单项,选中的候选选项会显示在回显区中。你可以使用上下方向键在菜单中切换不同选项,按下回车键确认选择。此外,每个菜单项都会分配一个字母或数字作为快捷选择符(通常取自菜单项名称中的某个单词首字母),该字符与菜单项名称之间用 '==>' 分隔,直接输入对应的字母或数字即可快速选中目标菜单项。
2. 用户输入类型
GNU Emacs 主要为 键盘操作 而设计。尽管你可以通过鼠标点击菜单栏和工具栏来执行编辑命令,但这种方式的效率通常不如键盘操作高。
Emacs 的键盘输入基于一套 高度扩展的 ASCII 字符集 。普通字符(例如 a、B、3、= 以及空格字符(记为 SPC))可直接敲击对应按键输入。控制字符(例如回车键 RET、制表符 TAB、删除键 DEL、退出键 ESC、功能键 F1、主页键 Home 以及左方向键 LEFT)同样通过这种方式输入,非英语键盘上的特定字符也是如此(详见 “国际字符集支持” 章节)。
Emacs 同样支持通过 修饰键(modifier keys) 输入控制字符。两种最常用的修饰键分别是 Control 键 (通常标注为 Ctrl)与 Meta 键 (通常标注为 Alt) 3。例如,输入 Control-a 的操作是按住 Ctrl 键的同时按下 a 键,我们将其简写为 C-a。同理,Meta-a(简写为 M-a)的输入方式是按住 Alt 键并按下 a 键。修饰键也可搭配非字母数字类字符使用,例如 C-F1 或 M-LEFT。
你也可以通过以 ESC 开头的双字符序列 来输入 Meta 字符。例如,输入 ESC 后再按下 a,等效于输入 M-a ;输入 ESC 后再按下 C-a ,等效于输入 C-M-a (即同时按住 Ctrl 键和 Alt 键,再按下 a 键)。与 Meta 键的操作方式不同, ESC 键需要作为独立字符输入:输入时无需按住 ESC 键再敲击后续字符,而是先按下并松开 ESC 键,之后再输入目标字符。该功能在部分 Meta 键工作不稳定的文本终端中十分实用。
Emacs 还支持另外 3 种修饰键,详见 “修饰键” 章节。
Emacs 对鼠标按键、鼠标滚轮,以及触控板、触摸屏等其他指针设备也提供了完善的支持,具体细节请参阅 “鼠标输入” 章节。
在图形化显示器中,窗口管理器可能会 拦截部分键盘输入 ,包括 M-TAB 、 M-SPC 、 C-M-d 和 C-M-l 。若遇到此类问题,你可以通过自定义窗口管理器设置,使其不再拦截这些按键;也可以重新绑定受影响的 Emacs 命令(详见 “自定义” 章节)。
普通字符、控制字符,以及鼠标点击等非键盘输入,在 Emacs 中统称为 输入事件 。关于 Emacs 内部如何处理输入事件的详细说明,参见《Emacs Lisp 参考手册》中的 “输入事件” 章节。
3. 按键(Keys)
部分 Emacs 命令仅需一个输入事件即可调用;例如, C-f 可在缓冲区中向前移动一个字符。另一些命令则需要两个或更多输入事件才能调用,比如 C-x C-f 与 C-x 4 C-f 。
按键序列 (简称按键)是指一组具有独立意义的一个或多个输入事件。若某一按键序列可以调用命令,则称之为 完整按键(complete key) ;例如, C-f 、 C-x C-f 和 C-x 4 C-f 均属于完整按键。若某一按键序列长度不足以调用命令,则称之为 前缀按键(prefix keys) ;从上述示例可知, C-x 和 C-x 4 均为前缀按键。所有按键序列要么是完整按键,要么是前缀按键。
前缀按键可与后续输入事件组合,形成更长的按键序列。例如, C-x 属于前缀按键,因此单独按下 C-x 并不会调用命令;相反,Emacs 会等待后续输入(若停顿超过一秒,它会回显 C-x 按键以提示用户输入后续内容,详见《回显区》章节)。 C-x 与下一个输入事件组合后,会生成一个双事件按键序列,该序列本身既可以是前缀按键(如 C-x 4 ),也可以是完整按键(如 C-x C-f )。按键序列的长度没有限制,但实际使用中很少超过三到四个输入事件。
无法在完整按键后追加输入事件。例如,由于 C-f 是完整按键,双事件序列 C-f C-k 会被视为两个独立的按键序列,而非一个。
默认情况下,Emacs 中的前缀按键(prefix keys)包括 C-c、C-h、C-x、C-x RET、C-x @、C-x a、C-x n、C-x r、C-x t、C-x v、C-x 4、C-x 5、C-x 6、ESC 和 M-g。(F1 和 F2 分别是 C-h 和 C-x 6 的别名)。该列表并非固定不变;用户可通过自定义 Emacs 来创建新的前缀按键,甚至可以移除部分标准前缀按键,但 不建议多数用户这样操作 ;例如,若移除 C-x 4 的前缀定义,那么 C-x 4 C-f 将变成无效的按键序列。详见《自定义按键绑定》章节。
在按下前缀按键后,再按下帮助字符( C-h 或 F1 ),会显示所有以此前缀开头的命令列表。此规则有一个例外: ESC C-h 等价于 C-M-h ,二者功能完全不同。不过,用户可以使用 F1 来查看所有以 ESC 开头的命令列表,即 ESC F1 。
4. 鼠标输入
默认情况下,Emacs 支持所有常规鼠标操作,例如单击鼠标左键定位光标、拖动鼠标指针选中区域。所有鼠标操作都可用于绑定命令,绑定方式与将命令绑定到键盘事件的方式完全相同(详见《按键》章节)。本节概述 Emacs 中的鼠标使用方法;关于 Emacs 鼠标命令的更多细节,可参考《用于编辑的鼠标命令》及其后续章节。
单击鼠标左键时,Emacs 会接收到 mouse-1 事件。若要查看该事件绑定的命令,你可以按下 C-h c ,随后单击鼠标左键。同理,鼠标中键对应的事件为 mouse-2 ,鼠标右键对应的事件为 mouse-3 。如果你的鼠标带有滚轮,滚轮事件通常会被绑定为 wheel-down (滚轮向下)、 wheel-up (滚轮向上),或 mouse-4 、 mouse-5 ,具体取决于操作系统的配置。
通常而言,旧式 X 系统与终端(详见《在文本终端中使用鼠标》)会上报 mouse-4 和 mouse-5 事件,其他所有系统则会上报 wheel-down 和 wheel-up 事件。
部分鼠标还配备了水平滚轮,触控板一般也支持水平滚动功能。在终端与旧式 X 系统之外的所有系统中,这类事件会被上报为 wheel-left (向左滚动)和 wheel-right (向右滚动);而在终端与旧式 X 系统中,对应的事件名称为 mouse-6 和 mouse-7 。
你也可以将键盘修饰键与鼠标事件组合使用,例如,你可以绑定一个特殊命令,使其在按住 Meta 键并单击鼠标中键时触发。这种情况下,对应的事件名称为 M-mouse-2 。
在部分系统中,你还可以为触屏事件绑定处理命令。此类事件的名称为 touchscreen-update (触屏更新)与 touchscreen-end (触屏结束)。
5. 按键与命令
本手册中多处会介绍特定按键的功能,但 Emacs 并非直接为按键赋予含义,而是先为 命名命令 定义功能,再通过 按键绑定 的方式,将按键与命令关联,以此赋予按键对应的作用。
每个命令都有一个由程序员定义的名称,这类名称通常由若干英文单词通过连字符连接而成,例如 next-line (下移一行)或 forward-word (前移一词)。在 Emacs 内部,每个命令本质上是一种特殊的 Lisp 函数,命令对应的具体操作,都是通过执行该函数来完成的。相关内容可参见《Emacs Lisp 参考手册》中的《什么是函数》章节。
按键与命令之间的绑定关系,会被记录在名为 键映射表(keymaps) 的表格中,详见《键映射表》章节。
当我们说 “快捷键 C-n 可实现垂直向下移动一行” 时,其实是简化了一个在日常使用中无需关注、但对 Emacs 定制至关重要的细节:真正执行 “垂直向下移动” 操作的是命令 next-line , C-n 之所以能实现该功能,是因为它被绑定到了 next-line 命令上。如果你将 C-n 重新绑定到 forward-word 命令,那么此后按下 C-n 时,光标就会向前移动一个单词,而非向下移动一行。
在本手册中,我们常会将 C-n 这类按键直接称作 “命令”,但严格来说,按键只是被绑定到了对应的命令上。 一般情况下,我们会在提及触发命令的按键后,用 括号 标注出真正执行操作的命令名称。例如,“命令 C-n (next-line) 可使光标垂直向下移动”,这句话的含义是: next-line 命令的功能是让光标垂直下移,而快捷键 C-n 默认与该命令绑定。
既然我们正在讨论定制相关的内容,就需要向你介绍 变量 的概念。在对命令的描述中,你常会看到这样的表述:“若要修改此功能,请设置变量 mumble-foo ”。变量是用于存储数值的命名标识符,本手册中介绍的大部分变量都支持用户定制:Emacs 的部分命令或功能模块会读取这些变量的值,并根据你设定的数值调整自身的行为逻辑。在你暂时没有定制需求时,可以忽略这些变量相关的内容;当你需要进行定制时,先阅读《变量》章节的基础内容,再查看各具体变量的说明,就能理解其作用了。
6. 触摸屏输入与虚拟键盘
Emacs 最初的设计,默认其用户是在台式计算机或计算机终端上使用它,这类设备会配备键盘,或许还会搭配鼠标这类合适的指针设备(参见《鼠标输入》章节)。
Emacs 同样支持接收来自其他输入设备的指令,即使用户将它安装在那些用其他输入方式、取代了传统 “键盘 + 鼠标” 组合的计算机上,也能顺畅地与之交互。
6.1. 触摸屏上使用 Emacs
触摸屏输入,是指通过手指、手写笔等操控工具,在显示 Emacs 窗口的显示器或计算机终端上执行点触、移动等操作,以此对窗口内的内容进行控制。
系统会将操控工具的 点触顺序 与 位置 这两个要素,和预先定义好的操作模式(称为 “手势”)进行比对,一旦匹配成功,就会在操控工具下方的文本区域执行该手势对应的一系列操作。目前 Emacs 支持识别的手势包括以下几种:
轻点(Tapping)
快速点触屏幕后抬起操控工具,该操作会选中被点触的窗口,并执行该窗口内此位置上绑定到
mouse-1的命令。如果该位置存在链接(参见《使用鼠标跳转至引用内容》章节),Emacs 会直接跳转至该链接(此行为与模拟mouse-1事件的操作有所区别)。滚动(Scrolling)
在屏幕上执行垂直或水平方向的连续移动,窗口会以操控工具初始位置为基准,朝着移动的方向滚动内容。用户可通过配置选项
touch-screen-enable-hscroll,控制该手势是否触发水平滚动功能(参见《水平滚动》章节)。拖拽(Dragging)
长按屏幕(将操控工具置于屏幕上并保持片刻)后再移动到其他位置,该操作会将光标移动到操控工具的初始位置,且在移动过程中选中工具下方的文本,效果等同于按住鼠标左键并拖动鼠标。相关内容可参见《用于编辑的鼠标命令》章节。
在触摸屏上精确定位操控工具存在一定难度,这会对文本选中操作造成影响。启用用户配置选项
touch-screen-word-select后,拖拽操作会自动选中操控工具下方的 完整单词 (默认情况下,选中范围仅会扩展至工具下方的单个字符)。同理,单次手势操作有时难以精准选中目标文本的全部内容。若启用用户配置选项
touch-screen-extend-selection,在窗口内的光标或选区标记位置轻点,即可启动一次新的 “拖拽” 手势,后续的移动操作会沿着移动方向扩展选区范围。操控工具在屏幕上的遮挡,可能会导致用户难以精准调整选区范围,而在回显区显示光标位置可缓解这一问题。当变量
touch-screen-preview-select的值非空时,在操控工具移动过程中,回显区(参见《回显区》章节)会显示光标所在行的内容,下方还会额外显示一行,用于标注光标在该行内的相对位置。捏合(Pinching)
将两个操控工具分开放置在屏幕上,再通过调整二者位置来增大或缩小间距,文本缩放比例(参见《文本缩放》章节)会随间距的变化比例同步调整。
当操控工具在屏幕上的停留时间超过 0.7 秒时,Emacs 会判定为一次长按操作。用户可通过自定义变量 touch-screen-delay ,调整该判定延迟的时长。
6.2. 搭配虚拟键盘使用 Emacs
当系统未连接物理键盘时,其窗口系统可能会提供一款屏幕内置的键盘 —— 即广泛使用的 虚拟键盘(virtual keyboard) 。该键盘包含多行可点击的按键,能够像实体键盘一样,向应用程序传递键盘输入指令。
由于虚拟键盘会占用宝贵的屏幕空间,因此当获得焦点的程序未请求文本输入时,虚拟键盘会处于隐藏状态。这就要求各类程序在准备好接收键盘输入后,主动将虚拟键盘调出。运行于 X 窗口系统的设备,会自动判断是否需要显示虚拟键盘;但在安卓等其他系统中,显示虚拟键盘的任务则由 Emacs 负责,触发场景通常为 触摸屏轻点手势 (参见《在触摸屏上使用 Emacs》章节),或是迷你缓冲区被调用时(参见《迷你缓冲区》章节)。
当轻点手势触发某条命令执行时,Emacs 会在列表 touch-screen-set-point-commands 中检索该命令,以此判断它是否用于设置光标位置。若该命令存在于列表中,且新光标位置对应的文本并非只读状态,Emacs 会激活虚拟键盘,以便用户输入内容。
touch-screen-set-point-commands 的默认值仅包含命令 mouse-set-point (参见《用于编辑的鼠标命令》章节),该命令是 mouse-1 的默认绑定命令,同时也是触摸屏轻点手势对应的默认命令。
用户配置选项 touch-screen-display-keyboard 可强制 Emacs 在 所有轻点手势触发时都显示虚拟键盘 ,即便对应文本处于只读状态;该选项也支持局部缓冲区配置,在此情况下,只要轻点显示该缓冲区的窗口,Emacs 就会自动调出虚拟键盘。
除此之外,Emacs 还提供了若干用于显示或隐藏虚拟键盘的函数,具体细节可参见《Emacs Lisp 参考手册》中的《屏幕内置键盘》章节。
由于 Emacs 在执行命令期间,可能无法调出虚拟键盘,因此它在那些通常不配备物理键盘的窗口系统中,实现了一项特殊功能:双击设备上始终存在的某个硬件按键,即可触发退出操作。相关内容可参见《退出与终止》章节。
X 窗口系统默认未启用此类按键,但用户可通过变量 x-quit-keysym 进行配置;在安卓系统中,默认的触发按键为音量减小键,用户同样可通过变量 android-quit-keycode 对其进行修改。
大多数为虚拟键盘设计的输入法,其文本编辑逻辑与桌面端输入法存在差异。
在传统桌面窗口系统中,输入法会直接在屏幕上显示正在输入的字符内容,待用户确认后,再将对应的按键事件发送给 Emacs。
与之不同的是,虚拟键盘输入法会 直接对各窗口帧的活动窗口执行文本编辑操作 ,这种方式在 X 窗口系统中被称为 文本转换 或 字符串转换 。
只要局部缓冲区变量 text-conversion-style 的值非空,Emacs 就会启用这类输入法,这一机制通常适用于 text-mode (文本模式)与 prog-mode (编程模式)的派生模式。
文本转换操作的执行是异步的:当 Emacs 收到输入法的转换请求,且当前未处于 “已读取前缀按键、等待完整按键序列” 的状态时(参见《按键》章节),就会触发文本转换。转换完成后,系统会发送一个 text-conversion 事件,具体可参见《Emacs Lisp 参考手册》中的《杂项事件》章节。
若输入法需要对缓冲区中的某一区域进行处理,该区域会被标记为 待转换区域*(或 *称预处理区域 )。变量 text-conversion-face 用于控制是否使用特殊的字体样式显示该区域,若启用,则可指定具体的字体样式。
7. 启动 Emacs
调用 Emacs 的常规方式是在 Shell 中执行命令 emacs 。在图形界面终端中运行 Unix Shell 时,你可以通过 emacs & 在后台启动 Emacs,这种方式不会占用终端窗口,你仍然可以在终端中执行其他 Shell 命令。(在微软视窗系统中启动 Emacs 的类似方法,参见《微软视窗系统下的 Emacs 启动方式》章节)。
Emacs 启动后,初始窗口会显示一个名为 *GNU Emacs* 的特殊缓冲区。这个启动界面包含了关于 Emacs 的介绍信息,以及对新手用户实用的常用任务链接。例如,激活 “Emacs Tutorial” 链接会打开 Emacs 教程,其功能等同于执行命令 C-h t (help-with-tutorial)。激活链接的方式有两种:一是将光标移至链接处并按下 RET (回车键),二是用 mouse-1 (鼠标左键) 点击该链接。
你可以通过 命令行参数 ,让 Emacs 在启动时直接打开一个或多个文件。例如,执行 emacs foo.txt 会启动 Emacs,并在缓冲区中显示文件 foo.txt 的内容。该功能主要是为了兼容其他编辑器 —— 这类编辑器通常设计为从 Shell 启动,用于短时间的编辑会话。若以这种方式启动 Emacs,初始窗口会被拆分为两个子窗口:一个显示指定的文件,另一个显示启动界面。相关内容参见《多窗口》章节。
通常情况下,每次编辑文件都重新启动 Emacs 既无必要,也会造成资源浪费。推荐的使用方式是:登录系统后只启动一次 Emacs,所有的编辑工作都在同一个 Emacs 会话中完成。关于打开多个文件的方法,参见《文件处理》章节。采用这种方式使用 Emacs 时,会话会累积大量实用的上下文信息,例如 king ring(剪切环) 、 registers(寄存器) 、 undo history(撤销历史) 和 mark ring data(标记环数据) ,这些功能会让编辑操作更加便捷,本手册后续章节会对其进行详细介绍。
当 Emacs 处于运行状态时,若想从其他程序中编辑文件,你可以借助辅助程序 emacsclient ,在已有的 Emacs 会话中打开目标文件。相关内容参见《将 Emacs 用作服务器》章节。
Emacs 支持其他类型的命令行参数,例如指定加载特定的 Lisp 文件、设置初始窗口的位置等。具体内容参见《Emacs 启动命令行参数》章节。
若变量 inhibit-startup-screen 的值非空,Emacs 将不会显示启动界面。这种情况下,如果命令行中指定了一个或多个文件,Emacs 会直接显示这些文件;反之,会打开一个名为 *scratch* 的缓冲区,你可以在该缓冲区中交互式地执行 Emacs Lisp 表达式。相关内容参见《Lisp 交互缓冲区》章节。你可以通过 自定义功能 (参见《简易自定义界面》章节),或编辑初始化文件(参见《Emacs 初始化文件》章节)来设置 inhibit-startup-screen 的值 4。
你也可以通过设置变量 initial-buffer-choice ,强制 Emacs 在启动时显示指定的文件或目录 —— 只需将该变量的值设为对应文件或目录的路径字符串即可。 initial-buffer-choice 的值也可以是一个无参函数,该函数需要返回一个缓冲区供 Emacs 显示。若 initial-buffer-choice 的值非空,即便命令行中指定了文件,Emacs 仍会加载这些文件,但不会在启动时直接显示。
8. 退出 Emacs
C-x C-c- 退出 Emacs(执行
save-buffers-kill-terminal命令)。 C-z- 在文本终端中,挂起 Emacs;在图形界面中,将选中的窗口图标化(或 “最小化”)(执行
suspend-frame命令)。
退出 Emacs 即终止 Emacs 程序。操作方法为按下 C-x C-c (save-buffers-kill-terminal)。采用双字符按键序列是为了防止误触。若按下该组合键时,存在任何已修改但未保存的文件缓冲区,Emacs 会首先提示你保存这些缓冲区。若你未将所有缓冲区保存,程序会再次请求确认,因为未保存的修改将会丢失。此外,若仍有子进程在运行,Emacs 也会要求确认退出操作 —— 退出 Emacs 的同时会终止这些子进程(参见《从 Emacs 执行 Shell 命令》章节)。
若你将 Emacs 用作服务器, C-x C-c 的行为会略有不同。在客户端窗口中按下该组合键,只会关闭对应的客户端连接。详见《将 Emacs 用作服务器》章节。
你可以选择让 Emacs 在退出时记录特定的会话信息,例如当前打开的文件。这些信息会在下次启动 Emacs 时生效。详见《保存 Emacs 会话》章节。
若变量 confirm-kill-emacs 的值为非 nil,按下 C-x C-c 时,Emacs 会将该变量的值视作一个断言函数并调用它。若函数返回值为非 nil,则终止当前会话;反之,Emacs 会继续运行。将函数 yes-or-no-p 设为 confirm-kill-emacs 的值是一种便捷的用法。该变量的默认值为 nil 。
若变量 confirm-kill-processes 的值为 nil ,Emacs 在终止其启动的子进程前不会请求确认。该变量的默认值为 t 。
若需进一步自定义 Emacs 的退出行为,请参见《GNU Emacs Lisp 参考手册》中的《退出 Emacs》章节。
若需直接退出 Emacs 且不弹出保存提示,可执行命令 M-x kill-emacs 。
C-z 对应命令 suspend-frame 。在图形界面中,该命令会将选中的 Emacs 窗口最小化(或图标化),隐藏窗口的同时保留恢复的可能(具体隐藏方式取决于对应的窗口系统)。在文本终端中, C-z 会挂起 Emacs,临时暂停程序运行并将控制权交还给父进程(通常为 Shell);在多数 Shell 环境中,你可以通过命令 %emacs 恢复挂起的 Emacs 进程。
文本终端通常会监听一些特殊字符,用于终止或挂起当前运行的程序。但在 Emacs 运行期间,终端的这一功能会被禁用。Emacs 将 C-z 和 C-x C-c 设为退出相关快捷键,灵感源于部分操作系统中用 C-z 和 C-c 终止或暂停程序的设计,但二者仅存在这一设计关联,与操作系统本身的功能并无直接联系。你可以自定义这些按键,将其绑定为任意命令(参见《键盘映射》章节)。
9. 基本编辑命令
本节将介绍文本输入、修改以及文件保存的基础操作。如果你是 Emacs 新手,建议先通过按下组合键 C-h t (help-with-tutorial) 运行 Emacs 实践教程。
9.1. 插入文本
按下对应按键,即可输入普通可打印字符(例如 a、B、3、=)。输入的字符会被插入到光标位置的缓冲区中,且光标会随文本插入自动后移,始终停留在新插入文本的后方。相关概念详见光标章节。
按下 RET 回车键(newline)可以换行并开始新的一行。(你的键盘上 RET 键可能标注为 Return 、 Enter ,或是一个指向左侧的特殊箭头符号,但本手册统一称其为 RET 。)该命令会在缓冲区中插入一个换行符,随后根据当前主模式自动缩进(详见缩进章节)。
- 若光标位于行尾,执行该命令会在当前行下方新建一行空白行,并对新行进行缩进;
- 若光标位于行中间,则会在光标位置将当前行拆分为两行,并缩进新行。
- 如需关闭自动缩进功能,你可以选择禁用 Electric Indent 模式(详见缩进便捷功能章节),或是按下
C-j键 —— 该快捷键仅插入换行符,不会触发自动缩进。
正如本手册后续章节所述,你可以通过开启次要模式(minor mades)来修改 Emacs 的文本插入行为。例如:
- 自动换行模式(Auto Fill mode) 会在文本行过长时自动换行(详见文本填充章节);
- 覆盖模式(Overwrite mode) 会让新输入的字符覆盖原有文本,而非将原有文本右移(详见次要模式章节)。
只有可打印字符能够通过按键直接输入;其他按键仅作为编辑命令触发相应功能,不会插入按键对应的字符。例如,默认情况下按下 DEL 键会执行 delete-backward-char 命令(部分模式会将其绑定为其他命令),而非插入一个字面意义上的 DEL 字符(ASCII 编码为 127)。
若要插入非打印字符,或是键盘上没有对应按键的字符,需要先按下 C-q (quoted-insert) 进行转义。 C-q 有两种使用方式:
- 按下
C-q后,再按下任意非打印字符(包括C-g),即可插入该字符本身。例如C-q DEL会插入一个字面意义上的 DEL 字符。 - 按下
C-q后,输入一串八进制数字,即可插入对应八进制编码的字符。你可以输入任意位数的八进制数字,遇到非数字字符时,输入序列即终止。- 若终止符为
RET,则该RET仅用于结束序列,不会额外执行换行操作; 若终止符为其他非数字字符,则该字符会在终止序列后作为普通输入生效。例如,输入
C-q 1 0 1 B会插入字符 AB(八进制 101 对应 ASCII 字符 A)。注意:在普通的非二进制覆盖模式下,八进制序列输入功能会被禁用。这样设计是为了方便你直接插入数字字符,而非用其覆盖原有文本。
- 若终止符为
若你希望使用十进制或十六进制编码(而非八进制)插入字符,可以将变量 read-quoted-char-radix 的值设为 10(十进制)或 16(十六进制)。当基数设为 16 时,字母 a 到 f 会被当作数字的一部分参与编码,且不区分大小写。
部分常用的 Unicode 字符可通过以 C-x 8 开头的快捷键插入。例如:
- 按下
C-x 8 [会插入左单引号 ‘(Unicode 编码 U+2018,也被称为左弯引号); - 同理,
C-x 8 ]、C-x 8 {、C-x 8 }会分别插入右单引号 ’、左双引号 “ 和右双引号 ”。 - 此外,若你的键盘上的
Alt键可正常工作,按下Alt+[等效于C-x 8 [(插入左单引号),以此类推(除非Alt键后紧跟的是RET键)。若要查看所有支持C-x 8快捷键的字符,可按下C-x 8 C-h查询。
你也可以使用命令 C-x 8 RET (insert-char) 插入字符:该命令会通过迷你缓冲区提示你输入目标字符的 Unicode 名称或编码。
- 输入名称时,命令支持补全功能(详见补全章节);
- 输入编码时,需使用十六进制数(Unicode 标准格式),或带基数标识的数字(例如八进制数
#o23072)。相关规则详见《Emacs Lisp 参考手册》中的整数基础章节。 - 输入完成后,对应字符会被插入到缓冲区中。
以下几种操作均可插入同一个左单引号 ‘ 字符:
C-x 8 RET left single quotation mark RET C-x 8 RET left sin TAB RET #利用补全功能 C-x 8 RET 2018 RET #输入十六进制编码) C-x 8 [ Alt+[ #若 Alt 键可用 ` #在智能引号模式(Electric Quote mode) 下
在执行 C-q 或 C-x 8 ... 类命令时,可添加数字参数(详见数字参数章节),指定要插入的字符重复次数。
除 C-x 8 外,你还可以通过以下方式插入特殊字符:先按下 C-u C-x \ iso-transl RET 选择对应的临时输入法,随后按下 C-x \ [ ,同样可以插入左单引号 ‘(详见临时输入法章节)。
此外,在部分场景下,即便不使用 C-x 8 类命令,输入特定格式的引号也会自动转换为弯引号:
输入 `like this' (使用反引号和单引号),会自动转换为 ‘like this’ ;
输入 ``like this'' (使用双反引号和双单引号),会自动转换为 “like this” 。相关规则详见引号格式章节。
9.2. 更改光标位置
若要执行 插入字符之外 的操作,你必须掌握移动光标的方法(详见光标章节)。快捷键 C-f 、 C-b 、 C-n 、 C-p 分别用于将光标向右、向左、向下、向上移动。你也可以使用多数键盘上的 arrow keys(方向键) : RIGHT 、 LEFT 、 DOWN 、和 UP 移动光标,但许多 Emacs 用户认为,方向键的操作效率低于控制键,原因是操作方向键时需要移动手部位置。
你还可以点击鼠标左键,将光标移动到点击的位置。Emacs 同时提供了多种功能更丰富的快捷键,可实现光标的灵活移动。
C-f- 向前移动一个字符 (
forward-char) RIGHT- 对应命令 (
right-char) 功能与C-f类似,但在从右至左排版的段落中行为会有差异(详见双向文本编辑章节) C-b- 向后移动一个字符 (
backward-char) LEFT- 对应命令 (
left-char) 功能与C-b类似,但在从右至左排版的段落中行为会有差异(详见双向文本编辑章节) C-nDOWN- 向下移动一行 (
next-line) 。该命令会尽量保持光标水平位置不变,例如若光标初始在某行中间位置,移动后会停在下一行的对应水平位置 C-pUP- 向上移动一行 (
previous-line) 。与C-n类似,该命令会保持光标在该行的水平位置 C-aHome- 移动到行首 (
move-beginning-of-line) C-eEnd- 移动到行尾 (
move-end-of-line) M-f- 向前移动一个单词 (
forward-word)。详见单词章节 C-RIGHTM-RIGHT- 功能与
M-f类似,但在从右至左排版的段落中会向后移动一个单词(详见双向文本编辑章节) M-b- 向后移动一个单词 (
backward-word)。详见单词章节 C-LEFTM-LEFT- 功能与
M-b类似,但在从右至左排版的段落中会向前移动一个单词(详见双向文本编辑章节) M-r在不移动屏幕文本的前提下,将光标定位到窗口内垂直居中行的左边缘;连续重复执行该命令时,光标会按循环顺序依次定位到窗口的首行、末行左边缘,以此类推,对应命令 (
move-to-window-line-top-bottom) 。- 若带数字参数,则表示将光标定位到从窗口顶部向下数的第 n 行(参数 0 代表窗口首行);
- 若参数为负数,则表示从窗口底部向上数的第 n 行(参数 -1 代表窗口末行)。
关于数字参数的更多用法,详见数字参数章节。
M-<- 移动到缓冲区开头 (
beginning-of-buffer) 。若带数字参数n,则移动到距离缓冲区开头n/10比例的位置。在图形界面中,快捷键C-HOME等效于此命令。 M->- 移动到缓冲区末尾 (
end-of-buffer) 。在图形界面中,快捷键C-END等效于此命令。 C-vPageDownnext- 向下滚动一屏内容,并在需要时将光标移动到屏幕可视区域内 (
scroll-up-command),详见滚动章节。 M-vPageUpprior- 向上滚动一屏内容,并在需要时将光标移动到屏幕可视区域内 (
scroll-down-command),详见滚动章节。- 快捷键命名逻辑:在 Emacs 术语中,
prior对应键盘上的PageUp键,next对应PageDown键,两者仅命名不同,功能完全一致。
- 快捷键命名逻辑:在 Emacs 术语中,
M-g c- 读取一个数字
n,并将光标移动到缓冲区的第n个字符位置(缓冲区起始位置为 1)。若光标当前位于或紧邻缓冲区中的某个数字,则该数字会作为n的默认值,直接按下RET回车键即可使用。你也可以通过给M-g c添加数字前缀参数的方式指定 n。 M-g M-gM-g g读取一个数字
n,并将光标移动到第n行的开头(对应命令goto-line,缓冲区首行编号为 1)。若光标当前位于或紧邻缓冲区中的某个数字,则该数字会作为n的默认值,直接按下RET回车键即可使用。你也可以通过给M-g M-g添加数字前缀参数的方式指定 n。若为该命令添加普通前缀参数,其行为会有所不同,详见创建与选择缓冲区章节;此外,你也可以使用goto-line-relative命令,将光标移动到相对于受限缓冲区可见部分的指定行。goto-line命令拥有独立的历史记录列表(详见迷你缓冲区历史章节)。通过自定义用户选项goto-line-history-local,你可以选择让所有缓冲区共享同一历史列表(默认行为),或是为每个缓冲区分别配置独立的历史列表。M-g TAB- 读取一个数字
n,并将光标移动到当前行的第n列(最左侧列编号为 0)。若为该命令添加前缀参数,则直接以参数的数值作为目标列号。 C-x C-n- 将光标当前所在列设为当前缓冲区的半永久目标列(对应命令
set-goal-column)。当半永久目标列生效时,C-n、C-p、PageUp和PageDown命令在垂直移动光标后,会自动将光标定位到该目标列,或尽可能接近该列的位置。目标列设置会一直生效,直至被手动取消。 C-u C-x C-n- 取消半永久目标列设置。此后
C-n和C-p命令会恢复默认行为,即保持光标水平位置不变。
当缓冲区中的某行文本长度超过窗口宽度时,Emacs 通常会将其拆分为多行显示,这种显示行也被称为 可视行(visul lines) 。为方便操作, C-n 、 C-p 以及方向键 down 、 up 均基于可视行移动光标。若你希望这些命令基于 逻辑行(logical line) (即缓冲区中实际存储的文本行)移动,可将变量 line-move-visual 的值设为 nil ;此时若某一逻辑行被拆分为多行可视行,光标会直接跳过额外的可视行。相关细节详见续行章节,变量设置方法详见变量章节。
与 C-n 、 C-p 不同,Emacs 中大多数针对行的命令均基于逻辑行(logical lines)执行。例如 C-a (move-beginning-of-line 移动到行首) 和 C-e ( move-end-of-line 移动到行尾)命令,分别作用于逻辑行的开头和结尾。后续遇到基于可视行工作的命令(如 C-n 、 C-p )时,我们会特别指出。
当 line-move-visual 的值为 nil 时,你还可以将变量 track-eol 设为非 nil 值。此时若光标初始位于某逻辑行的行尾,执行 C-n 或 C-p 命令后,光标会移动到下一行或上一行的行尾。该变量的默认值为 nil 。
默认情况下,若在缓冲区的最后一行执行 C-n 命令,光标会停在该行末尾不再移动。但如果你将变量 next-line-add-newlines 设为非 nil 值,在缓冲区最后一行执行 C-n 时,Emacs 会自动在末尾新建一行,并将光标移动到新行中。
9.3. 删除文本
DELBACKSPACE- 删除光标前的字符;若 选区处于激活状态 ,则删除选区内的文本 (
delete-backward-char) Delete- 删除光标后的字符或 字符簇 ;若选区处于激活状态,则删除选区内的文本 (
delete-forward-char) C-d- 删除光标后的字符 (
delete-char) C-k- 剪切至行尾 (
kill-line) M-d- 向前剪切至下一个单词的末尾 (
kill-word) 即移除光标右边一整个词 M-DEL- (no term)
M-BACKSPACE向后剪切至前一个单词的开头 (backward-kill-word),即移除光标左侧一整个词
DEL (delete-backward-char) 命令会删除光标前的字符,并将光标及后方所有字符向前移动一位。若光标原本位于行首,执行该命令会删除前一行的换行符,从而将当前行与上一行合并。
但如果 选区处于激活状态 ,DEL 命令的行为会变为删除选区内的所有文本。关于选区的详细说明,详见标记与选区章节。
在大多数键盘上, DEL 键标注的是 BACKSPACE ,但本手册统一称其为 DEL(注意不要与 Delete 键混淆,后文会介绍 Delete 键的功能)。在部分文本终端中,Emacs 可能无法正确识别 DEL 键,若遇到此问题可参考当 DEL 键无法删除时章节的解决方案。
Delete (delete-forward-char) 命令的删除方向与 DEL 相反:它会删除光标后的字符,也就是光标当前所在位置的字符。若光标原本位于行尾,执行该命令会将当前行与下一行合并。和 DEL 命令一样,当选区处于激活状态时,该命令会删除选区内的文本(详见标记与选区章节)。
此外,若光标后的字符与后续字符组合成一个 字符簇 (即多个字符合并为一个显示单元), Delete 命令会一次性删除整个字符簇序列。这一点与 DEL 命令不同 —— DEL 命令始终只会删除单个字符,即便该字符属于某个字符簇。
C-d (delete-char) 命令同样用于删除光标后的字符,功能与 Delete 键类似,但 该命令不会受选区激活状态的影响 ,始终只删除光标后的单个字符。
关于上述删除命令的更多详细信息,详见删除操作章节。
C-k (kill-line) 命令用于一次性剪切整行内容。
- 若在一行文本的开头或中间位置按下
C-k,该命令会剪切从光标位置到行尾的所有文本; - 若在行尾按下
C-k,该命令会将当前行与下一行合并。
关于 C-k 及相关命令的更多信息,详见剪切与移动文本章节。
9.4. 撤销更改
C-/C-x uC-_- 撤销一条撤销记录项 —— 通常对应一次命令的操作效果(
undo撤销功能)。(在纯文本模式的显示终端中,第一个快捷键可能无法使用)
Emacs 会记录缓冲区文本中发生的所有更改操作,因此你可以撤销近期的修改。这项功能通过 undo 实现,该命令绑定了三组快捷键: C-/ 、 C-x u 和 C-_ 。默认情况下,执行该命令会撤销上一次的修改操作,并将光标移回修改前的位置。需要注意的是,撤销命令 仅作用于缓冲区的文本更改 ,无法用于撤销光标的移动操作。
在支持所有按键组合 Control 修饰键的终端上,调用撤销功能最便捷的方式是使用 C-/ ,因为该快捷键无需搭配 Shift 键。而在仅支持 ASCII 控制字符的终端中, C-/ 这一组合键本身并不存在,但在多数此类终端中,按下 C-/ 实际会向 Emacs 发送 C-_ 指令;此外还有不少终端允许你在输入 C-_ 时省略 Shift 键(等效于按下 C-- ),因此这种方式也成了调用撤销功能的便捷选择。
尽管每次编辑命令通常会在撤销记录中生成独立的条目,但一些极为简单的命令可能会被合并为一条记录。反之,对于部分复杂命令,一条撤销记录有时仅能覆盖其操作的一部分内容。
重复按下 C-/ (或其等效快捷键),每一次重复操作都会撤销更早的一项修改,直至撤销记录的上限。若所有已记录的修改操作都已被撤销,撤销命令会输出一条错误提示信息,且不会执行任何操作。
如需了解撤销命令的更多详情,请参见《撤销》章节。
9.5. 文件操作
你在 Emacs 缓冲区中输入的文本,仅会在当前 Emacs 会话期间保留。若要将文本永久保存,你必须将其写入 文件 中。
假设你的主目录下有一个名为 test.emacs 的文件。若要在 Emacs 中开始编辑该文件,输入以下指令:
C-x C-f test.emacs RET
在此命令中,文件名是作为 C-x C-f (find-file) 命令的参数传入的。该命令会通过 minibuffer迷你缓冲区 读取参数,你需要按下回车键( RET )来确认参数输入(详见《迷你缓冲区》章节)。
Emacs 执行这条命令的方式是 访问 该文件:它会创建一个新的缓冲区,将文件内容复制到该缓冲区中,随后显示这个缓冲区以供编辑。如果你修改了缓冲区中的文本,可以按下 C-x C-s (save-buffer),将修改后的内容写回 test.emacs 文件,实现文本的永久保存。在执行保存操作之前,修改后的文本仅存在于 Emacs 缓冲区中,源文件 test.emacs 不会发生任何变化。
若要新建一个文件,只需直接使用 C-x C-f 命令访问这个尚不存在的文件即可。此时 Emacs 会创建一个空缓冲区,你可以在其中输入需要写入该文件的文本内容。当你第一次按下 C-x C-s 保存这个缓冲区时,Emacs 才会在系统中实际创建该文件。
如需了解在 Emacs 中使用文件的更多详情,请参见《文件处理》章节。
9.6. 帮助功能
如果你忘记了某个按键的功能,可以按下 C-h k (describe-key),紧接着按下想要查询的按键;例如,输入 C-h k C-n 就能查看 C-n 按键的作用。
前缀键 C-h 代表 “帮助” 功能。功能键 F1 是 C-h 的等效快捷键。除了 C-h k 之外,还有许多其他的帮助命令,可提供各类不同的帮助信息。
有关详情,请参见《帮助》章节。
9.7. 空行处理
本节介绍用于插入和删除空行的专用命令与操作技巧。
- C-o
- 在光标后方插入一行空行 (
open-line) 。 - C-x C-o
- 将连续的多行空行删减为仅保留一行 (
delete-blank-lines) 。
我们此前已经了解到,按下 RET (newline) 可以新建一行文本。不过,先插入一行空行,再在空行中输入目标文本,会让操作过程更清晰易见。使用快捷键 C-o (open-line)即可轻松实现这个操作,该命令会在光标位置后方插入一个换行符,同时保持光标停留在换行符之前。执行 C-o 后,你就可以直接在新行中输入文本内容。
连续按下多次 C-o ,即可插入多行空行;也可以为该命令指定 数字参数 ,以此设定需要插入的空行数量,具体用法详见《数字参数》章节。若你设置了 填充前缀 ,当在行首位置按下 C-o 时,该命令会自动在新插入的空行中添加填充前缀,相关内容详见《填充前缀》章节。
删除多余空行的便捷方法是使用命令 C-x C-o (delete-blank-lines) 。当光标处于连续多行空行的范围内时, C-x C-o 会将这些空行删减为仅保留一行;当光标位于单行空行上时, C-x C-o 会直接删除这行空行;当光标位于非空行上时, C-x C-o 会删除该行之后的所有空行(如果存在的话)。
9.8. 续行(Continuation Lines)
有时,缓冲区中的一行文本——即 logical line逻辑行 ——过长而无法完全显示在窗口内,Emacs会将其显示为两行或多行 screen lines 屏幕行 (或 visual lines视觉行 )。这称为 line wrapping换行 或 continuation续行 ,而较长的逻辑行则被称为 continued line续行 。在图形界面中,Emacs 会通过左右窗口边缘的弯曲小箭头,以此标记续行的起止;在文本终端中,Emacs 则会在屏幕行的右边界显示一个反斜杠字符 ‘\‘ 来标识续行。
大多数针对 “行” 执行操作的命令,作用对象都是 逻辑行 而非屏幕行。例如, C-k 命令会删除一整行逻辑行。但前文提到的 C-n (next-line) 和 C-p (previous-line) 是两个特殊例外:它们的作用是分别将光标向下或向上移动 一行屏幕行 (详见《光标位置调整》章节)。
Emacs 也可以选择对过长的逻辑行执行 truncate截断 而非续行处理。截断模式下,每条逻辑行仅占用一行屏幕行;如果逻辑行长度超过窗口宽度,超出部分将不会被显示。在图形化界面中,被截断的行会在窗口右侧提示区显示一个小型直箭头;在文本终端中,该行的右边界则会显示一个美元符号 $。详见《行截断》章节。
默认情况下,续行的折行位置是窗口的右边缘。由于折行可能发生在单词的中间位置,这类续行的可读性会比较差。常规的解决方法是在逻辑行过长之前手动插入换行符,将其拆分为较短的行。如果你需要,也可以启用 auto-fill-mode 自动填充模式,让 Emacs 在逻辑行长度达到阈值时自动插入换行符。详见《文本填充》章节。
默认状态下,每条续行的首字符都会对齐到其所在屏幕行的行首位置。次要模式 visual-wrap-prefix-mode 及其全局版本 global-visual-wrap-prefix-mode (详见《次要模式》章节),可以让续行在显示时自动根据该行上下文生成 填充前缀 (详见《填充前缀》章节)并进行缩进。这些前缀仅用于显示效果,不会对缓冲区中的文本内容产生任何修改。
在某些场景下,你可能需要编辑包含大量超长逻辑行的文件,此时逐一添加换行符来拆分这些行并不现实。这种情况下,你可以启用 Visual Line mode 视觉行模式 ,该模式支持 word wrapping按单词折行 :Emacs 不会在窗口右边缘的位置强制折行,而是会在最接近右边缘的单词边界处(即空格或制表符的位置)进行折行。同时,视觉行模式还会重新定义部分编辑命令(如 C-a 、 C-n 、 C-k )的作用对象,使其针对 屏幕行 而非逻辑行执行操作。详见《视觉行模式》章节。
9.9. 光标位置信息
本节介绍用于获取缓冲区各部分尺寸与位置信息,以及统计单词和行数的命令。
M-x what-line- 显示光标所在行的行号。
M-x line-number-modeM-x column-number-mode- 切换当前行号或列号的自动显示功能。相关内容请参考《可选模式行功能》。若你希望在每一行前方显示行号,请参考《显示自定义》。
M-=- 统计并显示选区范围内的行数、句数、单词数和字符数 (
count-words-region) 。关于选区的说明,请参考《标记与选区》。 M-x count-words- 统计并显示整个缓冲区的行数、句数、单词数和字符数。若选区处于激活状态(详见《标记与选区》),则会改为统计选区范围内的对应数据。
C-x =- 显示光标后一个字符的字符编码、光标在缓冲区中的字符位置,以及光标所在列号 (
what-cursor-position) 。 M-x hl-line-mode- 启用或关闭当前行的高亮显示功能。相关内容请参考《光标显示》。
M-x size-indication-mode- 切换缓冲区大小的自动显示功能。相关内容请参考《可选模式行功能》。
M-x what-line 命令会在回显区显示当前行的行号。由于模式行本身就会显示当前行号(详见《模式行》),该命令通常显得有些多余。但在缓冲区被缩窄的情况下,模式行仅会显示相对于当前可访问区域的行号(详见《缓冲区缩窄》)。相比之下, what-line 会同时显示相对于缩窄区域的行号,以及相对于整个缓冲区的行号。
M-= (count-words-region) 会在回显区输出一条消息,报告选区范围内的行数、句数、单词数和字符数(选区的概念解释见《标记与选区》)。若带上前缀参数执行 C-u M-= ,该命令则会统计整个缓冲区的对应数据。
M-x count-words 命令的功能与上述命令一致,只是调用方式不同。当选区处于激活状态时,它会统计选区数据;反之,则统计整个缓冲区的数据。
C-x = (what-cursor-position) 会显示当前光标位置的相关信息,以及该位置对应的缓冲区内容。它会在回显区输出如下格式的一行内容:
Char: c (99, #o143, #x63) point=28062 of 36168 (78%) column=53 字符:c(十进制 99,八进制 #o143,十六进制 #x63) 光标位置=28062/36168(78%) 列号=53
在 “Char:” 之后,显示的是光标所在位置的缓冲区字符;括号内的内容依次为该字符对应的十进制、八进制和十六进制编码。关于 C-x = 命令显示字符信息的更多细节,请参考《国际字符集简介》。“point=” 后面的数字是光标在缓冲区中的字符计数位置(缓冲区第一个字符的位置为 1,第二个为 2,以此类推);其后的数字代表缓冲区的总字符数;括号内的百分比表示光标位置占总字符数的比例。“column=” 后面的数字是光标在窗口中的水平位置,即相对于窗口左边缘的列数。
若用户选项 what-cursor-show-names 的值不为 nil,则还会显示该字符在 Unicode 字符数据库中定义的名称。此时,括号内的内容会变为:
(99, #o143, #x63, LATIN SMALL LETTER C)
当缓冲区被缩窄,导致开头和结尾的部分文本暂时无法访问时, C-x = 会额外显示一行描述当前可访问范围的内容。例如:
Char: C (67, #o103, #x43) point=252 of 889 (28%) <231-599> column=0
其中,额外显示的两个数字分别代表光标允许处于的最小和最大字符位置,这两个数值之间的字符即为当前可访问的内容。相关内容请参考《缓冲区缩窄》。
与之相关但功能不同的还有 display-line-numbers-mode (详见《显示自定义》)。
9.10. 数字参数(Numeric Arguments)
在数学与计算机领域的术语中,参数( argument ) 指的是 “传递给函数或操作的数据”。你可以为任意 Emacs 命令指定一个数值参数(也称为 prefix argument前缀参数)。部分命令会将该参数解读为重复执行的次数。例如,为 C-f 命令指定参数 10 时,光标会向前移动 10 个字符,而非默认的 1 个。对于这类命令,不指定参数等效于参数值为 1,而负参数则会让命令的执行方向或作用效果反向。
指定数值参数的常用方式
指定数值参数最简便的方法是:按住 Meta 键的同时输入数字或负号。例如:
M-5 C-n
该操作会让光标向下移动 5 行。 M-1 、 M-2 等按键,以及 M-- ,都被绑定到了对应的命令 (digit-argument 与 negative-argument),其作用是为后续要执行的命令设置参数。不带数字的 M-- 默认表示参数值为 -1。
若要输入多位数的参数,输入第一个数字时需要按住 Meta 键,后续数字则无需再按住。例如,要向下移动 50 行,可按下:
M-5 0 C-n
需要注意的是,这个操作 并不会 像你可能预想的那样,先插入 5 个字符 0 再向下移动 1 行 —— 这里的 0 会被视作前缀参数的一部分。
(如果确实需要插入 5 个字符 0 该怎么做?可以按下 M-5 C-u 0 。其中 C-u 的作用是终止前缀参数的输入,让后续的按键触发你真正要执行的命令。请注意, C-u 的这个用法仅适用于此场景,其常规作用见下文说明。)
除了 M-1、M-2 这种方式,还可以通过 C-u (universal-argument) 搭配数字来指定数值参数;若要指定负参数,则输入 C-u 后接负号与数字即可。不带数字的负号默认表示参数值为 -1。
C-u 的特殊用法
单独按下 C-u 有一个特殊含义 ——“ 4 倍执行 ”:它会将后续命令的默认执行次数乘以 4。连续按下两次 C-u(即 C-u C-u )则是乘以 16。例如, C-u C-u C-f 会让光标向前移动 16 个字符。其他实用的组合操作包括:
C-u C-n:向下移动 4 行C-u C-u C-n:向下移动 16 行(约占屏幕的一部分)C-u C-u C-o:插入 16 个空行C-u C-k:删除 4 行文本
为自插入字符指定数值参数
在输入一个自插入字符之前指定数值参数,可以一次性插入该字符的多个副本。如果该字符不是数字,操作会非常直观:
- 例如
C-u 6 4 a会插入 64 个字符 a。 - 但这个方法不适用于插入数字字符 ——
C-u 6 4 1会被识别为指定参数值为 641,而非插入 64 个字符 1。若要实现后者,需要用另一个C-u分隔参数与要插入的数字,例如按下C-u 6 4 C-u 1,即可插入 64 个字符 1。
命令对数值参数的不同解读方式
忽略参数值,仅判断是否存在参数
部分命令只关心是否传入了参数,而不关注参数的具体数值。例如命令
M-q(fill-paragraph段落重排):无参数时仅对段落进行换行整理;有参数时则会同时对文本进行两端对齐处理。(关于M-q的更多信息,请参考《文本填充》章节)。对于这类命令,只需按下一次C-u来指定参数即可。参数作为重复次数,但无参数时执行特殊逻辑
部分命令会将参数值作为重复次数,但无参数时会执行特殊操作。例如命令
C-k(kill-line) :传入参数 n 时,会删除 n 行文本(包含行尾的换行符);但无参数时的行为特殊 —— 它会删除光标到下一个换行符之间的文本;若光标恰好位于行尾,则直接删除该行的换行符。因此,连续执行两次无参数的C-k可以删除一行非空文本,效果等同于执行带参数 1 的C-k命令。(关于C-k的更多信息,请参考《文本的删除与移动》章节)。特殊的参数处理规则
少数命令会将单独的
C-u与普通数值参数区别对待,还有极少数命令会将仅含负号的参数(M--)与参数值 -1 区别对待。这些特殊情况会在对应命令的说明中提及;设计这些特殊规则的目的是让单个命令的使用更便捷,相关细节可查阅命令的文档字符串。
术语说明
我们使用 prefix argument 前缀参数 这一术语,是为了强调这类参数需要在命令执行之前输入,以此区分迷你缓冲区参数(参考《迷你缓冲区》章节)—— 这类参数需要在调用命令之后输入。
在图形化界面中, C-0 、 C-1 等按键的作用与 M-0 、 M-1 等完全相同。
9.11. 重复执行命令
许多简单命令(例如通过单个按键或 M-x 命令名 RET 调用的命令),都可以通过为其指定一个用作 重复次数 的数值参数来重复执行(详见《数值参数》章节)。但如果待重复的命令需要提示输入内容,或者会以其他方式使用数值参数,这种方法就不再适用。
命令 C-x z (repeat) 提供了另一种多次重复执行 Emacs 命令的方式。该命令会重复执行 上一条 Emacs 命令,无论这条命令原本是什么。重复执行时会沿用该命令上一次使用的参数,不会在每次重复时重新读取新参数。
若要将命令重复执行多次,只需在按下 C-x z 后继续输入更多的 z :每多输入一个 z ,命令就会再重复执行一次。当你输入 z 以外的字符,或按下鼠标按键时,重复执行的操作就会终止。
举个例子,假设你按下 C-u 2 0 C-d 删除了 20 个字符。此时你可以通过输入 C-x z z z ,将这条删除命令(包含它的参数)再重复执行 3 次,总共删除 80 个字符。其中第一次的 C-x z 会让命令重复执行 1 次,后续每多输入一个 z ,就会再重复执行 1 次。
你还可以激活 repeat-mode 重复模式,该模式允许你通过输入单个字符,来重复执行那些绑定在 两个或更多按键组合 上的命令。例如,在你按下 C-x u ( undo 详见《撤销》章节)撤销最近一次编辑操作后,可以继续输入 u u u… 来撤销更多次编辑。同理,若要切换到相隔多个窗口的目标窗口,你可以直接输入 C-x o o o… ,而无需重复按下完整的 C-x o C-x o C-x o… 组合键。
这个功能的实现逻辑是:当你按下调用命令的完整按键序列后,Emacs 会进入一个 临时重复模式 ;可供重复执行的单键快捷操作会显示在回显区中。
并非所有命令都支持在 repeat-mode 重复模式下重复执行;你可以输入 M-x describe-repeat-maps RET 查看支持该功能的命令列表。
临时重复模式启用的单键快捷操作 不必完全相同 :例如,在你按下 C-x { 后,输入 {、}、^、v 中的任意一个字符,或是以任意顺序混合输入这些字符,都能以对应的方式调整选中窗口的大小。类似地,在按下 M-g n 或 M-g p 后,以任意顺序输入一系列 n 或 p,就能重复执行 next-error 下一个错误和 previous-error 上一个错误命令,在 *compilation* (编译)或 *grep* (全局搜索)缓冲区中进行导航(详见《编译模式》章节)。
当你输入除重复命令绑定按键之外的任意按键时,临时重复模式会立即退出,且你输入的这个按键会按常规逻辑执行对应的操作。你也可以自定义一个专用按键,使其仅用于退出临时重复模式,而不执行该按键本身对应的命令。要实现这个功能,只需将用户选项 repeat-exit-key 自定义为目标按键即可;一个很自然的选择是将 RET (回车键)设为退出键。
最后,你还可以设置让重复链在闲置一段时间后自动中断:将用户选项 repeat-exit-timeout 自定义为指定的闲置时长(单位为秒),超过这个时长后,临时重复模式就会自动关闭。
10. 迷你缓冲区(Minibuffer)
minibuffer 迷你缓冲区是 Emacs 命令读取复杂参数的区域,例如文件名、缓冲区名称、Emacs 命令名或 Lisp 表达式。我们将其称为 “minibuffer迷你缓冲区”,是因为它是一块占用屏幕空间较小的专用缓冲区。你可以在迷你缓冲区中使用常规的 Emacs 编辑命令,对参数文本进行编辑。
10.1. 使用迷你缓冲区
当迷你缓冲区处于激活状态时,它会显示在回显区中,且带有一个光标。迷你缓冲区的开头会显示一段提示信息,通常以冒号结尾。这段提示会说明当前需要输入的参数类型,以及该参数的用途。提示信息会使用 minibuffer-prompt 这个显示样式进行高亮(详见《文本显示样式》章节)。
输入迷你缓冲区参数最简便的方式是:直接输入文本内容,然后按下回车键( RET )提交参数并退出迷你缓冲区。此外,你也可以按下 C-g 键,通过取消当前请求参数的命令来退出迷你缓冲区(详见《退出与终止》章节)。
在某些情况下,提示信息中会在冒号前的括号内显示一个默认参数。如果你直接按下回车键,程序就会使用这个默认参数执行命令。例如,读取缓冲区名称的命令通常会将某个缓冲区名称设为默认值;你按下回车键后,命令就会对这个默认缓冲区执行操作。你可以通过用户选项 minibuffer-default-prompt-format 来自定义默认参数的显示方式。
如果你启用了"Minibuffer Electric Default 迷你缓冲区动态默认模式" (这是一个全局次要模式),那么一旦你修改了迷你缓冲区中的内容,Emacs 就会自动隐藏默认参数(因为此时按下回车键提交的不再是该默认值)。当你恢复迷你缓冲区的原始文本内容后,提示信息会再次显示默认参数。要启用这个次要模式,可输入 M-x minibuffer-electric-default-mode 执行命令。
由于迷你缓冲区显示在回显区中,它的使用可能会与回显区的其他用途产生冲突。如果迷你缓冲区处于激活状态时,系统输出了错误信息或提示信息,该信息会以方括号包裹的形式,显示在迷你缓冲区文本的后方,持续几秒钟后自动消失;或者在你输入任意内容后立即消失。在迷你缓冲区的使用过程中,Emacs 不会回显你按下的按键。
使用迷你缓冲区时,你可以切换到其他frame(框架),方便查阅需要输入的文本内容(详见《框架命令》章节)。默认情况下,处于激活状态的迷你缓冲区会跟随切换到新的frame。如果你将用户选项 minibuffer-follows-selected-frame 的值设为 nil,迷你缓冲区就会停留在最初打开它的frame,你必须切换回该frame,才能完成(或终止)当前命令。若将该选项的值设为一个既非 nil 也非 t 的值,那么只有在当前命令中打开了递归迷你缓冲区后(详见《Emacs Lisp 手册》中的《递归迷你缓冲区》章节),迷你缓冲区才会跟随切换frame。这个选项的主要作用是让 Emacs 的行为与 28.1 版本之前的旧逻辑保持(大致)一致。请注意,当你最终完成迷你缓冲区的操作后,命令的执行效果始终会作用于最初打开迷你缓冲区的那个frame。唯一的例外情况是:如果该frame已经不存在,命令才会在当前选中的frame(框架)中执行。
10.2. 文件名专用迷你缓冲区
诸如 C-x C-f (find-file) 这类命令,会通过迷你缓冲区读取文件名参数(详见《文件》章节)。当迷你缓冲区用于读取文件名时,其初始文本通常会以一个斜杠结尾,这段文本即为默认目录。例如,迷你缓冲区可能会显示如下内容:
Find file: /u2/emacs/src/
这里的 'Find file:' 是提示信息,'u2/emacs/src' 是默认目录。此时若输入 buffer.c 作为参数,就代表指定了文件 /u2/emacs/src/buffer.c 。关于默认目录的更多信息,请参考《文件名》章节。
你可以按下 M-n 来调取其他可选的文件名默认值,相关操作详见《迷你缓冲区历史记录》章节。
你可以使用 .. 来指定上级目录下的文件:路径 /a/b/../foo.el 等价于 /a/foo.el 。此外,也可以按下 M-DEL 来反向删除目录名称(详见《单词操作》章节)。
若要指定一个完全不同目录下的文件,你可以按下 C-a C-k 清除整个默认目录文本(详见《迷你缓冲区中的编辑操作》章节)。或者你也可以忽略默认目录,直接在其后方输入以斜杠或波浪号开头的绝对文件名。例如,你可以通过以下方式指定文件 /etc/termcap :
Find file: /u2/emacs/src//etc/termcap
连续两个斜杠会让 Emacs 忽略这对斜杠中第二个斜杠之前的所有内容。在上面的例子中, /u2/emacs/src/ 会被忽略,因此你实际指定的参数是 /etc/termcap 。如果终端支持的话,文件名中被忽略的部分会显示为灰色。(若要关闭该灰色显示功能,可执行命令 M-x file-name-shadow-mode 关闭文件名遮蔽模式。)
在补全远程文件名时(详见《远程文件》章节),连续两个斜杠的行为会略有不同:它只会让 Emacs 忽略文件名部分,保留其余内容(如连接方式、主机地址、用户名等)不变。连续输入三个斜杠,则会忽略远程文件名中的所有内容。相关细节请参考《Tramp 手册》中的《文件名补全》小节。
Emacs 会将 ~/ 解析为你的主目录。因此路径 ~/foo/bar.txt 指的是,位于主目录下 foo 目录中的文件 bar.txt 。除此之外, ~user-id/ 表示登录名为 user-id 的用户对应的主目录。波浪号之前的所有前置目录名称都会被忽略:例如路径 /u2/emacs/~/foo/bar.txt 等价于 ~/foo/bar.txt 。
在 MS-Windows 和 MS-DOS 操作系统中,用户不一定都有主目录,因此 Emacs 会采用多种替代方案。关于 MS-Windows 系统的相关配置,请参考《MS-Windows中的 HOME 目录与启动目录》章节;关于 MS-DOS 操作系统的配置,请参考《MS-DOS 操作系统中的文件名》章节。在这些系统中, ~user-id/ 格式仅对当前用户生效,也就是说,只有当用户标识与当前登录用户的用户名一致时,该格式才能正常解析。
若要阻止 Emacs 在读取文件名时自动插入默认目录,可将变量 insert-default-directory 的值设为 nil。设置后,迷你缓冲区的初始状态会变为空白,但相对文件名参数的解析仍然会基于原有的默认目录。
你同样可以在迷你缓冲区中输入远程文件名,相关内容请参考《远程文件》章节。
10.3. 迷你缓冲区中的编辑操作
迷你缓冲区本质上也是一个 Emacs 缓冲区,只是特性比较特殊,你可以使用常规的 Emacs 命令编辑参数文本。(但提示信息是 read-only 只读的,无法修改。)
由于在迷你缓冲区中按下 RET 键的作用是提交参数,因此无法用它来插入换行符。若要插入换行,你可以按下 C-q C-j ,这个组合键会插入一个 C-j 控制字符,其功能与换行符完全等价(详见《插入文本》章节)。除此之外,也可以使用 C-o (open-line) 命令来实现换行(详见《空行操作》章节)。
在迷你缓冲区中,按键 TAB 、 SPC 和 ? 通常会被绑定到补全命令,让你无需手动输入完整文本,就能快速补全目标内容,相关内容详见《补全功能》章节。和 RET 键类似,你可以通过 C-q 来插入 TAB 、 SPC 或 ? 这些字符本身。如果希望按下 SPC 和 ? 时直接插入字符,而非触发补全功能,可以在初始化文件中添加以下配置:
(keymap-unset minibuffer-local-completion-map "SPC") (keymap-unset minibuffer-local-completion-map "?")
为了操作便利,在迷你缓冲区中按下 C-a ( move-beginning-of-line 移动到行首) 时,光标会跳到参数文本的开头,而非提示信息的开头。例如,你可以通过 C-a C-k 的组合操作快速清除整个参数文本。
当迷你缓冲区处于激活状态时,回显区的表现和普通 Emacs 窗口基本一致。比如,你可以按下 C-x o 切换到其他窗口,在那里编辑文本后,再切回迷你缓冲区窗口继续输入参数。你甚至可以在其他窗口中剪切文本,回到迷你缓冲区后将其粘贴到参数中。不过迷你缓冲区窗口也存在一些限制,比如无法对其执行拆分操作(详见《多窗口》章节)。
默认情况下,迷你缓冲区窗口只占用一行屏幕空间。但如果输入的文本超过一行,它会自动扩展高度以容纳内容。变量 resize-mini-windows 用于控制迷你缓冲区的自动调整行为,其默认值为 grow-only ,也就是前面所说的 “只自动扩展,不自动收缩”。若将该变量设为 t ,当删除迷你缓冲区中的部分文本行后,窗口也会自动收缩,最小会缩至一行高度。若设为 nil,迷你缓冲区窗口不会自动调整大小,但你可以用常规的窗口调整命令手动修改其尺寸(详见《多窗口》章节)。
变量 max-mini-window-height 用于限制迷你缓冲区窗口的最大高度。若将其设为浮点数,代表窗口最大高度为框架高度的对应比例;若设为整数,则代表窗口最大可占用的行数;若设为 nil ,则禁用迷你缓冲区的自动调整功能。该变量的默认值为 0.25。
当某些命令在其他窗口中显示帮助文本时,你可以在迷你缓冲区中按下 C-M-v 来滚动查看这些帮助信息。同时也支持使用 M-PageUp 和 M-PageDown (等价于 M-prior 和 M-next )来滚动,这个功能在查看冗长的补全候选列表时尤为实用(详见《使用其他窗口》章节)。
默认情况下,Emacs 不允许在迷你缓冲区处于激活状态时,调用那些同样会使用迷你缓冲区的命令。若要启用这一功能,需要将变量 enable-recursive-minibuffers 的值设为 t 。当迷你缓冲区被递归调用时,你可能还需要启用 minibuffer-depth-indicate-mode ,让提示信息中显示当前的递归深度。
迷你缓冲区处于激活状态时,通常会进入 minibuffer-mode (迷你缓冲区模式)。这是一个 Emacs 内部模式,没有额外的特殊功能。
当迷你缓冲区未激活时,会处于 minibuffer-inactive-mode (迷你缓冲区非激活模式),此时在该区域单击鼠标左键,会打开 *Messages* 缓冲区。如果你的迷你缓冲区有专用的框架,Emacs 还会在该区域识别部分快捷键,例如按下 n 键可以新建一个框架。
10.4. 自动补全(Completion)
你通常可以借助一项名为 completion补全 的功能来辅助输入参数。该功能的作用是:在你输入部分参数文本后,Emacs 能够根据已输入的内容,自动补全剩余的全部或部分文本。
当补全功能可用时,迷你缓冲区中的部分按键(通常是 TAB 、 RET 和 SPC )会被重新绑定为专用的补全命令(详见《补全命令》章节)。这些命令会依据当前请求参数的命令所提供的补全候选列表,尝试补全迷你缓冲区中的文本。你通常可以按下 ? 来查看完整的补全候选列表。
尽管补全功能通常在迷你缓冲区中使用,但该功能有时也可在普通缓冲区中启用。相关内容详见《符号名称补全》章节。
10.4.1. 补全示例
通过一个简单示例或许能更好地理解补全功能。 M-x 命令会通过迷你缓冲区读取待执行的命令名,因此补全功能的实现逻辑是:将迷你缓冲区中的输入文本与已有的 Emacs 命令名进行匹配。假设你希望执行 auto-fill-mode (自动填充模式)命令,既可以直接输入 M-x auto-fill-mode RET 来调用,不过使用补全功能会更便捷。
若你按下 M-x a u TAB ,此时 TAB 键会查找以 “au” 开头的补全候选项(本例中即命令名)。符合条件的命令有多个,包括 auto-fill-mode 和 autoconf-mode 等,但这些命令名的共同前缀是 “auto”,因此迷你缓冲区中的 “au” 会补全为 “auto”。(在你的 Emacs 会话中,可能还定义了更多命令。例如,若存在一个名为 authorize-me 的命令,Emacs 最多只能补全到 “aut” 这一步。)
如果立即再次按下 TAB ,由于无法确定下一个字符(可能是 “-”、“a” 或 “c”),TAB 不会添加任何字符,而是会在另一个窗口中显示所有可能的补全候选列表。
接下来输入 “-f”,此时迷你缓冲区中的内容为 “auto-f”,而以该字符串开头的命令名只有 auto-fill-mode 。若此时按下 TAB ,补全功能会将参数剩余部分 “auto-fill-mode” 填充到迷你缓冲区中。
由此可见,只需输入 a u TAB - f TAB ,就能完成 "auto-fill-mode" 命令名的输入。
即便光标不在迷你缓冲区的末尾, TAB 键同样可以触发补全。这种情况下,补全功能会同时在光标位置和迷你缓冲区末尾填充文本。例如,你先输入 M-x autocm ,再按下 C-b 将光标移到 “m” 之前,此时按下 TAB ,Emacs 会在光标位置插入文本 “onf-”,并在迷你缓冲区末尾插入 “ode”,最终迷你缓冲区中的内容会变为 “autoconf-mode”。
10.4.2. 补全命令
以下是启用补全功能时,迷你缓冲区(minibuffer)中定义的 list of the completion补全命令列表 。
TAB- 尽可能补全迷你缓冲区中的文本;若无法补全,则显示所有可能的补全候选列表
SPC- (空格键) 补全光标位置之前的文本,仅补全到下一个连字符或空格处
C-x UP- 调用迷你缓冲区历史记录进行文本补全
C-x DOWN- 调用迷你缓冲区默认值进行文本补全
RET- (回车键) 将迷你缓冲区中的文本作为参数提交,提交前可能会先执行补全操作。详情参见《补全退出》
?- 显示补全候选列表及若干实用快捷键绑定 (
minibuffer-completion-help) M-DOWNM-UP- 遍历补全候选列表
M-vM-g M-cPageUpprior- 在迷你缓冲区中操作时,切换到显示补全列表的窗口
RET- 在补全缓冲区中, 选中光标所在位置的补全候选
mouse-1mouse-2- (鼠标按键) 在补全缓冲区中,点击鼠标选中对应位置的补全候选
TABRIGHTn- 在补全缓冲区中, 移动到下一个补全候选
S-TABLEFTp- 在补全缓冲区中,移动到上一个补全候选
q- 关闭补全窗口,切换回迷你缓冲区窗口
z- 关闭并删除补全缓冲区及其对应的窗口
TAB (minibuffer-complete) 是最基础的补全命令。它会搜索所有与迷你缓冲区现有文本匹配的补全候选,并尽可能完成补全。补全候选的筛选规则详见《补全候选的选择方式》。
SPC (minibuffer-complete-word) 的补全逻辑与 TAB 类似,但仅补全到下一个连字符或空格为止。例如:若迷你缓冲区中已有文本 'auto-f',按下空格键后,补全结果为 'auto-fill-' (而非完整的 'auto-fill-mode');再次按下空格键,才会补全为完整的 'auto-fill-mode' 。注意:该命令不适用于包含空格的参数类型(如文件名)。
当 TAB 或 SPC 无法完成补全时,会在新窗口中显示匹配的补全候选列表(若存在候选),同时展示若干用于选择候选的实用命令。你也可以按下 ? (minibuffer-completion-help) ,主动调出补全列表和帮助信息。补全列表的相关操作命令如下:
在迷你缓冲区或补全缓冲区中,按下 M-DOWN (minibuffer-next-completion) 和 M-UP (minibuffer-previous-completion) 可遍历补全缓冲区中的候选。当变量 minibuffer-completion-auto-choose 设为非 nil(默认配置)时,遍历操作会同时将当前候选插入迷你缓冲区;若该变量设为 nil ,可按下 M-RET (minibuffer-choose-completion) 将候选插入迷你缓冲区。默认情况下,按下 M-RET 会退出迷你缓冲区;若添加前缀参数( C-u M-RET ),则仅插入候选,不退出迷你缓冲区。
在迷你缓冲区中按下 M-v ,可切换到显示补全列表的窗口 (switch-to-completions),方便后续操作。 PageUp 、 prior 、 M-g M-c 也可实现该功能。你也可以通过其他方式切换窗口(详见《多窗口操作》)。
在补全缓冲区中,按下 RET 可选中光标所在候选 (choose-completion) ;点击鼠标左键( mouse-1 )或中键( mouse-2 )也可选中对应位置的候选。若添加前缀参数( C-u RET ),则仅将光标所在候选插入迷你缓冲区,不退出迷你缓冲区,便于重新选择其他候选。
在补全缓冲区中,按下 TAB 、 RIGHT 或 n 可移动到下一个补全候选 (next-completion) ;按下 S-TAB 、 LEFT 或 p 可移动到上一个补全候选 (previous-completion) 。
你还可以基于当前命令的迷你缓冲区输入历史完成补全:按下 C-x UP (minibuffer-complete-history) ,其功能与 TAB 类似,但补全候选来源为迷你缓冲区历史记录,而非默认候选池。类似地, C-x DOWN (minibuffer-complete-defaults) 会调用当前命令提供的默认输入项进行补全。
最后,按下 q 会关闭补全窗口并切换回迷你缓冲区窗口 (quit-window) ;按下 z 会直接关闭并删除补全缓冲区及其窗口 (kill-current-buffer)。
若将变量 minibuffer-visible-completions 自定义为非 nil 值,箭头键的绑定功能会发生变化:此时箭头键不再用于移动迷你缓冲区中的光标,而是像默认的元箭头键(M-方向箭头)一样遍历补全候选;同时,按下 RET 会选中当前候选(功能等同于默认的 M-RET )。按下 C-g 会隐藏补全窗口,但保持迷你缓冲区处于激活状态,你可以继续在提示符后输入内容。
10.4.3. 补全退出
当一个命令通过带补全功能的迷你缓冲区读取参数时,它同时会控制你按下 RET 回车键 (minibuffer-complete-and-exit) 提交参数时的行为。该行为分为四种类型:
Strict completion严格补全仅接受精确匹配的补全结果。只有当迷你缓冲区中的文本本身是精确匹配项,或者可以补全为某个精确匹配项时,按下RET回车键才会退出迷你缓冲区。反之,Emacs 会拒绝退出迷你缓冲区;它会尝试执行补全操作,若无法完成补全,则会在迷你缓冲区文本后短暂显示"[Not match]"。(你仍然可以按下C-g取消该命令,从而退出迷你缓冲区。)使用这种行为的命令示例是
M-x,因为对它而言,接受一个不存在的命令名是没有意义的。Cautious completion谨慎补全的行为与严格补全类似,区别在于只有当文本本身已是精确匹配项时,按下RET回车键才会退出。如果文本可以补全为某个精确匹配项,按下RET回车键只会执行补全操作,但不会立即退出;你需要再次按下RET回车键才能退出迷你缓冲区。例如,读取必须已存在的文件对应的文件名时,就会使用谨慎补全。
Permissive completion宽松补全允许输入任意内容;补全候选项仅作为参考建议。按下RET回车键不会触发补全操作,只会直接提交你当前输入的内容作为参数。Permissive completion with confirmation带确认的宽松补全的行为与宽松补全基本一致,仅存在一个例外情况:当你按下制表键(TAB)并将文本补全至某个中间状态(即尚未形成精确匹配的补全结果)时,若紧接着按下RET回车键,系统不会直接提交该参数。取而代之的是,Emacs 会在文本后短暂显示"[Confirm]"以要求你确认;再次按下RET回车键,即可确认并提交该文本。这种机制可以避免一个常见误操作 —— 用户在未意识到TAB制表键未完成预期补全的情况下,误按RET回车键提交内容。你可以通过自定义变量
confirm-nonexistent-file-or-buffer来调整上述确认行为。该变量的默认值为after-completion,对应上述的默认行为。若将其值改为nil,Emacs 将不再要求确认,直接退化为宽松补全模式。若将其值设为其他非 nil 的值,无论前序操作是否为按下TAB制表键,Emacs 都会要求你进行确认。大多数读取文件名的命令(如
C-x C-f)和读取缓冲区名的命令(如C-x b),都会采用这种带确认的宽松补全行为。
10.4.4. 补全候选的选择规则
补全命令的工作原理是,从一长串可能的补全候选项中,筛选出与你在迷你缓冲区中输入内容相匹配的较小子集。在《补全示例》一节中,我们给出了一个此类匹配的简单案例。判断何为匹配项的过程十分精细复杂,Emacs 会尝试在大多数情况下提供合理的补全结果。
Emacs 会借助 一种或多种 completion styles补全风格 来执行补全操作 —— 补全风格是一套判定迷你缓冲区文本与补全候选项是否匹配的标准。补全过程中,Emacs 会依次尝试每种补全风格:若某一种风格筛选出一个或多个匹配项,这些匹配项就会被作为补全候选项列表;若该风格未筛选出任何匹配项,Emacs 就会继续尝试下一种风格。
列表变量 completion-styles 用于指定要使用的补全风格,列表中的每个元素都是一种补全风格的名称(一个 Lisp 符号)。所有可用的风格符号都存储在变量 completion-styles-alist 中(参见《Emacs Lisp 参考手册》中的《补全变量》一节)。默认的补全风格按顺序排列如下:
basic(基础风格)- 匹配的补全候选项,其开头部分必须与迷你缓冲区中光标之前的文本完全一致。此外,若迷你缓冲区中光标之后还有文本内容,则补全候选项的剩余部分必须包含该文本作为子串。
partial-completion(部分补全风格)这种主动的补全风格会将迷你缓冲区中的文本按连字符或空格分割为多个单词,再对每个单词分别进行补全。(例如,补全命令名时,输入 "em-l-m" 会被补全为 "emacs-lisp-mode"。)
除此之外,迷你缓冲区文本中的星号 '*' 会被当作通配符 —— 它可以匹配补全候选项对应位置上的任意字符序列。
emacs22(Emacs22 风格)- 这种补全风格与 basic 风格类似,区别在于它会忽略迷你缓冲区中光标之后的文本。该风格以此命名,是因为它与 Emacs 22 版本中的补全行为完全一致。
以下额外的补全风格同样已被定义,你可以根据需要将它们添加到 completion-styles 中(参见《自定义》一节):
substring(子串风格)匹配的补全候选项,必须同时包含迷你缓冲区中光标之前的文本和光标之后的文本作为子串,且两个子串的顺序需与原文本一致。
例如,若迷你缓冲区中的文本为 'foobar',且光标位于 'foo' 与 'bar' 之间,那么 'afoobbarc' 会被判定为匹配项(其中 a、b、c 可以是任意字符串,包括空字符串)。
flex(灵活风格)- 这种主动的补全风格也被称为
flx、fuzzy模糊补全或scatter分散补全,它会尝试基于 有序子串 进行补全。例如,它会将 'foo' 判定为与 'frodo' 或 'fbarbazoo' 相匹配。 initials(首字母风格)- 这种补全风格的匹配策略非常主动,它会尝试针对缩写词和首字母缩写进行补全。例如,补全命令名时,它会将 'lch' 匹配为 'list-command-history'。
还有一种极为简单的补全风格名为 emacs21 。在该风格下,若迷你缓冲区中的文本为 'foobar',则只有以 'foobar' 开头的候选项会被视为匹配项。
你可以通过设置变量 completion-category-overrides ,在不同场景下使用不同的补全风格。例如,该变量的默认配置规定,针对缓冲区名称仅使用 basic 和 substring 这两种补全风格。
10.4.5. 补全选项
在补全 区分大小写的参数 (例如命令名)时,大小写是有意义的。例如,补全命令名时,输入 'AU' 不会补全为 'auto-fill-mode'。而在补全不区分大小写的参数时,大小写差异会被忽略。
补全文件名时,若变量 read-file-name-completion-ignore-case 的值为非 nil,则大小写差异会被忽略。该变量的默认值在区分大小写文件名的系统(如 GNU/Linux)上为 nil ;在不区分大小写文件名的系统(如微软 Windows)上为非 nil。补全缓冲区名时,若变量 read-buffer-completion-ignore-case 的值为非 nil,则大小写差异会被忽略,该变量的默认值为 nil。
补全文件名时,Emacs 通常会忽略某些被判定为 不太可能 被选中的候选项,具体由列表变量 completion-ignored-extensions 决定。该列表中的每个元素都应为一个字符串;任何文件名以该字符串结尾的文件,都会被排除在补全候选项之外。若列表元素以斜杠(/)结尾,则代表该元素是一个子目录名。 completion-ignored-extensions 的标准值包含多个元素,例如 ".o"、".elc" 和 ”~“ 。举例来说,若某个目录下存在 "foo.c" 和 "foo.elc" 两个文件,输入 'foo' 会补全为 'foo.c'。但如果 所有 可能的补全候选项的后缀都属于被忽略的字符串,那么这些候选项将不会被忽略:以上述例子来说,输入 'foo.e' 会补全为 'foo.elc'。需要注意的是,当 Emacs 在补全列表中展示候选项时,会忽略 completion-ignored-extensions 这个变量的配置。
Shell 补全是文件名补全的扩展版本,具体可参见《Shell 模式选项》一节。
若将 completion-auto-help 的值设为 nil ,补全命令将不会自动显示补全列表缓冲区;你必须手动输入 ? 来查看候选项列表。若该变量的值为 lazy ,Emacs 仅会在第二次尝试补全时展示补全列表缓冲区。也就是说,若当前无内容可补全,第一次按下 TAB 会提示 “Next char not unique 后续字符不唯一”;第二次按下 TAB 才会弹出补全列表缓冲区。若该变量的值为 always ,则每次尝试补全时,补全列表缓冲区都会自动显示。
补全列表缓冲区首次显示后,其后续的显示状态同样由 completion-auto-help 控制。若该变量的值为 t 或 lazy ,当 Emacs 能够完成补全时,展示补全候选项的窗口会自动收起;而当你输入新内容后再次出现无法补全的情况时,该窗口可能会重新弹出。若变量值为 always ,则只有当你退出补全操作时,该窗口才会收起。若变量值为 visible ,则该配置属于混合模式:在决定是否弹出补全列表窗口时,它的行为与 t 一致;在决定是否收起该窗口时,它的行为与 always 一致。
Emacs 支持在弹出补全列表窗口时,自动选中该窗口。若要启用此功能,可将用户选项 completion-auto-select 自定义为 t ,这会改变 TAB 键在补全窗口弹出时的行为:按下 TAB 会切换到补全列表缓冲区,之后你可以通过光标移动命令选中目标候选项,并按下 RET 确认选择。若 completion-auto-select 的值为 second-tab ,则第一次按下 TAB 会弹出补全列表缓冲区,第二次按下 TAB 才会切换到该缓冲区。
当补全列表窗口被选中时(无论是通过自定义 completion-auto-select 实现,还是手动按下 C-x o 切换窗口),按下 UP and DOWN 上下方向键 ( previous-line-completion 和 next-line-completion ) 可以在补全候选项之间逐行切换;若在按下方向键时附带数字前缀参数,则可以一次跳过对应行数的候选项。若变量 completion-auto-wrap 的值为非 nil,那么当光标移动到候选项列表的顶端或底端时,会自动循环到另一端。
若变量 completion-cycle-threshold 的值为非 nil,补全命令可以循环遍历所有补全候选项。在默认情况下,当迷你缓冲区中的文本存在多个补全候选项时,补全命令会补全到这些候选项的最长公共子串。若将 completion-cycle-threshold 的值改为 t ,补全命令会优先补全为第一个候选项;此后每次调用补全命令,都会循环替换为下一个候选项。若将该变量的值设为一个数字 n ,则只有当候选项数量小于等于 n 时,补全命令才会触发这种循环补全的行为。
默认情况下,Emacs 会弹出一个新的缓冲区来展示补全候选项,且候选项会按 horizontal 水平方向排列,排列的列数取决于当前窗口的宽度。你可以通过自定义用户选项 completions-format 来修改这一排列方式。若该选项的值为 vertical ,Emacs 会改为垂直排列候选项;若值为 one-column ,则所有候选项会被排列在同一列中。
用户选项 completions-sort 用于控制 *Completions* 缓冲区中候选项的排序规则,其默认值为 alphabetical ,即按字母顺序排序。若值为 nil ,则禁用排序功能;若值为 historical ,则会先按字母顺序排序,再根据迷你缓冲区的历史记录调整候选项的顺序。该选项的值也可以是一个函数,Emacs 会将补全候选项列表传入该函数,函数需返回排序后的候选项列表。
若变量 completions-max-height 的值为非 nil,则该变量会限制补全窗口的大小。其取值为行数,且包含模式行、标题行以及底部分隔线(若存在)。如果需要更精细地控制补全窗口的显示属性,可以使用变量 display-buffer-alist (具体可参见《Emacs Lisp 参考手册》中的《缓冲区显示的动作列表》一节)。
变量 completions-header-format 是一个格式规范字符串,用于控制补全候选项列表上方的信息提示行。若该字符串中包含 '%s' 占位符,则该占位符会被替换为补全列表缓冲区中展示的候选项数量。若要隐藏该信息提示行,可将该变量自定义为 nil 。该变量的值(即提示行字符串)可以设置文本属性,从而改变提示行的视觉外观;常用的属性包括 face (字体)和 cursor-intangible (光标不可见)(具体可参见《Emacs Lisp 参考手册》中的《具有特殊含义的属性》一节)。
若变量 completions-highlight-face 指向某个有效的字体(face),则当前补全候选项(即按下 RET 或鼠标点击时会被选中的候选项)会用该字体高亮显示。该变量的默认值为 completions-highlight ;若将其设为 nil ,则会禁用高亮功能。此特性依赖于特殊文本属性 cursor-face 实现。
10.5. 迷你缓冲区历史记录
你在迷你缓冲区中输入的所有内容都会保存到 minibuffer histroy list迷你缓冲区历史记录列表 中,方便你后续随时复用。这其中包含补全候选内容(例如文件名、缓冲区名称、命令名称等)以及其他任何类型的迷你缓冲区输入。你可以使用以下命令,快速将历史输入或备选输入调取到迷你缓冲区中:
M-p- 跳转到迷你缓冲区历史记录的上一项,即更早输入的参数 (
previous-history-element)。 M-n- 跳转到迷你缓冲区历史记录的下一项 (
next-history-element)。 UP- ↑(上箭头)
DOWN- ↓ (下箭头) 功能类似
M-p和M-n,但会优先在当前多行历史项内向上或向下跳转一行,再切换至上或下一条历史记录 (previous-line-or-history-element和next-line-or-history-element) M-r regexp RET- 跳转到历史记录中更早且匹配该正则表达式的项 (
previous-matching-history-element) M-s 正则表达式 回车- 跳转到历史记录中更晚且匹配该正则表达式的项
(
next-matching-history-element)
在迷你缓冲区中,按下 M-p (previous-history-element) 会逐条遍历历史记录列表,每按一次就会将历史记录中更早的一项调取到迷你缓冲区,并覆盖当前内容。按下 M-n (next-history-element) 则会反向遍历历史记录,将更新的条目调取到迷你缓冲区。
若在迷你缓冲区中按下 M-n 时,历史记录中已经没有更新的条目(例如你此前从未按过 M-p ),Emacs 会尝试从 默认参数列表 中调取内容:这些是你大概率会输入的常用值。你可以将这个过程理解为遍历 “future history未来历史记录”。
文件名对应的 “future history” 包含多种实用备选内容,例如当前光标所在位置的文件名或网址。这类场景下,“future history” 的默认内容由选项 file-name-at-point-functions 所指定的函数控制。默认情况下,该选项会调用 ffap 包(参见《定位光标处的文件与网址》章节),此包会根据光标周围的文本内容自动推测默认的文件或网址。若要关闭该推测功能,可将该选项自定义为 nil ,此时文件名的 “未来历史记录” 将只包含当前缓冲区打开的文件(若有)以及默认目录。
上下箭头键的功能与 M-p 、 M-n 类似,但如果当前历史项是多行内容,它们会先在该多行内容内向上或向下跳转一行,再切换到上一条或下一条历史记录。
如果你编辑了通过 M-p 或 M-n 调取到迷你缓冲区的文本, 不会修改 该内容在历史记录列表中的原始条目。但当你提交编辑后的内容时,该内容会被添加到历史记录列表的末尾。
你可以使用 M-r (previous-matching-history-element) 搜索历史记录中更早的匹配项,使用 M-s (next-matching-history-element) 搜索更新的匹配项。这两个命令都会要求你输入一个正则表达式作为参数,并将第一个匹配的条目调取到迷你缓冲区。关于正则表达式的语法说明,参见《正则表达式语法》章节。若为命令添加数字前缀参数 n ,则会调取第 n 个匹配项。这两个命令比较特殊:即便它们是在迷你缓冲区中被调用,依然会通过迷你缓冲区读取正则表达式参数。正则表达式中的大写字母会使搜索过程区分大小写(参见《搜索过程中的宽松匹配》章节)。
你也可以使用 增量搜索 功能遍历历史记录,详情参见《迷你缓冲区搜索》章节。
Emacs 会为不同类型的参数维护 独立的历史记录列表 。例如,所有读取文件名的命令会共用一个文件名历史列表;其他独立的历史列表还包括:缓冲区名称列表、命令名称列表(供 M-x 使用)以及命令参数列表(供 query-replace 这类命令使用)。
变量 history-length 用于指定迷你缓冲区历史记录列表的 最大长度 :当列表长度超出限制时,新增条目会自动删除最旧的条目。若将该变量设为 t ,则历史记录列表无长度限制。
变量 history-delete-duplicates 用于指定是否 删除历史记录中的重复项 :若该变量值为非 nil,新增条目时会删除列表中所有与之内容相同的旧条目。该变量的默认值为 nil 。
10.6. 重复执行迷你缓冲区命令
所有使用过一次迷你缓冲区的命令,都会连同其参数值一起被记录在一个特殊的历史列表 —— 命令历史列表中,你可以借此重复执行整条命令。尤其是 M-x 的每次调用都会被记录在内,因为 M-x 本身就是通过迷你缓冲区来读取命令名称的。
C-x ESC ESC- 从命令历史列表中重新执行最近一条使用过迷你缓冲区的命令 (
repeat-complex-command) M-x list-command-history- 显示完整的命令历史列表,列出所有可通过
C-x ESC ESC重复执行的命令,按从新到旧的顺序排列。
C-x ESC ESC 用于重新执行最近一条调用过迷你缓冲区的命令。不带参数时,它会重复执行最后一条该类命令;带数字前缀参数时,则指定要重复的命令位置:参数 1 代表最后一条,2 代表倒数第二条,以此类推。
C-x ESC ESC 的工作原理是,将此前执行的命令转换为一段 Lisp 表达式 ,并在迷你缓冲区中初始化显示这段表达式文本。即便你不懂 Lisp 语言,也能轻松识别出当前显示的待重复命令。直接按下回车键( RET ),就会原封不动地重复执行该命令;你也可以先编辑这段 Lisp 表达式来修改命令,再按下 RET 回车执行。执行后的命令会被添加到命令历史列表的头部,除非它与列表中最新的条目完全相同。
在 C-x ESC ESC 唤起的迷你缓冲区中,你可以使用常规的迷你缓冲区历史记录命令(参见《迷你缓冲区历史记录》章节)来遍历历史列表。找到想要重复的历史命令后,可像平常一样编辑其表达式,再按回车键执行。
严格来说, 增量搜索 并没有使用迷你缓冲区。因此,尽管它的行为类似复杂命令,但默认不会出现在 C-x ESC ESC 对应的历史列表中。若要让增量搜索命令被纳入该历史列表,可将变量 isearch-resume-in-command-history 的值设为非 nil。详情参见《增量搜索》章节。
所有此前调用过迷你缓冲区的命令,会以 Lisp 列表的形式存储在变量 command-history 中。列表中的每个元素都是一段 Lisp 表达式,描述了一条命令及其对应的参数。Lisp 程序可通过调用函数 eval ,传入 command-history 中的元素来重新执行对应命令。
10.7. 输入密码
有时你需要在 Emacs 中输入密码。例如,当你通过 FTP 等网络协议让 Emacs 访问另一台机器上的文件时,往往需要提供密码才能获取该机器的访问权限(参见《远程文件》章节)。
输入密码的操作和使用迷你缓冲区类似。Emacs 会在回显区显示一个提示(如"Password: ");输入所需密码后,按下回车键( RET )提交即可。为防止他人窥看密码,你输入的每个字符都会以星号(“*”)代替原本的样式显示。
输入密码时,迷你缓冲区的大部分功能和命令都无法使用。此时没有历史记录和补全功能,且在提交密码前,你无法切换窗口或执行 Emacs 的其他任何操作。
输入密码的过程中,你可以按下删除键( DEL )向后删除,移除最后输入的一个字符。快捷键 C-u 会清空当前已输入的所有内容。 C-g 可退出密码提示(参见《退出与终止》章节)。 C-y 会将当前的剪切内容粘贴到密码输入框中(参见《文本的剪切与移动》章节)。按下制表键( TAB )可以切换密码的可见状态。你既可以按回车键( RET ),也可以按退出键( ESC )来提交密码。其他任何可插入字符的按键会将对应的字符输入到密码中,除此之外的所有输入都会被忽略。
模式行中还会有一个图标用于指示密码的可见状态。在该图标上单击鼠标左键( mouse-1 ),同样可以切换密码的可见性。
10.8. 确认提示(Yes or No Prompts)
Emacs 命令在执行过程中,可能会要求你回答一个 "是/否" 类问题。这类询问主要分为两种类型。
第一种是结尾标注 “(y or n)” 的是 / 否询问。你只需按下单个按键('y' 代表是,'n' 代表否),即可立即退出迷你缓冲区并提交响应。例如,当你按下 C-x C-w ( write-file 写入文件命令)保存缓冲区,并输入了一个已存在的文件名时,Emacs 会弹出如下提示:
File ‘foo.el’ exists; overwrite? (y or n)
第二种是结尾标注 “(yes or no)” 的是 / 否询问(如果你自定义了 yes-or-no-prompt 变量,则会显示该变量的值),这类询问通常用于 误操作会引发严重后果 的场景。例如,当你对一个包含未保存修改的文件访问缓冲区执行 C-x k ( kill-buffer 关闭缓冲区命令)时,Emacs 会在迷你缓冲区中弹出如下提示:
Buffer foo.el modified; kill anyway? (yes or no)
此时你需要在迷你缓冲区中完整输入 "yes" 或 "no",再按下回车键( RET )来提交响应。
对于这两种是 / 否询问,迷你缓冲区都支持前文所述的基础操作:你可以用 C-l 重定所选窗口的显示中心,用 C-v (或 PageDown )向下滚动、 M-v (或 PageUp )向上滚动该窗口,用 C-x o 切换到其他窗口,用 M-p 和 M-n 执行历史记录相关命令等。按下 C-g 可以取消当前询问,同时退出迷你缓冲区和发起询问的命令(参见《退出与终止》章节)。
11. 通过名称执行命令
每个 Emacs 命令都有一个可用于执行它的名称。为方便使用,许多命令还配有快捷键绑定。你既可以通过按下快捷键来执行这些命令,也可以通过输入命令名称来执行。大多数 Emacs 命令没有快捷键绑定,因此 通过名称执行是唯一的方式 。(有关如何设置快捷键绑定的方法,参见《自定义快捷键绑定》章节。)
按照惯例,命令名称由一个或多个单词组成,单词之间用连字符分隔;例如 auto-fill-mode (自动换行模式)或 manual-entry (手动录入)。命令名称大多使用完整的英文单词,以便于记忆。
若要通过名称执行命令,需先按下 M-x ,接着输入命令名称,最后按下回车键( RET )确认。 M-x 会借助迷你缓冲区读取命令名称,迷你缓冲区开头会显示字符串 'M-x' 作为提示,提醒你输入需要执行的命令名称。按下 RET 回车键后,迷你缓冲区会关闭并执行该命令。关于迷你缓冲区的更多信息,参见《迷你缓冲区》章节。
你可以使用补全功能来输入命令名称。例如,要调用 forward-char (向前移动字符)命令,你可以直接输入:
M-x forward-char RET
或者使用补全的方式输入:
M-x forw TAB c RET
需要注意的是, forward-char 与按下快捷键 C-f 所执行的是同一个命令。即便命令有对应的快捷键绑定,也不会影响你通过名称执行它。
当 M-x 对命令进行补全时,会忽略所有在 Emacs 早期主版本中被标记为废弃的命令;对于这类命令,你必须输入完整的名称才能执行。而在当前 Emacs 版本中被标记为废弃的命令,仍会出现在补全列表里。(废弃命令指的是已有更新、更优替代方案,且计划在未来某个 Emacs 版本中移除的命令。)
此外, M-x 的补全功能可以排除与当前缓冲区主模式(参见《主模式》章节)和次要模式(参见《次要模式》章节)不相关、且通常无法在当前模式下工作的命令。默认情况下,不会排除任何命令,但你可以自定义选项 read-extended-command-predicate ,将这些不相关的命令从补全结果中剔除。
与之相反,Emacs 也可以只显示与当前缓冲区密切相关的命令。 M-S-x (即 “Meta 键 + Shift 键 + x 键”)命令的工作方式与 M-x 类似,但它不会列出 Emacs 支持的所有(或大部分)命令,只会显示那些被标记为 “属于” 当前主模式或已启用的次要模式的命令。
若要取消 M-x 操作且不执行任何命令,无需输入命令名称,直接按下 C-g 即可。这会让你回到正常的命令操作状态。
如果要向通过 M-x 调用的命令传递数值参数,需要在按下 M-x 之前指定该数值参数。在读取命令名称的过程中,参数值会显示在迷你缓冲区的提示信息中,最终 M-x 会将该参数传递给对应的命令。例如,要向 forward-char 命令传递数值参数 42,可以输入:
C-u 42 M-x forward-char RET
当你通过 M-x 执行的命令存在对应的快捷键绑定时,Emacs 会在命令执行完毕后,在回显区提示该快捷键。例如,若你输入 M-x forward-word ,回显区会显示该命令也可通过按下 M-f 来执行。你可以通过将变量 suggest-key-bindings 的值设为 nil ,来关闭这类提示信息。该变量的值也可以设为一个数字,此时 Emacs 会将快捷键提示信息显示对应秒数后再清除。默认情况下,提示信息会显示 2 秒。
此外,当 suggest-key-bindings 的值不为 nil 时, M-x 的补全列表中会为所有带有快捷键绑定的命令,显示对应的等效快捷键。
对于没有快捷键绑定的命令,在 M-x 提示符下,你无需输入完整的命令名称即可调用。如果命令的简写形式比完整名称短很多,且变量 extended-command-suggest-shorter 的值不为 nil,Emacs 会在回显区提示该简写形式。 suggest-key-bindings 的设置同样会影响这类提示信息的显示。
在本手册中,当提及通过名称执行命令时,我们通常会省略用于确认命令名称的回车键( RET )。因此,我们可能会写成 M-x auto-fill-mode ,而非 M-x auto-fill-mode RET 。只有在需要强调的情况下(例如命令后需要跟参数时),才会特别提及回车键。
M-x 的底层实现是通过执行 execute-extended-command 命令完成的,该命令的作用是读取另一个命令的名称并调用它。
12. 帮助功能
Emacs 提供了种类丰富的帮助命令,所有命令均可通过前缀键 C-h (或等效的功能键 F1 )调用。下文将对这些帮助命令进行详细说明。你也可以按下 C-h C-h 来查看完整的帮助命令列表 (help-for-help) 。在命令列表界面,可使用 SPC (空格键)和 DEL (删除键)滚动列表,然后输入想要执行的帮助命令;若要取消操作,按下 C-g 即可。
许多帮助命令会在一个特殊的 help buffer帮助缓冲区 中展示信息。在该缓冲区中,你可以用 SPC 和 DEL 滚动内容,按下 RET (回车键)则可跳转至超链接。详情参见《帮助模式》章节。
默认情况下,帮助命令会在独立窗口中打开帮助缓冲区,但不会自动选中该窗口。这一行为由变量 help-window-select 控制:它的默认值为 nil ;若将其自定义为 t ,帮助命令会强制选中帮助窗口;若设为 other ,则仅当选中的frame中存在两个以上窗口时,才会选中帮助窗口。
与之相对, *Help* 缓冲区中的许多命令会弹出新窗口来展示执行结果。例如,点击链接查看源代码、或使用 i 命令查看手册条目时,默认都会弹出新窗口。如果将变量 help-window-keep-selected 的值改为非 nil,系统就会复用当前显示 *Help* 缓冲区的窗口,而非新建窗口。
若你想使用某个功能,但不清楚它的名称或查找路径,我们推荐三种方法:首先尝试关键词检索命令,其次检索手册索引,接着查阅常见问题(FAQ)和软件包关键词,最后再尝试列出外部软件包。
C-h a TOPICS RET- 检索名称匹配参数
TOPICS的命令。参数可以是单个关键词、多个空格分隔的关键词,或正则表达式(详情参见《正则表达式》章节)。Apropos C-h d TOPICS RET- 类似上一条命令,但检索范围是文档字符串的文本内容,而非命令与函数的名称。
C-h r i TOPIC RET- 在 Emacs 信息手册的索引中检索
TOPIC,并展示首个匹配结果。按下,逗号可查看后续匹配项。 C-h r s TOPIC RET- 类似上一条命令,但检索范围是手册的正文内容,而非索引。
C-h C-f- 通过信息阅读器(Info)打开 Emacs 常见问题(FAQ)文档。
C-h p- 根据关键词展示可用的 Emacs 软件包(详情参见《软件包关键词搜索》章节)。
M-x list-packages- 展示所有外部软件包的列表(详情参见《软件包》章节)。
此外,在其他多种场景下, C-h 或 F1 也代表 “帮助” 功能。例如,在按下前缀键后再按这两个键,即可查看该前缀键后续可搭配的按键列表。(此场景下也可使用 ? 键替代。少数前缀键不支持通过 C-h 或 ? 查看后续按键 —— 因为这些按键被定义了其他功能,但所有前缀键均支持 F1 来触发帮助。)
目录
- 帮助摘要:所有帮助命令的简明列表
- 按键相关文档:查询 Emacs 中按键的功能
- 按命令或变量名查询帮助:查询命令、变量或函数名称的相关信息
- 关键词检索帮助(Apropos):查询与指定主题相关的内容
- 帮助模式命令:帮助模式与帮助缓冲区的特殊功能
- 软件包关键词搜索:通过关键词(主题)查找 Lisp 程序库
- 国际语言支持相关帮助:与国际化语言支持相关的帮助
- 其他帮助命令:各类杂项帮助命令
- 帮助文件:用于展示辅助帮助文件的命令
- 活动文本与工具提示帮助:活动文本的帮助信息与工具提示(“气泡帮助”)
12.1. 帮助摘要
以下是用于查阅内置文档的帮助命令汇总,其中大部分命令会在后续章节展开详细说明。
C-h a topics RET- 显示名称匹配指定主题的命令列表 (
apropos-command) 。详情参见《关键词检索》章节。 C-h b- 显示当前所有生效的按键绑定;展示顺序为:次要模式绑定 → 主模式绑定 → 全局绑定(对应函数
describe-bindings)。详情参见《其他帮助命令》章节。 C-h C-q- 切换显示一个窗口,该窗口用于展示常用命令及其对应的按键绑定。详情参见《其他帮助命令》章节。
C-h c key- 显示该按键序列所绑定命令的名称 (
describe-key-briefly) 。此处的 c 代表 “字符(character)”。若需查看该按键的完整信息,可使用C-h k命令。详情参见《按键相关文档》章节。 C-h d topics RET- 显示文档字符串内容匹配指定主题的命令与变量列表 (
apropos-documentation) 。详情参见《关键词检索》章节。 C-h e- 显示
*Messages*缓冲区的内容 (view-echo-area-messages) 。详情参见《其他帮助命令》章节。 C-h f 函数名 RET- 显示名为函数名的 Lisp 函数文档 (
describe-function) 。由于 Emacs 命令本质上也是 Lisp 函数,该命令同样适用于查询命令;你也可以使用C-h x命令查询。详情参见《按命令或变量名查询帮助》章节。 C-h h- 显示
HELLO文件,该文件包含多种字符集的示例文本。 C-h i- 启动 Info——GNU 官方文档阅读器(对应函数
info)。Emacs 手册可在 Info 中查阅。详情参见《其他帮助命令》章节。 C-h k key- 显示该按键序列所绑定命令的名称与完整文档 (
describe-key) 。详情参见《按键相关文档》章节。 C-h l- 显示你最近输入的 300 次按键记录 (
view-lossage) 。详情参见《其他帮助命令》章节。 C-h m- 显示当前主模式与已启用次要模式的文档说明 (
describe-mode) 。详情参见《其他帮助命令》章节。 C-h n- 显示 Emacs 近期更新内容的公告 (
view-emacs-news) 。详情参见《帮助文件》章节。 C-h o 符号- 显示名为符号的 Lisp 符号文档 (
describe-symbol) 。该命令可查询各类符号:函数、变量、以及显示样式(face)均适用。详情参见《按命令或变量名查询帮助》章节。 C-h p- 根据主题关键词查找软件包 (
inder-by-keyword) 。详情参见《软件包关键词检索》章节。查询结果会以软件包菜单缓冲区的形式列出。详情参见《Emacs Lisp 软件包》章节。 C-h P 软件包名 RET- 显示指定软件包名对应的软件包文档 (
describe-package) 。详情参见《软件包关键词检索》章节。 C-h r- 在 Info 中打开 Emacs 手册 (
info-emacs-manual) 。 C-h s- 显示当前语法表的内容 (
describe-syntax) 。详情参见《其他帮助命令》章节。语法表定义了各类字符的属性,例如哪些字符属于左分隔符、哪些字符属于单词组成部分等。详情参见《Emacs Lisp 参考手册》中的《语法表》章节。 C-h t- 启动 Emacs 交互式教程 (
help-with-tutorial) 。 C-h v var RET- 显示名为变量名的 Lisp 变量文档 (
describe-variable) 。详情参见《按命令或变量名查询帮助》章节。 C-h w command RET- 显示触发指定命令名对应命令的按键序列 (
where-is) 。详情参见《按键相关文档》章节。 C-h x command RET- 显示指定命令名对应命令的文档 (
describe-command) 。详情参见《按命令或变量名查询帮助》章节。 C-h C coding RET- 描述指定编码名对应的编码系统 (
describe-coding-system) 。详情参见《编码系统》章节。 C-h C RET- 描述当前正在使用的编码系统。
C-h F command RET- 启动 Info 并跳转到记录指定 Emacs 命令名文档的节点 (
Info-goto-emacs-command-node) 。详情参见《按命令或变量名查询帮助》章节。 C-h I method RET- 描述指定输入法名对应的输入法 (
describe-input-method) 。详情参见《选择输入法》章节。 C-h K key- 启动 Info 并跳转到记录指定按键序列文档的节点 (
Info-goto-emacs-key-command-node) 。详情参见《按键相关文档》章节。 C-h L language-env RET- 显示指定语言环境名所使用的字符集、编码系统与输入法信息 (
describe-language-environment) 。详情参见《语言环境》章节。 C-h S 符号 RET- 根据当前编辑文件对应的编程语言,显示该符号的 Info 文档 (
info-lookup-symbol) 。详情参见《其他帮助命令》章节。 C-h .- 若光标位于特殊文本区域内,显示该区域对应的帮助信息 (
display-local-help) 。(例如*Help*缓冲区中的超链接就属于这类特殊文本区域。)详情参见《活动文本与工具提示帮助》章节。若带前缀参数执行该命令(即C-u C-h .),且光标位于按钮(button)或控件(widget)之上,该命令会弹出一个新缓冲区,展示对应按钮 / 控件的详细描述。
12.2. 按键相关文档
获取按键序列相关信息的帮助命令为 C-h c (describe-key-briefly ,简要描述按键功能) 和 C-h k (describe-key) 。
按下 C-h c 后再输入目标按键 ,会在回显区显示该按键所绑定的命令名称。例如,执行 C-h c C-f 会显示命令 'forward-char'(向前移动字符)。
C-h k key 命令的作用与 C-h c key 类似,但会提供更详细的信息:它会打开一个帮助缓冲区,其中包含该命令的文档字符串,详细说明命令的具体功能。
C-h K key 命令则会跳转到 Emacs 手册中,对应该按键所绑定命令的说明章节。
C-h c 、 C-h k 和 C-h K 适用于所有类型的按键序列,包括功能键、菜单操作和鼠标事件( C-h c 会忽略鼠标移动事件除外)。例如,按下 C-h k 后,你可以从菜单栏中选择一个菜单项,查看该菜单项所执行命令的文档字符串。
C-h w command RET 会列出该命令所绑定的所有按键,结果会显示在回显区。如果提示该命令未绑定任何按键,则意味着你必须通过 M-x 来调用这个命令。 C-h w 对应的底层命令是 where-is 。
Emacs 的部分模式会用到各类按钮(参见《Emacs Lisp 参考手册》的 “按钮” 章节)和控件(参见《Emacs Widget 控件使用入门》),点击这些元素可以执行相应操作。若要查看这些按钮最终调用的函数,你可以将光标移到按钮上方,然后执行 button-describe 和 widget-describe 命令。
M-x which-key 是一个全局次要模式,专门用于帮助用户探索 Emacs 的按键映射表。当你输入了不完整的命令前缀时,它会以弹窗形式显示对应的按键绑定关系。
12.3. 按命令或变量名查询帮助
C-h x command RET (describe-command) 会在一个窗口中显示指定命令的文档说明。例如,执行
C-h x auto-fill-mode RET
会展示自动换行模式 (auto-fill-mode) 的相关文档。对于那些未绑定到任何按键的命令(这类命令通常需要通过 M-x 调用),这是获取其文档的常用方式。
C-h f function RET (describe-function) 用于显示 Lisp 函数的文档说明,该命令主要面向 Lisp 程序中调用的函数。比如,当你编写了表达式 (make-vector len) ,想要确认 make-vector 的用法是否正确时,只需输入 C-h f make-vector RET 即可查看文档。此外,由于 Emacs 中所有命令本质上都是 Lisp 函数,因此你也可以用这个命令查看任意命令的文档。
若直接按下 C-h f RET ,该命令会解析光标所在位置周围最内层的 Lisp 表达式,并展示其调用函数的文档 —— 前提是该函数名是已定义的合法 Lisp 函数(输入参数时,这个函数名会作为默认值显示)。例如,当光标位于文本 "(make-vector (car x)" 之后时,包含光标的最内层列表是以 "(make-vector" 开头的,此时按下 C-h f RET ,就会显示 make-vector 函数的文档。
C-h f 也可用于校验函数名的拼写是否正确。如果 C-h f 在迷你缓冲区的提示符中,将光标所在位置的函数名作为默认值显示,就说明这个名称是已定义的 Lisp 函数。若你并不需要查看该函数的文档,按下 C-g 即可取消 C-h f 命令的执行。
describe-function 命令展示的函数文档,不仅包含 函数的文档字符串和签名 ,还会附带一些辅助信息,比如函数类型、定义该函数的文件路径、函数是否已被标记为废弃。文档中被加粗强调的部分,通常可以通过点击或按下回车键,跳转到更多相关内容。
如果函数的类型是已知的,会通过 函数类型说明符 来标注(参见《Emacs Lisp 参考手册》中的 “类型说明符” 章节)。只有当 Lisp 程序手动声明了函数类型,或者编译器自动推导出了函数类型时,该标注才会显示。需要注意的是,函数类型推导功能仅在启用 原生编译 时生效(参见《Emacs Lisp 参考手册》中的 “原生编译” 章节)。
若你查询的是一个 自动加载函数 ,且其自动加载定义(参见《Emacs Lisp 参考手册》中的 “自动加载” 章节)中未提供文档字符串,那么 *Help* 帮助缓冲区中将不会显示任何文档内容。这种情况下,如果变量 help-enable-symbol-autoload 的值不为 nil,Emacs 会尝试加载该函数的定义文件,以查找是否存在对应的文档字符串。
使用 M-x shortdoc 命令,你可以获取与特定主题相关的函数概览。执行该命令后,它会提示你输入感兴趣的主题(例如 string ,即字符串),然后弹出一个缓冲区,列出所有与字符串处理相关的常用函数。
你还可以设置让 C-h f 弹出的 *Help* 缓冲区中,在展示函数和命令文档的同时附带 使用示例 。要实现这个功能,需在你的初始化文件中添加以下配置(参见《Emacs 初始化文件》章节):
(add-hook 'help-fns-describe-function-functions
#'shortdoc-help-fns-examples-function)
C-h v (describe-variable) 的功能与 C-h f 类似,区别在于它用于展示 Lisp 变量的文档,而非 Lisp 函数。如果光标所在位置或前方的符号是已定义的 Lisp 变量,该变量名会作为默认值填充到输入参数中。详情参见 “变量” 章节。
只要你安装了 Emacs 的源码文件,描述变量和函数的帮助缓冲区中,通常会包含指向对应源码的超链接(参见 “超链接与网页导航功能” 章节)。
若要在手册中查找某个命令的文档说明,可以使用 C-h F (Info-goto-emacs-command-node) 。该命令支持检索多种手册,而不仅限于 Emacs 官方手册,并能自动定位到对应的章节。
C-h o (describe-symbol) 的功能涵盖了 C-h f 和 C-h v ,它可以描述任意符号—— 无论是函数、变量还是面(face)。如果某个符号拥有多重定义(例如,既被定义为函数,又被定义为变量),该命令会依次展示它的所有文档说明。
C-h 4 s (elp-find-source) 会切换到一个新的缓冲区,打开当前帮助文档中所描述对象的 源码定义文件 。
如果用户选项 completions-detailed 的值不为 nil,部分命令在展示补全候选时会附带详细信息。例如,执行 C-h o TAB 键,补全列表中会包含每个符号文档字符串的第一行内容,同时标注该符号的类型(如函数、变量等)。具体附带的详细信息会根据所使用的命令有所不同。
12.4. 关键词检索帮助(Apropos)
apropos关键词检索 类命令可以解答这类问题:“有哪些用于文件操作的命令?”更准确地说,你需要输入一个 apropos pattern检索模式串 ,这个模式串可以是单个单词、一组用空格分隔的单词,或是一个正则表达式。
下述所有关键词检索命令,都会在迷你缓冲区中读取检索模式串,搜索匹配该模式的目标对象,并在新窗口中展示检索结果。
C-h a- 搜索命令 (
apropos-command) 。若带上前缀参数执行,则同时搜索非交互式函数 M-x apropos- 搜索函数与变量,可同时匹配交互式函数(即命令)与非交互式函数
M-x apropos-user-option- 搜索用户可自定义的变量。若带上前缀参数执行,则同时搜索不可自定义的变量
M-x apropos-variable- 搜索所有变量。若带上前缀参数执行,则仅搜索可自定义变量
M-x apropos-local-variable- 仅搜索缓冲区局部变量
M-x apropos-value- 搜索值匹配指定模式的变量。若带上前缀参数执行,则同时搜索定义匹配模式的函数、以及属性匹配模式的 Lisp 符号
M-x apropos-local-value- 仅搜索值匹配指定模式的缓冲区局部变量
C-h d- 搜索文档字符串匹配指定模式的函数与变量(对应底层函数 apropos-documentation)
最简单的检索模式串是 单个单词 ,任何名称中包含该单词的对象都会被匹配。例如,要查找所有文件相关的命令,输入 C-h a file RET 即可。执行后会列出所有名称含 'file' 的命令,比如 copy-file 、 find-file 等。每条命令都会附带简短描述,以及当前可调用它的快捷键列表。以 find-file 为例,检索结果会标注它的快捷键是 C-x C-f 。
默认情况下,展示检索结果的 apropos 缓冲区不会被自动选中。若要让 Emacs 自动选中该缓冲区,可将变量 help-window-select 设为任意非 nil 值。
对于 apropos 缓冲区中列出的函数定义、变量或符号属性,若想查看其详细信息,可使用 mouse-1 鼠标左键或 mouse-2 中键点击对应条目,或移动光标到条目后按下 RET 回车键。
当检索模式串包含 多个单词 时,目标对象的名称必须至少包含其中两个单词,才算匹配成功。例如,若想查找 “删除光标前方文本块” 的命令,可输入 C-h a kill back backward behind before RET 。实际存在的命令 kill-backward 会被匹配到;如果存在 kill-text-before 这类命令,也会被匹配到,因为它的名称包含了模式串中的两个单词。
若需要更高的检索灵活性,可直接输入 正则表达式 (参见《正则表达式语法》章节)。当模式串中包含正则表达式的特殊字符 ”^$*+?.\[“ 时,Emacs 会自动将其解析为正则表达式。
遵循 Emacs 命令的命名规范,以下这些单词在检索模式串中非常实用。通过在 C-h a 中使用它们,你也能逐步熟悉 Emacs 的命名习惯:
char(字符)、line(行)、word(单词)、sentence(句子)、paragraph(段落)、region(区域)、page(页)、sexp(S 表达式)、list(列表)、defun(函数定义)、rect(矩形区域)、buffer(缓冲区)、frame(框架)、window(窗口)、face(外观)、file(文件)、dir(目录)、register(寄存器)、mode(模式)、beginning(开头)、end(结尾)、forward(向前)、backward(向后)、next(下一个)、previous(上一个)、up(向上)、down(向下)、search(搜索)、goto(跳转至)、kill(剪切)、delete(删除)、mark(标记)、insert(插入)、yank(粘贴)、fill(填充)、indent(缩进)、case(大小写)、change(修改)、set(设置)、what(查询)、list(列出)、find(查找)、view(查看)、describe(描述)、default(默认)。
若变量 apropos-do-all 的值为非 nil,则大多数关键词检索命令的执行效果,等同于带前缀参数执行的效果。但存在一个例外:不带前缀参数执行 apropos-variable 时,无论 apropos-do-all 的值是什么,都会始终搜索所有变量。
默认情况下,除 apropos-documentation 外,所有关键词检索命令都会按 字母顺序 排列结果。若将变量 apropos-sort-by-scores 设为非 nil,这些命令会尝试评估结果的相关度,将最相关的结果排在前面。而 apropos-documentation 命令默认按 相关度 排序结果;若要改为按字母顺序排序,可将变量 apropos-documentation-sort-by-scores 设为 nil。
12.5. 帮助模式命令
帮助缓冲区的主模式为帮助模式。该模式包含查看模式的所有命令(参见《查看模式》相关内容);例如,按 SPC 空格键可向下滚动,按 DEL 删除键或 S-SPC 可向上滚动。同时它还提供了若干专属的特殊命令:
RET- 跳转到光标所在位置的交叉引用 (
help-follow) TAB- 将光标向前移动至下一个超链接 (
forward-button) S-TAB- 将光标向后移动至上一个超链接 (
backward-button) mouse-1mouse-2- 跳转到点击的超链接
np- 在帮助缓冲区中向前或向后翻页
C-c C-c- 显示光标所在位置符号的全部相关文档 (
help-follow-symbol) C-c C-fr- 向前翻阅帮助命令的操作历史 (
help-go-forward) C-c C-bl- 向后翻阅帮助命令的操作历史 (
help-go-back) s- 查看当前帮助主题的源码(若有源码可查) (
help-view-source) i- 在手册中检索当前主题 (
help-goto-info) I- 在 Emacs Lisp 手册中检索当前主题 (
help-goto-lispref-info) c- 自定义光标所在的变量或显示样式 (
help-customize)
在帮助缓冲区的文档中,函数名、变量名或显示样式名(参见文《本显示样式》相关内容)通常会显示为 underlined hyperlink带下划线的超链接 。若要查看其关联文档,可将光标移至对应位置并按 RET 回车 (help-follow) ,或用 mouse-1 鼠标左键 / mouse-2 中键点击该超链接。此操作会替换帮助缓冲区的原有内容;若要回溯操作记录,可按 C-c C-b 或 l (help-go-back) 。回溯过程中,可按 C-c C-f 或 r (help-go-forward) 向前恢复操作。
在帮助缓冲区中切换超链接时,按 TAB (forward-button) 可跳至下一个超链接,按 S-TAB 可返回上一个超链接。这些命令为循环执行;例如,在最后一个超链接处按制表符,光标会跳回第一个超链接。
默认情况下,帮助缓冲区中的许多超链接会被引号包裹。若将用户选项 help-clean-buttons 设为非空值,缓冲区中的这些引号会被自动移除。
部分帮助命令生成的帮助缓冲区(例如展示大量按键绑定的 C-h b 命令)会通过 ^L 字符将内容分块为多个页面。在这类缓冲区中,按 n (help-goto-next-page) 可跳至下一页开头,按 p (help-goto-previous-page) 可返回上一页开头。通过该方式可快速在帮助缓冲区的不同文档板块间导航。
帮助缓冲区中还可包含指向 Info 手册、源码定义和网页地址的超链接。前两种链接会在 Emacs 中直接打开,网页地址则会通过 browse-url 命令调用浏览器打开(参见超链接跳转相关内容)。
若要查看文档中任意符号的全部相关信息,可将光标移至该符号处并按 C-c C-c (help-follow-symbol) 。该操作会展示该符号的所有相关文档 —— 包括其作为变量、函数和、and/or 显示样式的相关说明。
12.6. 软件包关键词搜索
Emacs 中大多数可选功能都归类为软件包。Emacs 内置了数百个软件包,还可通过网络安装更多软件包(参见《Emacs Lisp 软件包》章节)。
为方便查找与特定主题相关的软件包,多数软件包会根据其功能关联一个或多个关键词。按下 C-h p (finder-by-keyword) 可调出软件包关键词列表,同时显示各关键词的含义说明。若要查看某一关键词对应的软件包列表,在该关键词所在行按下 RET 回车键即可;相关软件包列表会在「软件包菜单」缓冲区中展示(参见《软件包菜单缓冲区》章节)。
按下 C-h P (describe-package) 后,Emacs 会提示你输入软件包名称(参见《Emacs Lisp 软件包》章节),并在帮助缓冲区中展示该软件包的属性信息及所实现的功能。该缓冲区会以按钮形式列出与该软件包关联的所有关键词,使用鼠标左键或鼠标中键点击任意按钮,即可查看该关键词对应的其他软件包列表。
12.7. 国际语言支持相关帮助
若需查看特定语言环境的相关信息(参见《语言环境》章节),按下 C-h L (describe-language-environment) 即可。该操作会调出帮助缓冲区,展示此语言环境所支持的语言,同时列出其关联的字符集、编码体系、输入方法,以及该语言环境的示例文本。
命令 C-h h (view-hello-file) 会打开 etc/HELLO 文件,该文件通过展示多种语言的 “你好” 表达,直观演示各类字符集的使用。
命令 C-h I (describe-input-method) 用于说明输入方法 —— 可指定某一输入方法进行查看,默认情况下则展示当前正在使用的输入方法(参见《输入方法》章节)。
命令 C-h C (describe-coding-system) 用于解读编码体系 —— 可指定某一编码体系进行查看,默认情况下则展示当前正在使用的编码体系(参见《编码体系》章节)。
12.8. 其他帮助命令
C-h i (info) 可启动 Info 程序,该程序用于浏览结构化的文档文件。 C-h 4 i (info-other-window) 功能与之相同,区别在于会在另一个窗口中显示 Info 缓冲区。Emacs 的完整手册及 GNU 系统的其他众多手册均可在 Info 中查阅。进入 Info 后按下 h 键,即可运行 Info 的使用教程。
若为 C-h i 指定数字参数 n ,该命令会选中名为 ”*info*<n>“ 的 Info 缓冲区,此功能便于你同时浏览多本 Info 手册。若仅将 C-u 作为前缀参数, C-h i 会提示你输入文档文件名,你可借此浏览在 Info 顶层菜单中无入口的文件。
前文提及的帮助命令 C-h F functions RET 与 C-h K key ,会直接进入 Info 并跳转到对应函数或按键的说明文档。
在编辑程序时,若该编程语言有对应的 Info 版手册,你可使用 C-h S (info-lookup-symbol) ,在对应手册中查找某个符号(关键字、函数或变量)的相关条目。该命令的具体工作方式由当前主模式决定。
若遇到意外情况,且不确定自己按下了哪些按键,可使用 C-h l (view-lossage) 。 C-h l 会显示你最近输入的按键序列及其触发的命令。Emacs 默认保存最近的 300 次按键记录,你可通过 lossage-size 命令修改该数值。若发现记录中有不熟悉的命令,可使用 C-h k 或 C-h f 查询其功能。
如需查看近期的回显消息,可使用 C-h e (view-echo-area-messages),该命令会打开保存此类消息的 *Messages* 缓冲区。
Emacs 的每种主模式通常会重新定义部分按键,并对编辑的工作方式做出其他调整。 C-h m (describe-mode) 会显示当前主模式的说明文档,文档中通常会介绍该模式下修改后的命令、功能,以及对应的按键绑定。
C-h b (describe-bindings) 与 C-h s (describe-syntax) 可展示 Emacs 当前运行环境的其他相关信息。 C-h b 会显示当前所有生效的按键绑定列表,顺序依次为:当前次要模式的局部绑定、当前主模式定义的局部绑定,最后是全局绑定(参见《自定义按键绑定》章节)。 C-h s 会显示语法表的内容,并对每个字符的语法规则做出解释(参见《Emacs Lisp 参考手册》中的《语法表》章节)。
C-h C-q (help-quick-toggle) 可切换一个辅助缓冲区的显示与隐藏,该缓冲区展示了 Emacs 最常用的命令及其对应的按键绑定(也被称作 “速查手册”),其内容由 help-quick 命令生成。缓冲区中所有按键绑定均为可点击按钮,使用 mouse-1 鼠标左键或 mouse-2 中键点击,即可查看该按键序列所绑定命令的说明文档。
在按下某个前缀键后,再输入 C-h 、 ? 或 F1 (describe-prefix-bindings) ,即可查看该前缀键对应的所有子命令列表。(少数前缀键不支持全部上述按键 —— 这类前缀键为相关按键定义了专属绑定。ESC 就是其中之一: ESC C-h 与 ESC ? 实际对应的是 C-M-h (mark-defun) 和 M-? (xref-find-references) ,但 ESC F1 可正常生效。)
最后,执行 M-x describe-keymap 命令,程序会带补全功能提示你输入键盘映射表名称,确认后将显示该键盘映射表中所有的按键绑定。
12.9. 帮助文件
除内置文档和手册外,Emacs 还包含若干其他说明文件,内容涉及复制条款、版本说明、调试方法、问题反馈指引等。你可通过以下命令查看这些文件,除快捷键 C-h g 外,其余命令均为 C-h C-字符 的形式。
C-h C-c- 显示 Emacs 的复制与再分发规则 (
describe-copying) 。 C-h C-d- 显示 Emacs 调试相关帮助 (
view-emacs-debugging) 。 C-h C-e- 显示获取外部包的相关信息 (
view-external-packages) 。 C-h C-f- 显示 Emacs 常见问题解答列表 (
view-emacs-FAQ) 。 C-h g- 打开 GNU 项目的介绍页面 (
describe-gnu-project) 。 C-h C-m- 显示 Emacs 手册印刷版的订购信息 (
view-order-manuals) 。 C-h C-n- 显示版本更新日志,列出当前 Emacs 版本的新功能 (
view-emacs-news) 。 C-h C-o- 显示 Emacs 及其他 GNU 软件最新版本的订购与下载方式 (
describe-distribution) 。 C-h C-p- 显示已知的 Emacs 问题列表,部分问题会附带建议的解决办法 (
view-emacs-problems) 。 C-h C-t- 显示 Emacs 的待办事项列表 (
view-emacs-todo) 。 C-h C-w- 显示 GNU Emacs 无任何担保的完整详细说明 (
describe-no-warranty) 。
12.10. 活动文本与工具提示帮助
在 Emacs 中, active text活动文本 (即响应鼠标点击或 RET 回车键执行特定操作的文本)通常配有对应的帮助文本。这类文本包括 Emacs 缓冲区中的超链接,以及模式行的部分内容。在图形化显示界面中,或是部分支持鼠标追踪的文本终端中,将鼠标移至活动文本上方时,相关帮助文本会以 tooltip 工具提示 的形式显示,详见「工具提示」相关说明。
在不支持鼠标追踪的终端中,可键入快捷键 C-h . (display-local-help) ,显示光标所在位置的缓冲区活动文本的帮助文本,该内容会展示在回显区。若希望光标所在位置存在可用帮助文本时,自动显示对应的帮助信息,可将变量 help-at-pt-display-when-idle 的值设为 t。
13. 标记与区域(Mark and Region)
Emacs 与诸多其他应用程序一样,允许你选中缓冲区文本中的任意部分,并调用针对该 select text选中文本 执行操作的命令。在 Emacs 中,我们将选中的文本称为 region区域 ;其处理方式与其他程序中选中文本的处理方式十分相似,但也存在一些重要区别。
区域指的是 标记 与当前 光标位置 之间的缓冲区文本部分。你可以通过在某处设置标记(例如使用 C-SPC 命令),再将光标移动至希望作为区域结束位置的地方,来定义一个区域。(你也可以使用鼠标来定义区域。)
无论标记和光标在文本中哪个位置更靠前,区域始终覆盖两者之间的范围;每次移动光标,区域都会随之改变。
在文本的某个位置设置标记后,标记会 activates被激活 。当标记处于激活状态时,我们也称区域处于激活状态;Emacs 会通过 region face区域面 为区域内的文本添加高亮,以此标示出区域的范围(参见「自定义样式」相关内容)。
执行部分非移动类命令后(包括所有会修改缓冲区文本的命令),Emacs 会自动 deactivates取消标记的激活状态 ,区域的高亮效果也会随之消失。你也可以在任何时候键入 C-g ,手动取消标记的激活状态(参见「退出与终止操作」相关内容)。
许多命令会将其操作的文本范围限定在 激活的区域 内。例如, M-% 命令(用于替换匹配的文本)默认会作用于缓冲区中所有可访问的文本部分,但如果存在激活的区域,该命令将仅对该区域内的文本生效。
即便标记未被激活,它依然具有实用价值。例如,你可以通过标记环跳转到之前设置过的标记位置(参见「标记环」相关内容)。此外,部分命令即便针对未激活的区域,也能执行相应操作(例如 upcase-region 命令,用于将区域文本转为大写)。你也可以通过 C-x C-x 这类命令,重新激活区域。
上述行为是 Emacs 交互会话中的默认行为,被称为 临时标记模式 (Transient Mark mode)。关闭临时标记模式后,Emacs 会切换至另一种行为模式,在该模式下,区域通常不会被高亮显示(参见「关闭临时标记模式」相关内容)。
在一个缓冲区中设置标记,不会对其他缓冲区中的标记产生任何影响。当你回到一个存在激活标记的缓冲区时,标记会停留在之前的位置。当多个窗口显示同一个缓冲区时,各窗口的光标位置可以不同,因此对应的区域也会不同,但所有窗口会共享同一个标记位置(参见「多窗口」相关内容)。通常情况下,只有 选中的窗口 会为其对应的区域添加高亮;但如果将变量 highlight-nonselected-windows 的值设为非 nil,每个窗口都会为自身对应的区域添加高亮。
Emacs 中还有另一种区域类型:矩形区域(参见「矩形区域」相关内容)。
13.1. 设置标记
以下是若干用于设置标记的命令:
C-SPC- 在光标位置设置标记并将其激活 (
set-mark-command) 。 C-@- 与上一命令功能相同。
C-x C-x- 在光标位置设置标记并将其激活,随后将光标移至标记原位置 (
exchange-point-and-mark,交换光标与标记位置)。 Drag-mouse-1- 鼠标左键拖动。在拖动鼠标划过的文本范围两端分别设置光标与标记。
mouse-3- 鼠标右键点击。在当前光标位置设置标记,随后将光标移至鼠标点击处 (
mouse-save-then-kill) 。 - 按住 SHIFT 的光标移动键
- 若标记未激活,则在光标位置设置标记,再移动光标(详见「移位选择」相关内容)。
设置标记最常用的方式是按下 C-SPC (set-mark-command)5。该操作会在当前光标位置设置并激活标记,之后你可移动光标,标记将停留在原位置。若标记已存在于当前光标位置,该命令不会重复设置标记,仅激活已有的标记。
例如,若你希望将缓冲区中的部分文本转换为大写,可将光标移至目标文本的一端,按下 C-SPC ,再移动光标至目标文本的另一端,此时目标文本会被高亮显示。接着按下 C-x C-u (upcase-region ,将区域文本转为大写) ,该命令会将区域内的文本转换为大写,随后自动取消标记的激活状态。
只要标记处于激活状态,你可按下 C-g 取消其激活(详见「退出与终止操作」)。大多数对区域执行操作的命令都会自动取消标记激活,如上述示例中的 C-x C-u 。
标记不仅可用于定义待操作的区域,还可用于标记缓冲区中的某个位置(连续按下 C-SPC C-SPC ),后续可通过 C-u C-SPC 跳回该位置(详见「标记环」相关内容)。
命令 C-x C-x (exchange-point-and-mark) 用于交换光标与标记的位置。当你希望保留当前光标位置,仅调整区域的另一端(标记位置)时,该命令非常实用。若需要,再次按下 C-x C-x ,可将标记移至新位置,同时将光标恢复至原始位置。默认情况下,若标记处于未激活状态,该命令会先重新激活上一次设置的标记,确保区域保持高亮;但如果为该命令添加前缀参数执行,它会保持标记未激活、区域不高亮的状态,你可通过这种方式跳至标记位置,效果与 C-u C-SPC 类似。
你也可通过鼠标设置标记:按住鼠标左键( down-mouse-1 )并拖动划过一段文本,鼠标按下处会被设为标记,松开处则为光标位置。此外,点击鼠标右键( mouse-3 )会在当前光标位置设置标记,再将光标移至点击位置。有关这些鼠标命令的详细说明,参见「编辑相关的鼠标命令」。
最后,你还可在按下Shift 键的同时,按下部分光标移动命令(如 S-RIGHT 、 S-C-f 、 S-C-n 等)设置标记,这种方式被称为“shift-selection”移位选择。该操作会在移动光标前,于当前光标位置设置标记 —— 但仅当此前未通过移位选择或鼠标命令激活标记时生效。通过鼠标命令和移位选择设置的标记,与常规标记的行为略有不同:后续任何未按住 Shift 的光标移动命令,都会自动取消其激活状态(详见「移位选择」)。
许多插入文本的命令(如 C-y (yank ,粘贴) 会在插入文本的另一端设置标记,但不会激活该标记。这一设计能让你轻松返回该位置(详见「标记环」),当回显区显示 “Mark set(标记已设置)“ 时,即表示当前执行的命令完成了该操作。
在 X 窗口系统中,每当激活的区域发生变化,Emacs 会将区域内的文本保存至主选择区(primary selection),你可通过点击鼠标中键( mouse-2 ),将该文本插入其他 X 应用程序中(详见「与其他窗口应用程序的剪切和粘贴」)。
13.2. 标记文本对象的命令
以下命令可在单词、列表、段落、页面等文本对象的两端定位光标与标记:
M-@- 将标记设到下一个单词的末尾 (
mark-word) ,执行后光标位置不变。 C-M-@- 将标记设到下一个平衡表达式的末尾之后 (
mark-sexp) ,执行后光标位置不变。 M-h- 将光标移至当前段落开头,并将标记设到段落末尾 (
mark-paragraph) 。 C-M-h- 将光标移至当前函数定义开头,并将标记设到定义末尾 (
mark-defun) 。 C-x C-p- 将光标移至当前页面开头,并将标记设到页面末尾 (
mark-page) 。 C-x h- 将光标移至缓冲区开头,并将标记设到缓冲区末尾 (
mark-whole-buffer) 。
M-@ (mark-word) 会把标记定位到下一个单词的末尾(关于单词的定义详见「单词」相关内容)。重复执行该命令,会将标记逐个单词向后移动,从而扩展选中的区域。一个例外情况是:若标记处于激活状态且位于光标前方, M-@ 会将标记从当前位置逐个单词向前移动。
该命令也可接收数字参数 n ,指示将标记向后移动 n 个单词;若传入负参数 -n ,则将标记向前移动 n 个单词。
类似地, C-M-@ (mark-sexp) 会把标记定位到下一个平衡表达式的末尾(关于括号平衡表达式详见「带配对括号的表达式」相关内容)。重复执行该命令,会将区域扩展至后续的表达式;传入正、负数字参数时,会将标记按指定数量的表达式向前或向后移动。
上述列表中的其他命令会同时调整光标与标记的位置,以此在缓冲区中划定一个文本对象的范围: M-h (mark-paragraph) 用于标记段落(详见「段落」相关内容), C-M-h (mark-defun) 用于标记顶层函数定义(详见「按函数定义移动」相关内容), C-x C-p (mark-page) 用于标记页面(详见「页面」相关内容)。重复执行这些命令,作用同样是扩展区域至相邻的同类文本对象;数字参数也可指定标记需要移动过的文本对象数量。
C-x h (mark-whole-buffer) 会将光标置于缓冲区开头、标记置于缓冲区末尾,从而将整个缓冲区设为选中区域
13.3. 对区域执行操作
定义好区域后,可通过以下方式对其执行各类操作:
C-w删除区域内容(参见「文本的删除与移动」)。M-w将区域内容复制到删除环(参见「粘贴操作」)。C-x C-l或C-x C-u转换区域内容大小写(参见「大小写转换命令」)。C-u C-/撤销区域内的修改操作(参见「撤销」)。M-%替换区域内的文本(参见「查询替换」)。C-x TAB或C-M-\对区域内容进行缩进(参见「缩进」)。M-x fill-region将区域内容按文本格式进行填充排版(参见「文本填充」)。M-$检查区域内单词的拼写(参见「拼写检查与修正」)。M-x eval-region将区域内容作为 Lisp 代码执行(参见「Emacs Lisp 表达式的执行」)。C-x r s将区域内容保存到寄存器(参见「寄存器」)。- 将区域内容保存到缓冲区或文件中(参见「文本累积」)。
部分命令在标记未激活时执行默认操作,标记激活时则对区域进行操作。例如 M-$ (ispell-word) ,默认会检查光标所在单词的拼写,标记激活时则检查区域内文本的拼写(参见「拼写检查与修正」)。通常情况下,若区域为空(即标记与光标位置重合),这类命令会执行默认操作。若希望命令对空区域也执行区域操作,可将变量 use-empty-active-region 设为 t 。
如「文本擦除」章节所述, DEL (backward-delete-char ,向前删除字符) 和 Delete (delete-forward-char ,向后删除字符) 命令也遵循此规则:标记激活时,这两个命令会删除区域内的文本。(例外情况:若为命令指定非 1 的数字参数 n ,无论标记是否激活,命令都会删除 n 个字符。)若将变量 delete-active-region 设为 nil ,这两个命令在标记激活时将不再执行特殊操作;若将该变量值设为 kill ,这两个命令会将区域内容删除并保存到删除环,而非直接擦除(参见「文本的删除与移动」)。
另有部分命令始终对区域进行操作,无默认行为,这类命令的名称中通常包含 “region”(区域),例如 C-w (kill-region ,删除区域) 和 C-x C-u (upcase-region ,区域内容转大写) 。标记未激活时,这些命令会对 非激活区域 —— 即光标与上一次设置标记的位置之间的文本 —— 进行操作(参见「标记环」)。若要禁用此行为,可将变量 mark-even-if-inactive 设为 nil ,此后标记未激活时,执行这类命令会直接抛出错误。
默认情况下,即便标记处于激活状态,文本插入操作仍正常执行 —— 例如输入 a 会插入字符 a,随后取消标记的激活状态。次要模式「删除选中内容模式(Delete Selection mode)」会修改此行为:启用该模式后,标记激活时执行文本插入,会先删除区域内的文本,再插入新内容。不过可通过自定义选项 delete-selection-temporary-region 调整该行为,该选项默认值为 nil ;若将其设为 t , 仅临时激活的区域 会被新内容替换,临时激活区域包括通过鼠标拖动(参见「设置标记」)、移位选择(参见「移位选择」)设置的区域,以及临时标记模式禁用时通过 C-u C-x C-x 激活的区域。若将 delete-selection-temporary-region 设为 selection ,则仅鼠标拖动或移位选择激活的临时区域会被替换,通过 C-u C-x C-x 激活的临时区域不会被替换。键入 M-x delete-selection-mode 可切换 delete-selection-mode删除选中内容模式 的启用与禁用状态。
13.4. 标记环(Mark Ring)
每个缓冲区都会通过 mark ring标记环 记录标记的历史位置,设置标记的命令会将旧标记压入该标记环中。标记环的用途之一,就是记录你可能需要返回的位置。
C-SPC C-SPC- 设置标记并将其压入标记环,且不激活该标记。
C-u C-SPC- 将光标移至标记的上一位置,并从历史标记环中恢复标记位置。
当你希望用标记记录一个后续可能返回的位置时,命令 C-SPC C-SPC 会非常实用。该操作会将当前光标位置压入标记环,且不会激活标记(激活标记会让 Emacs 高亮显示对应区域)。这一操作实际是连续两次执行 C-SPC (set-mark-command) :第一次按下 C-SPC 用于设置标记,第二次则用于取消标记的激活状态。(若临时标记模式处于关闭状态, C-SPC C-SPC 会临时激活该模式,详见「关闭临时标记模式」相关内容。)
若要返回标记记录的位置,可带前缀参数执行 set-mark-command 命令: C-u C-SPC 。该操作会将光标移至标记的上一位置,若标记原本处于激活状态,则会将其取消激活。后续每一次按下 C-u C-SPC ,都会跳转到标记环中存储的更早一个位置,通过这种方式遍历的位置不会从环中丢失,而是会被移至标记环的末尾。
若将变量 set-mark-command-repeat-pop 设为非 nil 值,那么在按下 C-u C-SPC 后,可直接按下 C-SPC 替代 C-u C-SPC ,实现标记环的循环遍历。该变量的默认值为 nil 。
每个缓冲区都有独立的标记环 ,所有编辑命令均使用当前缓冲区的标记环,因此 C-u C-SPC 的跳转操作始终在当前缓冲区中进行,不会跳至其他缓冲区。
变量 mark-ring-max 用于指定标记环中可保存的最大记录数,默认值为 16 条。当标记环中的记录达到该上限,且有新标记被压入时,最早存入的那条记录会被丢弃。重复按下 C-u C-SPC ,会在当前标记环中存储的所有位置间循环跳转。
若你需要反复返回同一个位置,标记环的操作方式可能不够便捷。这种情况下,你可将该位置记录到寄存器中,方便后续快速调取(详见「在寄存器中保存位置」相关内容)。
13.5. 全局标记环(Global Mark Ring)
除了每个缓冲区各自拥有的普通标记环外,Emacs 还配有一个 global mark ring 全局标记环。若在上一次设置标记后切换过缓冲区,那么每次你设置新标记时,该标记会被同时记录在当前缓冲区的标记环与全局标记环中。因此,全局标记环会记录你曾操作过的缓冲区序列,且为每个缓冲区留存一处标记设置的位置。全局标记环的最大记录数由变量 global-mark-ring-max 控制,默认值为 16 条。
需注意, 仅当通过命令新建标记时 ,该标记才会被记录到全局标记环中。若只是激活已存在的标记(例如在已有标记的位置按下 C-SPC ,详见「设置标记」章节),并不会将该标记压入全局标记环。
命令 C-x C-SPC (pop-global-mark) 会跳转到全局标记环中最新记录对应的缓冲区与位置,同时会对全局标记环进行轮循 —— 连续按下 C-x C-SPC ,会依次跳转到更早记录的缓冲区及对应标记位置。
13.6. 移位选择(Shift Selection)
在按下光标移动命令的同时按住 Shift 键,会先设置标记,再移动光标,使区域覆盖从光标原始位置到新位置的范围。该功能被称为 shift-selection 移位选择 ,其文本选中方式与其他编辑器的操作逻辑相近。
通过移位选择设置的标记,行为与前文所述的常规标记略有不同。其一,除了常规的标记取消激活方式(如修改缓冲区文本、按下 C-g )外, 任何未按住 Shift 键的光标移动命令 ,都会触发标记的取消激活;其二,后续再次按下的移位光标移动命令,不会重新设置标记。因此,连续执行一系列移位光标移动命令,可对选中区域进行连续调整。
仅当移位后的光标移动键 未绑定至其他独立命令 时,移位选择功能才会生效(参见「自定义配置」相关内容)。例如,若将 S-C-f 绑定至其他命令,按下 S-C-f 时会执行该绑定命令,而非触发 C-f (forward-char) 对应的移位选择操作。
通过鼠标命令设置的标记,与移位选择设置的标记行为 完全一致 (参见「设置标记」相关内容)。例如,通过鼠标拖动划定区域后,可继续使用移位光标移动命令扩展该区域。无论以哪种方式设置标记,只要按下未按住 Shift 键的光标移动命令,都会取消标记的激活状态。
若要关闭移位选择功能,可将变量 shift-select-mode 的值设为 nil ,此操作不会禁用通过鼠标命令设置标记的功能。若将该变量值设为 permanent ,未经过移位转换的光标移动键将不会触发标记的取消激活;例如,此前命令划定的区域可通过移位选择继续扩展,未按住 Shift 键的光标移动键也能对移位选择划定的区域进行扩展。
13.7. 禁用瞬时标记模式(Disabling Transient Mark Mode)
标记与区域的默认行为 —— 设置标记时会激活标记并高亮显示区域 —— 由 临时标记模式 (Transient Mark mode) 实现。该模式为次要模式,在交互会话中默认启用,可通过 M-x transient-mark-mode 命令切换开关,也可通过「Options选项」菜单中的「Highlight Active Region 高亮激活区域」菜单项进行操作。关闭该模式后,Emacs 会切换为另一套操作方式:
执行
C-SPC、C-x C-x等命令设置标记时, 不会高亮显示区域 。因此无法通过视觉判断标记的位置,只能手动记忆。解决这一问题的常用方法是,设置标记后尽快使用,避免忘记其位置;也可通过
C-x C-x命令查看标记位置,该命令会交换光标与标记的位置(参见「设置标记」章节)。- 部分原本在标记激活时会对区域执行操作的命令,将不再具备该行为。例如默认情况下,若标记处于激活状态,
M-%(qurey-replace) 会在区域内执行替换操作;而关闭临时标记模式后,该命令会始终从光标位置开始,执行至缓冲区末尾。这类存在行为差异的命令,会在其自身的文档说明中明确标注。
关闭临时标记模式后,可通过 C-SPC C-SPC 或 C-u C-x C-x 临时激活 该模式。
C-SPC C-SPC- 在光标位置设置标记(与普通的
C-SPC操作一致),并一次性启用临时标记模式,直至标记被取消激活为止。(这并非独立命令,而是连续执行两次C-SPC命令的效果。) C-u C-x C-x- 交换光标与标记的位置,激活标记并临时启用临时标记模式,直至标记下一次被取消激活。(这是带前缀参数执行
C-x C-x命令exchange-point-and-mark的效果。)
上述命令在设置 或者 激活标记的同时,仅会在 标记激活期间 临时启用临时标记模式。使用该操作的一个常见原因是:关闭临时标记模式后,部分命令会对整个缓冲区而非区域执行操作,而临时启用该模式,就能让这些命令重新对区域生效。
通过鼠标(参见「设置标记」章节)或移位选择(参见「移位选择」章节)划定区域时,Emacs 也会以同样的方式 临时激活临时标记模式 ,并高亮显示该区域。
14. 剪切与移动文本(Killing and Moving Text)
在 Emacs 中, killing 指擦除文本并将其复制到 kill ring 删除环中, yanking 指将删除环中的文本重新插入到缓冲区中。(部分应用程序将类似操作称为「cutting剪切」和「pasting粘贴」。)之所以称其为删除环,是因为可以将其想象成一组按环形排列的文本块,你能以循环的方式访问其中的内容,详见「删除环」相关章节。
killing删除与yanking粘贴是 Emacs 中移动或复制文本最常用的方式,该方式的灵活性极高,因为 Emacs 提供了针对多种不同语法单元的删除命令。
14.1. 删除与剪切
大多数从缓冲区中清除文本的命令,会将清除的文本保存至删除环中(参见「删除环」)。这类命令被称为 kill commands删除命令 ,其名称中通常包含 “kill” 一词(例如 kill-line )。删除环会存储近期多次执行删除操作的文本,而非仅保留最后一次的内容,因此删除操作的安全性很高:你无需过度担心丢失之前删除的文本。 删除环为 所有缓冲区共享 ,因此在一个缓冲区中删除的文本,可粘贴至另一个缓冲区中。
当你使用 C-/ (undo 撤销) 来撤销某一删除命令时(参见「撤销」),被删除的文本会恢复至缓冲区,但不会从删除环中移除。
在图形化显示界面中,执行删除操作的同时,还会将文本复制到系统剪贴板,详见「图形化界面中的『剪切 - 粘贴』操作』。
仅清除文本但 不将其保存至删除环 的命令,被称为 delete commands 擦除命令 ,其名称中通常包含 “delete” 一词。这类命令包括 C-d (delete-char ,向前擦除字符) 和 DEL (delete-backward-char ,向后擦除字符) —— 二者均一次仅擦除一个字符,以及所有仅用于擦除空格或换行符的命令。通常,若某一命令会清除大量有效文本,其执行的是删除(kill)操作而非擦除操作。
你也可通过鼠标执行删除与粘贴操作,详见「图形化界面中的『剪切 - 粘贴』操作」。
14.1.1. 删除操作
delete 擦除指清除文本且 不将其保存至删除环 的操作。Emacs 中的擦除命令,大多仅用于清除单个字符或空白字符。
DELBACKSPACE- 删除前一个字符;若区域处于激活状态,则删除区域内的文本 (
delete-backward-char) 。 Delete- 删除后一个字符;若区域处于激活状态,则删除区域内的文本 (
delete-forward-char) 。 C-d- 删除后一个字符 (
delete-char) 。 M-\- 删除光标位置前后的空格与制表符 (
delete-horizontal-space) 。 M-x just-one-space- 删除光标位置前后的空格与制表符,仅保留一个空格。
M-SPC- 以灵活的方式删除光标位置前后的空格与制表符 (
cycle-spacing) 。 C-x C-o- 删除当前行前后的空行 (
delete-blank-lines) 。 M-^- 删除两行之间的换行符及换行符后的所有缩进,将两行合并为一行 (
delete-indentation) 。
前文已介绍过 "basic deletion commands基础擦除命令" DEL (delete-backward-char) 、 Delete (delete-forward-char) 与 C-d (delete-char) ,详见「文本擦除」章节。为这些命令指定数字参数时,会按参数值删除对应数量的字符;若省略参数或参数为 1,当区域处于激活状态时, DEL 与 Delete 命令会删除区域内的所有文本,详见「对区域进行操作」章节。
其余擦除命令均仅用于清除空白字符(空格、制表符、换行符)。
M-\ (delete-horizontal-space) 会删除光标位置前后所有的空格与制表符;若为该命令添加前缀参数,则仅删除光标位置之前的空格与制表符。
M-x just-one-space 会删除光标位置前后的制表符与空格,且无论原位置有多少个空格(即便无空格),均在光标前保留一个空格。为该命令指定正数字参数 n 时,会在光标前保留 n 个空格;若参数为负数字 -n ,则除了删除空格与制表符外,还会删除换行符,并在光标前保留 -n 个空格。
cycle-spacing (M-SPC) 可看作是功能更灵活的 just-one-space 命令。若连续重复执行该命令,它会按照 cycle-spacing-actions 变量定义的规则,循环执行不同的空白字符清理操作。默认规则为:第一次执行等同于 just-one-space 命令,第二次执行等同于 delete-horizontal-space 命令(删除光标前后所有空白字符),第三次执行恢复光标位置原本的空白字符布局,后续按此规则循环。若为该命令添加前缀参数,所有循环操作都会沿用该参数值。用户可通过自定义 cycle-spacing-actions 变量添加更多清理规则,具体可参考该变量的文档说明。
C-x C-o (delete-blank-lines) 会删除当前行之后的所有空行;若当前行本身为空行,则同时删除当前行之前的所有空行(仅保留当前行这一个空行);若缓冲区中仅有这一个空行,则直接删除该行。
M-^ (delete-indentation) 会删除换行符及其周围的所有空格,将当前行与上一行合并为一行,通常仅在合并处保留一个空格,详见「M-^ 命令说明」。
delete-duplicate-lines 命令会在区域内查找重复的行,并删除每行的多余副本,仅保留一份。默认保留每组重复行中的第一行;若为该命令添加前缀参数 C-u ,则保留每组重复行中的最后一行;若添加前缀参数 C-u C-u ,则仅查找相邻的重复行(该模式执行效率更高,适用于已排序的文本);若添加前缀参数 C-u C-u C-u ,则会保留重复的空行不做删除。
14.1.2. 按行剪切
C-k- 剪切行尾剩余内容,或剪切一行或多行内容 (
kill-line) 。 C-S-backspace- 一次性剪切整行内容 (
kill-whole-line) 。
最简单的剪切命令是 C-k (kill-line) 。若在行尾使用该命令,它会剪切行尾的换行符,将下一行合并至当前行(因此空行会被彻底删除)。若不在行尾, C-k 会剪切从光标位置到行尾的所有文本;若光标原本就在行首,执行后该行会变为空行。
判断适用上述哪种情况时,会忽略行尾的空格和制表符。只要光标位于行中最后一个非空白字符之后,即可确定 C-k 会剪切换行符。若要剪切一整行非空内容,需将光标移至行首,连续按两次 C-k 。
此处的「line行」指 逻辑文本行 ,而非屏幕显示行(详见「折行」相关说明)。
当给 C-k 传入正数值参数 n 时,它会剪切 n 行内容及其后续的换行符(光标之前的当前行文本不会被剪切)。若传入负数值参数 -n ,它会剪切当前行之前的 n 行内容,以及光标之前的当前行文本。若给 C-k 传入参数 0,则仅剪切光标之前的当前行文本。
若变量 kill-whole-line 的值为非空(non-nil),在行首执行 C-k 会剪切包含后续换行符在内的整行内容。该变量的默认值为空(nil)。
C-S-backspace (kill-whole-line) 会剪切包含换行符在内的整行内容,与光标在该行中的位置无关。注意,许多文本终端会限制输入 C-S-backspace 这个按键组合。
14.1.3. 其他剪切命令
C-w- 剪切区域内的文本 (
kill-region) 。 M-w- 将区域内的文本复制到剪切环 (
kill-ring-save) 。 M-d- 剪切下一个单词 (
kill-word) ,详见「单词」相关说明。 M-DEL- 向前剪切一个单词 (
backward-kill-word) 。 C-x DEL- 向前剪切至句子开头 (
backward-kill-sentence) ,详见「句子」相关说明。 M-k- 剪切至句子末尾 (
kill-sentence) 。 C-M-k- 剪切后续的匹配表达式 (
kill-sexp) ,详见「括号匹配表达式」相关说明。 M-z char- 剪切至指定字符的下一次出现位置(含该字符) (
zap-to-char) 。 M-x zap-up-to-char char- 剪切至指定字符的下一次出现位置(不含该字符)。
最常用的剪切命令之一是 C-w (kill-region) ,该命令会剪切区域内的所有文本(详见「标记与区域」相关说明)。与之对应, M-w (kill-ring-save) 会将区域内的文本复制到剪切环,而不会从缓冲区中删除该文本。若按下 C-w 或 M-w 时标记处于未激活状态,命令会作用于光标位置与上一次设置标记的位置之间的文本(详见「区域操作」相关说明)。
Emacs 还提供了剪切特定语法单元的命令:可通过 M-DEL 和 M-d 剪切单词(详见「单词」);通过 C-M-k 剪切括号匹配表达式(详见「括号匹配表达式」);通过 C-x DEL 和 M-k 剪切句子(详见「句子」)。
M-z (zap-to-char) 命令将剪切与搜索结合:输入一个字符后,命令会从光标位置开始,剪切至该字符在缓冲区中下一次出现的位置(包含该字符本身)。传入数字参数表示重复执行次数;传入负数值参数则表示 向前搜索 并剪切光标之前的内容。该命令会保留此前输入过的字符历史,可通过 M-p / M-n 按键调取,此功能在需要通过复杂输入法输入目标字符时尤为实用。与之类似的 zap-up-to-char 命令,同样剪切至指定字符的下一次出现位置,但 不包含该字符本身 ,数字参数的作用同样为重复执行次数。
14.1.4. 剪切相关选项
部分专用缓冲区包含 read-only text 只读文本,这类文本无法修改,因此也无法被剪切。 kill commands 剪切命令在只读缓冲区中会以特殊方式工作:光标会遍历目标文本并将其复制到剪切环,却不会从缓冲区中实际删除该文本。默认情况下,执行此操作时编辑器还会发出提示音并显示错误信息。但如果将变量 kill-read-only-ok 设为非空值,编辑器仅会在回显区打印一条提示信息,说明文本未被删除的原因。
在将剪切内容存入剪切环(kill ring)之前,你可以通过 kill-transform-function 函数对目标字符串进行转换。该函数会接收待剪切的字符串作为参数,返回值为你希望存入剪切环的字符串;若返回 nil ,则该字符串不会被存入剪切环。例如,若你希望永远不将纯空白字符串存入杀环,可使用以下配置:
(setq kill-transform-function (lambda (string) (and (not (string-blank-p string)) string)))
若将变量 kill-do-not-save-duplicates 设为非空值,连续执行的多次相同剪切操作,最终仅会在剪切环中生成一条条目,不会产生重复内容。
若启用次要模式 kill-ring-deindent-mode ,存入剪切环的文本会自动减少缩进量,减少的幅度与被保存文本第一行的缩进量一致。也就是说,若被保存文本的第一行有n列的缩进,该模式会从每一行的缩进中均移除n列的空白。
14.2. 粘贴(Yanking)
Yanking 粘贴指重新插入此前被剪切的文本。移动或复制文本的常规方式为:先将文本剪切,再在其他位置将其粘贴。
C-y- 将最近一次剪切的内容粘贴到缓冲区的光标位置 (
yank) 。 M-y- 将刚粘贴的文本替换为更早一次剪切的文本块 (
yank-pop) ,或支持从过往所有剪切的文本块列表中选择粘贴内容,详见「粘贴更早的剪切内容」。 C-M-w- 让后续执行的命令(若为剪切命令)将内容追加至前一次的剪切结果中(追加下一次剪切命令),详见「追加剪切内容」。
基础的粘贴命令为 C-y (yank) ,该命令会插入最近一次剪切的内容,光标停留在插入文本的末尾;同时会在插入文本的开头位置设置标记(标记处于未激活状态),若需要跳转到该位置,可使用 C-u C-SPC 快捷键实现(详见「标记环」)。
若使用纯前缀参数执行该命令 C-u C-y ,光标会停留在插入文本的前方,并将标记设置在插入文本的末尾。使用其他任意前缀参数时,可指定粘贴更早一次的剪切内容:例如 C-u 4 C-y ,会重新插入倒数第四次剪切的内容,详见「粘贴更早的剪切内容」。
在图形化界面及支持该功能的文本模式界面中, C-y 会首先检查:其他应用程序是否在 Emacs 最后一次剪切操作之后,向系统剪贴板写入了新的文本。若检测到新内容,C-y会优先插入系统剪贴板中的文本。因此,Emacs 会将其他应用中执行的剪贴板「cut剪切」或「copy复制」操作,视作 Emacs 自身的剪切操作来处理;区别在于,这些外部操作的内容 不会被记录在 Emacs 的kill ring剪切环中 。相关细节详见「图形化界面中的 “剪切与粘贴” 操作」。
14.2.1. 剪切环(Kill Ring)
kill ring 剪切环是此前被剪切的文本块构成的列表。Emacs 中 仅有一个剪切环 ,由所有缓冲区共享,因此你可在一个缓冲区中剪切文本,再在另一个缓冲区中粘贴,这也是将文本从一个缓冲区移至另一缓冲区的常规方式。(此外还有多种实现方法:例如可将文本存入寄存器,详见「寄存器」章节;也可参考「文本累加」章节,了解其他文本移动方式。)
剪切环中的最大条目数由变量 kill-ring-max 控制,其默认值为 120。当剪切环达到该数量上限后,若执行新的剪切操作,Emacs 会删除剪切环中最旧的条目,为新内容腾出空间。
剪切环的实际内容存储在名为 kill-ring 的变量中,你可通过快捷键 C-h v kill-ring 查看剪切环的全部内容。
14.2.2. 粘贴之前的剪切内容
正如「粘贴」章节所述,你可以为快捷键 C-y 添加数字参数,来粘贴并非最近一次的删除文本。如果你能记清想要调用删除环中的哪一项内容,这个方法会非常实用。若记不清,可使用 M-y (yank-pop) 命令遍历所有删除记录,或从中选中某条更早的删除内容。
如果上一个执行的命令是粘贴类命令, M-y 会将当前已粘贴的文本,替换为删除环中更早一条的删除内容。因此,若要恢复倒数第二次的删除文本,需先执行 C-y 粘贴最后一次的删除内容,再执行 M-y 将其替换为前一次的删除内容。该操作 仅在执行C-y或其他M-y命令后有效 (若在其他命令后调用 M-y ,执行逻辑会有所不同,详见下文)。
你可以通过 最后粘贴指针 来理解 M-y 的这一运行模式:该指针始终指向删除环中的某一条目。每次执行删除操作时,最后粘贴指针会移动到删除环头部新生成的条目处。 C-y 会粘贴该指针指向的条目;在 C-y 或其他 M-y 之后执行 M-y ,会将最后粘贴指针移动到上一条目,同时缓冲区中的文本会同步替换为该条目内容。连续执行多次 M-y ,可将指针移动到删除环中的任意条目,从而将任意删除内容调入缓冲区。当指针到达删除环末尾时,再次执行 M-y 会循环回到第一条目。
M-y 仅会移动删除环中的最后粘贴指针, 不会改变删除环中条目的顺序 —— 删除环始终保持「头部为最近一次删除内容,尾部为仍保留的最早一次删除内容」的顺序。
在 C-y 或 M-y 之后执行 M-y 时,也可为其添加数字参数,该参数用于指定最后粘贴指针需要向前移动的条目数。负数字参数会让指针向删除环头部移动;若指针已在头部,会循环到尾部并继续向前移动。
当你找到目标文本并将其调入缓冲区后,即可停止执行 M-y ,此时最后粘贴的文本会保留在缓冲区中。该文本仅是删除环条目的一份副本,因此在缓冲区中编辑它, 不会改变删除环中原有的内容 。只要未执行新的删除操作,最后粘贴指针会始终停留在删除环的当前位置,重复执行 C-y 会粘贴同一条历史删除内容的另一份副本。
为 C-y 添加数字参数执行时,最后粘贴指针也会同步指向此次粘贴的条目。
你也可在非粘贴类命令后调用 M-y ,此时 M-y 会在迷你缓冲区中弹出提示,让你选择某条历史删除内容。你可使用 迷你缓冲区历史命令 (参见「迷你缓冲区历史」)遍历或搜索删除环中的条目,直至找到想要重新插入的内容;也可使用补全命令(参见「补全命令」),对删除环条目列表进行补全匹配,或弹出 *Completions* (补全)缓冲区,从候选条目中选择目标内容。选中删除环条目后,你还可在迷你缓冲区中对其进行编辑。最后按下 RET (回车)退出迷你缓冲区,选中的删除环条目文本就会插入到缓冲区中。与在粘贴命令后执行 M-y 的情况相同,最后粘贴指针会指向此次刚粘贴的文本(无论该文本是某条原始历史删除内容,还是你编辑后再插入的删除环条目 —— 若为后者,编辑后的条目会被添加到删除环的头部)。因此,这种情况下执行 C-y ,也会粘贴刚插入的文本的另一份副本。
在非粘贴类命令后,使用纯前缀参数 (C-u M-y) 调用 M-y 时,该命令会将光标定位在插入文本的前方,并在文本末尾设置标记,与 C-y 的默认行为一致。
14.2.3. 追加剪切内容(Appending Kills)
默认情况下,每一个删除命令都会向删除环中新增一条独立条目。但 连续执行的两个或多个删除命令 ,会将其删除的文本合并为删除环中的单一条目,如此一来,单次执行 C-y 即可将所有文本作为一个整体粘贴回来,与删除前的原貌一致。
因此,若你希望将一段文本作为整体粘贴,无需用单个命令一次性删除全部内容;你可以逐行、逐个单词地连续执行删除操作,直至删完目标文本,后续仍能一次性将其全部恢复。
从光标处向前删除的命令,会将删除的文本追加到上一次删除内容的末尾;从光标处向后删除的命令,会将删除的文本添加到上一次删除内容的开头。通过这种方式,无论你混合执行多少次向前、向后的删除命令,所有被删除的文本都会按原有顺序合并为删除环中的单一条目,不会发生内容错乱。为删除命令添加数字参数,并不会打断这种删除内容的追加序列。例如,假设缓冲区中有如下文本:
This is a line ∗of sample text.
其中 ∗ 为光标位置。若你依次执行 M-d (删除后一个单词)、 M-DEL (删除前一个单词)、 M-d 、 M-DEL ,交替进行向前、向后删除,最终删除环中会新增单一条目a line of sample,而缓冲区中剩余文本为 "This is text." (注意is与text之间的两个空格,可使用 M-SPC 或 M-q 整理)。
删除上述相同文本的另一种方式:先执行 M-b M-b 将光标向前移动两个单词,再执行 C-u M-d 向前一次性删除四个单词。这种操作在缓冲区和删除环中产生的结果,与前一种交替删除的方式完全一致。即便执行 M-f M-f 将光标后移两个单词,再执行 C-u M-DEL 向后一次性删除四个单词,最终结果也毫无差别 —— 删除环中该条目内的文本,始终与删除前其在缓冲区中的原有顺序保持一致。
若某一删除命令与上一次删除命令之间,插入了 其他非删除命令 (仅添加数字参数除外),则该命令会在删除环中新建一条独立条目。但你可通过提前执行 C-M-w (append-next-kill 追加下一次删除) ,强制让该删除命令与上一次的删除内容合并。 C-M-w 的作用是:告知其后紧跟的命令(若为删除命令),将此次删除的内容视作上一次删除序列的一部分。与常规的追加规则一致,若该删除命令为向前删除,则将文本追加到上一次删除内容的末尾;若为向后删除,则将文本添加到上一次删除内容的开头。通过这种方式,你可以删除缓冲区中多处不连续的文本,并将其全部累积为一个整体,后续在某一位置一次性粘贴回来。
执行 M-w (kill-ring-save 保存到删除环,即复制) 后,紧跟的删除命令不会将删除的文本,追加到 M-w 复制到删除环中的内容之后。
14.3. 图形界面中的 “复制 - 粘贴” 操作
在大多数图形化桌面环境中,你可通过名为 clipboard剪贴板 的系统功能,在不同应用程序间传输数据(通常为文本)。在 X 窗口系统中,还有另外两种类似的功能可用: 主选择区 和 次选择区 。当 Emacs 在图形化显示界面中运行时,其删除和粘贴命令会与这些系统功能集成,因此你能轻松在 Emacs 与其他图形化应用之间传输文本。
默认情况下,Emacs 将 UTF-8 用作程序间文本传输的编码系统。若你发现粘贴的文本与预期不符,可通过键入 C-x RET x 或 C-x RET X 指定其他编码系统;也可通过自定义 x-select-request-type 变量,请求使用不同的数据类型。详见《进程间通信的编码系统》章节。
14.3.1. 使用剪贴板
clipboard 剪贴板是绝大多数图形化应用程序用于 剪切粘贴 的系统功能。当系统存在剪贴板时,Emacs 的删除和粘贴命令会直接调用该功能。
当你通过 C-w (king-region) 这类命令删除文本,或通过 M-w (kill-ring-save) 这类命令将文本复制至删除环时, 该文本也会同时存入系统剪贴板 。
Emacs 的删除命令向剪贴板写入文本时,剪贴板中原有的内容默认会被覆盖。你可手动配置 Emacs,将剪贴板原有内容保存至删除环,避免旧数据丢失:若将变量 save-interprogram-paste-before-kill 设为数字值,当剪贴板原有内容的字符数小于该数字时,会自动将其复制到删除环;若将该变量设为非 nil 的其他值,则无论内容大小,都会始终将剪贴板原有内容复制到删除环 —— 但此设置可能因剪贴板内容过大,导致 Emacs 内存占用过高。
C-y (yank) 这类粘贴命令同样会调用剪贴板。若 剪贴板的归属权属于其他应用程序 (即你在其他应用中执行剪切 / 复制操作的时间,晚于在 Emacs 中执行最后一次删除命令的时间),Emacs 会优先从 系统剪贴板 粘贴内容,而非从自身的 kill rang删除环中读取。
默认情况下,使用 M-y (yank-pop) 遍历 Emacs 删除环的操作, 不会修改系统剪贴板的内容 ;若将变量 yank-pop-change-selection 设为t,则执行 M-y 时,会将当前遍历到的粘贴内容同步保存至系统剪贴板。
若要禁止 Emacs 的 kill 删除 、粘贴命令访问系统剪贴板,将变量 select-enable-clipboard 设为 nil 即可。
程序可向剪贴板存入纯文本以外的内容,例如网页浏览器中对图片执行「复制图片」操作后,图片数据会被存入剪贴板。在支持该功能的平台上,你可通过 Emacs 的 yank-media 命令粘贴这类对象 —— 仅在支持该特性的编辑模式下可用 (详见《Emacs Lisp 参考手册》中的「粘贴媒体内容」章节)。
许多 X 窗口桌面环境支持 clipboard manager剪贴板管理器功能 :若 Emacs 是当前剪贴板数据的归属程序,且系统中正在运行剪贴板管理器,那么退出 Emacs 时,Emacs 会将剪贴板数据传输至剪贴板管理器,避免数据丢失。部分场景下,该传输过程可能导致 Emacs 退出卡顿;若要禁止此行为,将变量 x-select-enable-clipboard-manager 设为 nil 即可。
由于包含 空字节(NUL) 的字符串在通过剪贴板传输时,通常会被截断,因此 Emacs 会在将这类字符串传输至系统剪贴板前,自动将空字节替换为转义字符“\0”。
在Emacs 24 版本之前,其删除和粘贴命令默认调用的是主选择区(详见「与其他窗口应用的剪切粘贴」小节),而非系统剪贴板。若你希望恢复旧版行为,需同时完成以下配置:将 select-enable-clipboard 设为 nil 、 select-enable-primary 设为 t 、 mouse-drag-copy-region 设为 t 。配置后,你可通过以下命令显式操作系统剪贴板:
clipboard-kill-region:删除指定区域文本,并将其保存至剪贴板;clipboard-kill-ring-save:将指定区域文本复制至 Emacs 删除环,同时保存至剪贴板;clipboard-yank:在光标位置粘贴系统剪贴板中的内容。
14.3.2. 与其他窗口应用程序的复制 - 粘贴
在 X 窗口系统、PGTK 图形工具包及 Haiku 系统中,存在 primary selection主选择区 功能,其中会保存 X 应用中最后一次选中的文本(通常通过鼠标拖动选中)。通常情况下,在其他 X 应用中单击 mouse-2 鼠标中键,即可将该文本插入对应位置。主选择区与剪贴板相互独立,其内容的留存性更低 —— 每次用鼠标选中新文本时,主选择区的内容就会被覆盖,而剪贴板的内容仅会被显式的剪切或复制命令覆盖。
在 X 窗口系统中,只要 Emacs 的 区域处于激活 状态(参见《标记与区域》),区域内的文本就会自动保存到主选择区。无论该区域是通过鼠标拖动、点击创建(参见《编辑相关的鼠标命令》),还是通过键盘命令创建(例如按下 C-SPC 设置标记后移动光标),此规则均适用。
若将变量 select-active-regions 设为 only ,Emacs 仅会将 临时激活的区域 (即通过鼠标或移位选择创建的区域,参见《移位选择》)保存至主选择区;若将该变量设为 nil ,Emacs 则完全不会将激活区域的内容保存到主选择区。
要将主选择区的内容插入 Emacs 缓冲区,在目标位置单击 mouse-2 (mouse-yank-primary) 即可(参见《编辑相关的鼠标命令》)。若已启用 select-enable-primary 变量(参见《使用剪贴板》),也可使用 Emacs 常规的粘贴命令 C-y 来插入该文本。
默认情况下,即便在其他程序中选中了文本,Emacs 的区域仍会保持激活状态,这与 X 窗口系统的常规行为不符。若希望当其他程序向主选择区存入数据后,Emacs 自动取消区域激活,启用全局次要模式 lost-selection-mode 即可。
MS-Windows微软视窗系统本身不提供主选择区功能,但 Emacs 会通过内部 存储选中的文本 ,在单个 Emacs 会话中模拟该功能。因此,所有与主选择区相关的功能和命令,在视窗系统中对 同一 Emacs 会话内 的剪切粘贴操作均有效,与在 X 窗口系统中的表现一致;但跨 Emacs 会话,或与其他应用程序之间的剪切粘贴,该模拟功能则无法生效。
14.3.3. 次要选择(Secondary Selection)
除主选择区外,X 窗口系统还提供了另一项功能相似的机制,即 secondary selection次选择区 。如今鲜有 X 应用程序会用到次选择区,但你可以通过以下 Emacs 命令对其进行操作:
M-Drag-mouse-1拖动鼠标左键设置次选择区,选区的一端为按下鼠标键的位置,另一端为松开鼠标键的位置(对应命令
mouse-set-secondary)。拖动过程中,选中的文本会以次选择区面版的样式高亮显示。若将鼠标拖至窗口顶部或底部外侧,窗口会自动滚动,该行为与mouse-set-region命令一致(参见《编辑相关的鼠标命令》)。该命令不会修改Emacs 的 kill ring删除环。
M-mouse-1单击鼠标左键- 设置次选择区的一个端点 (
mouse-start-secondary) ;可配合M-mouse-2单击鼠标右键设定另一个端点,完成选区的创建。执行该命令新建次选择区时,会取消当前已存在的任意次选择区。 M-mouse-3单击鼠标右键- 设置次选择区 (
mouse-secondary-save-then-kill) ,选区的一端为单击该按键的位置,另一端为之前通过M-mouse-1单击鼠标左键指定的位置。该操作会同时将选中的文本存入 Emacs 的删除环。若在同一位置再次执行M-mouse-3单击鼠标右键,则会删除刚通过次选择区选中的文本。 M-mouse-2单击鼠标中键- 将次选择区的内容插入到单击位置,且光标会定位在粘贴文本的末尾 (
mouse-yank-secondary) 。
对 M-mouse-1 单击鼠标左键执行双击或三击操作时,会按单词、按行进行选区匹配,行为与普通的鼠标左键双击 / 三击基本一致。
若变量 mouse-yank-at-point 设为非 nil 值,则 M-mouse-2 单击鼠标中键会在当前光标位置粘贴内容,此时鼠标单击的具体位置、甚至单击的是框架中的哪个窗口,均不影响粘贴结果(参见《编辑相关的鼠标命令》)。该用户选项同样会作用于交互式搜索:若其值为非 nil,在框架内任意位置通过鼠标执行的粘贴操作,都会将对应文本添加至搜索字符串中。
14.4. 文本累积(Accumulating Text)
通常我们通过 killing删除 + yanking粘贴 的方式复制或移动文本,但如需将某段文本复制到多个位置,或把多处分散的文本复制到同一位置,还有其他更便捷的方法。本节将介绍把分散的文本片段累积到缓冲区或文件中的相关命令。
M-x append-to-buffer- 将选中的区域文本追加至指定缓冲区的内容中。
M-x prepend-to-buffer- 将选中的区域文本前置插入至指定缓冲区的内容中。
M-x copy-to-buffer- 将选中的区域文本复制到指定缓冲区,清空该缓冲区原有的所有内容。
M-x insert-buffer- 将指定缓冲区的全部内容,插入到当前缓冲区的光标位置。
M-x append-to-file- 将选中的区域文本追加至指定文件的末尾。
若要将文本累积到缓冲区中,可使用 M-x append-to-buffer 。执行该命令时,会先提示你输入缓冲区名称,随后将选中区域的文本副本插入至该指定缓冲区;若指定的缓冲区不存在,该命令会自动创建。文本的插入位置为 目标缓冲区的当前光标处 :若该缓冲区此前被用于编辑,复制的文本会从光标当前位置开始,插入到缓冲区原有文本的中间位置。
执行后,目标缓冲区的光标会停留在复制文本的末尾,因此连续执行 M-x append-to-buffer 时,文本会按照 复制的先后顺序 累积到指定缓冲区中。严格来说,该命令并非始终将文本追加到缓冲区原有内容的末尾 —— 仅当目标缓冲区的光标处于末尾位置时,才会实现「追加」效果。但如果仅使用该命令修改某一缓冲区,光标会始终保持在缓冲区末尾,也就始终实现追加。
M-x prepend-to-buffer 的功能与 M-x append-to-buffer 基本一致,唯一区别是:执行后目标缓冲区的光标会停留在复制文本的前方,因此连续执行该命令时,文本会按与复制顺序相反的方式添加。 M-x copy-to-buffer 与之类似,但会先 清空目标缓冲区的所有原有内容 ,最终该缓冲区中仅保留本次新复制的文本。
使用 C-x x i (insert-buffer) 命令,可从其他缓冲区中调取累积的文本。执行该命令时会提示输入缓冲区名称,随后将该缓冲区的全部文本副本插入到 当前缓冲区的光标位置 ,且光标会停留在插入文本的开头;同时会将插入文本的末尾位置添加到 mark ring标记环 中,且不会激活标记。关于缓冲区的基础信息,可参见《使用多个缓冲区》章节。
除了将文本累积到缓冲区,也可使用 M-x append-to-file 直接将文本追加到文件中。执行该命令时会提示输入文件名,随后将选中区域的文本添加到指定文件的末尾,且修改会 立即同步到磁盘上的文件 。
注意: append-to-file 该命令仅适用于 未在 Emacs 中打开 的文件。若对 Emacs 中正在编辑的文件执行此命令,会在 Emacs 后台修改文件内容,可能导致部分编辑操作的内容丢失。
另一种文本移动的方法是将文本存储到寄存器中,相关操作可参见《寄存器》章节。
14.5. 矩形操作(Rectangles)
Rectangle 矩形操作命令作用于文本的 矩形区域 :即某几行范围内、指定两列之间的所有字符。Emacs 提供了多种矩形操作命令,可实现矩形区域的删除、粘贴、清空、填充空白或指定文本,或直接删除矩形区域等功能。矩形命令适用于多列格式的文本编辑,也可将普通文本转换为多列格式,或反向转换。
要为命令指定操作的矩形区域,需在矩形的 一个对角 设置标记,将光标置于 对角的另一端 ,这样定义的矩形区域被称为 region-rectangle区域矩形 。若光标与标记处于同一列,该区域矩形为空;若处于同一行,该区域矩形的高度为一行。
区域矩形的控制方式与普通区域基本一致,但需注意:同一组光标与标记的位置组合,会根据调用命令的不同,被解析为 普通区域 或 矩形区域 。
也可通过鼠标标记矩形区域: C-M-mouse-1 按住并拖动鼠标左键,从矩形的一个对角拖至另一个对角即可。
矩形操作核心快捷键
C-x r k- 删除区域矩形内的文本,并将其内容保存为 the last killed rectangle最近一次删除的矩形 (
kill-rectangle) 。 C-x r M-w- 将区域矩形内的文本保存为最近一次删除的矩形,不删除原文本 (
copy-rectangle-as-kill) 。 C-x r d- 直接删除区域矩形内的文本 (
delete-rectangle) 。 C-x r y- 粘贴最近一次删除的矩形,其左上角对齐当前光标位置 (
yank-rectangle) 。 C-x r o- 插入空格填充到当前区域矩形,将原矩形内的内容向右推移 (
open-rectangle) 。 C-x r N- 在区域矩形的左侧边缘插入行号,将原矩形内的内容向右推移 (
rectangle-number-lines) 。 C-x r c- 将区域矩形内的所有内容替换为空格,实现清空效果 (
clear-rectangle) 。 M-x delete-whitespace-rectangle- 删除指定矩形区域内每行的空白字符,从矩形左边缘对应的列开始执行。
C-x r t 字符串 RET- 将矩形区域内的每行内容替换为指定字符串 (
string-rectangle) 。 M-x string-insert-rectangle RET 字符串 RET- 在矩形区域的每行插入指定字符串。
C-x SPC- 切换矩形标记模式 (
rectangle-mark-mode) 。该模式激活时,区域矩形会高亮显示,可调整其大小,且标准的删除、粘贴命令会直接作用于该矩形区域。
矩形操作的分类与核心逻辑
矩形操作主要分为两类: erase擦除 / insert插入矩形的命令 ,以及 make blank rectangles创建空白矩形的命令 。
一、擦除矩形区域的两种方式
C-x r d(delete-rectangle) :直接删除矩形内的文本,不保存;C-x r k(kill-rectangle) :删除文本并将其保存为last killed rectanle最近一次删除的矩形。
两种方式的擦除效果一致:均会删除矩形内每行的指定文本,若该行擦除位置后还有其他文本,后续文本会向左移动填补空白。
注意:删除矩形并非普通意义上的「删除」—— 矩形内容不会存入 删除环 ,而是保存在一个专门的区域,且该区域仅记录 最近一次删除的矩形 。这是因为矩形粘贴与普通线性文本的粘贴逻辑差异极大,需使用专用的粘贴命令,且矩形操作不支持 粘贴循环 功能。
C-x r M-w (copy-rectangle-as-kill) 是矩形操作的「复制」命令,等同于普通文本的 M-w :仅将矩形内容记录为最近一次删除的矩形,不会从缓冲区中删除原文本。
二、矩形粘贴
执行 C-x r y (yank-rectangle) 可粘贴最近一次删除的矩形:矩形的第一行插入在光标位置,第二行插入在光标正下方同一列的位置,后续行依次向下排列,受影响的行数由保存的矩形高度决定。
示例:将两个单列列表合并为双列列表,可将其中一个单列列表作为矩形删除,再将其粘贴至另一个列表的右侧。
此外,还可通过 C-x r r r 寄存器和 C-x r i r 寄存器,将矩形内容存入寄存器或从寄存器中调取,详见《将矩形保存至寄存器》章节。
三、创建空白矩形
有两个命令可创建空白矩形:
C-x r c(clear-rectangle) :将现有区域矩形内的文本替换为空格,保留矩形区域的占位;C-x r o(open-rectangle) :直接插入一个空白的矩形区域,原区域内容向右推移。
四、其他常用矩形命令
delete-whitespace-rectangle:删除矩形区域内每行的水平空白字符,以矩形 左边缘的列 为起始位置,矩形的右边缘对该命令无影响;C-x r N(rectangle-number-lines) :在区域矩形的左侧边缘插入行号,默认从数字 1 开始(对应矩形的第一行)。若添加前缀参数,命令会提示输入起始行号,以及行号的格式化字符串(详见《Emacs Lisp 参考手册》中的《格式化字符串》章节);C-x r t(string-rectangle) :将矩形区域内的每行内容替换为指定字符串,字符串的宽度无需与矩形宽度一致:若字符串更短,矩形右侧的文本会向左移动;若字符串更长,矩形右侧的文本会向右移动;string-insert-rectangle:与string-rectangle类似,但不会替换原内容,仅在矩形区域的每行插入指定字符串,原文本向右推移。
矩形标记模式(Rectangle Mark Mode)
C-x SPC (rectangle-mark-mode) 用于切换区域的高亮类型(必要时会先激活普通区域):模式启用时,高亮显示 区域矩形 ,调整区域大小的命令(如 C-f 、 C-n 等)会 按矩形方式 调整,且删除、粘贴命令会直接作用于该矩形区域(详见《删除与移动文本》章节)。该模式仅在 区域处于激活状态 时有效。
区域矩形仅在 标记激活 时生效。尤其当 临时标记模式 关闭时(详见《关闭临时标记模式》),除了按下 C-x SPC ,还需手动激活标记。
与普通区域不同,区域矩形的对角可延伸至 缓冲区末尾之外 ,也可定位在光标通常无法进入的空白区域内(例如 TAB 制表符的中间位置)。
当区域处于激活状态且开启矩形标记模式时,执行 C-x C-x 会调用 rectangle-exchange-point-and-mark 命令,该命令会在区域矩形的 四个对角之间循环切换 光标与标记的位置。若要在对标记文本执行操作前调整区域矩形的尺寸,该命令会非常实用。
14.6. CUA 键绑定(CUA Bindings)
执行命令 M-x cua-mode 可配置一套与 通用用户访问(CUA) 系统兼容的键位绑定,该系统被广泛应用于其他各类应用程序中。
启用 CUA 模式后,按键 C-x 、 C-c 、 C-v 和 C-z 将分别执行剪切(kill删除)、复制、粘贴(yank)和撤销命令。 仅当区域处于激活状态时 , C-x 和 C-c 才会执行剪切、复制操作;若区域未激活,这两个按键仍会作为 prefix keys前缀键 生效,因此 C-x C-c 这类标准 Emacs 命令依然可以正常使用。需注意,这意味着变量 mark-even-if-inactive 对 C-x 和 C-c 不产生任何作用(参见《对区域执行操作》章节)。
若标记处于激活状态,想要输入 C-x C-f 这类 Emacs 标准命令,可采用以下两种方法:一是按住 Shift 键同时按下前缀键,例如 S-C-x C-f ;二是快速连续按下两次前缀键,例如 C-x C-x C-f 。
若希望保留下文所述 CUA 模式的其他功能,仅禁用其对 Emacs 标准键位绑定的覆盖,可将变量 cua-enable-cua-keys 设为 nil 。
CUA 模式默认会激活 删除选区模式 (参见《编辑相关的鼠标命令》章节),此时输入的文本会替换激活的区域。若想使用 CUA 模式但关闭该行为,将变量 cua-delete-selection 设为 nil 即可。
CUA 模式对矩形操作提供了增强支持,包括 矩形区域高亮显示 功能:按下 C-RET 即可开始标记矩形,通过移动命令扩展矩形范围,再使用 C-x 或 C-c 对其执行剪切或复制操作。按下 RET 可将光标移动至矩形的下一个(顺时针方向)角点,方便向任意方向扩展矩形。在该模式下,输入的普通文本会插入到矩形每一行的左侧或右侧(与光标所处的一侧保持一致)。
即便不激活 CUA 模式,也可通过调用 cua-rectangle-mark-mode 命令,使用这套矩形操作增强功能。此外还有标准的 rectangle-mark-mode 命令可供使用,详见《矩形操作》章节。
在 CUA 模式下,可为剪切、复制、粘贴命令添加 单个数字的前缀参数 ,轻松将文本和矩形存入或调取自寄存器。例如, C-1 C-c 会将区域内容复制到寄存器 1 中, C-2 C-v 会粘贴寄存器 2 中的内容。
CUA 模式还提供 全局标记 功能,便于在不同缓冲区之间移动和复制文本:按下 C-S-SPC 可切换全局标记的开启与关闭状态。当全局标记开启时,所有被剪切或复制的文本会自动插入到全局标记位置,输入的文本也会插入至全局标记处,而非当前光标位置。
示例:若要将多个缓冲区中的单词复制到某一缓冲区的单词列表中,可先在目标缓冲区中设置全局标记,然后导航至每个需要添加的单词处,标记该单词(例如使用 S-M-f ),通过 C-c 或 M-w 将其复制到列表中,最后按下 RET 在目标列表的该单词后插入换行符即可。
15. 寄存器(Registers)
Emacs registers寄存器 是可用于保存文本、矩形、位置及其他内容的独立存储区域,方便后续调用。文本或矩形一旦存入寄存器,可单次或多次复制到缓冲区中;位置一旦存入寄存器,也可单次或多次跳转到该位置。
每个寄存器均有一个 a single character单字符名称 ,下文统一用 r 表示;该字符可以是字母(如“a”)或数字(如“1”), 大小写敏感 ,因此寄存器“a”与寄存器“A”并非同一个。也可使用非字母数字字符命名寄存器,例如通过 C-q C-d 的方式将 “C-d” 设为寄存器名。
一个寄存器可存储的内容类型包括:位置、文本片段、矩形、数字、窗口或框架配置、缓冲区名或文件名,但 同一时间仅能存储一种内容 。存入寄存器的内容会一直保留,直至向该寄存器存入其他内容。若要查看寄存器 r 中存储的内容,可使用 M-x view-register 命令:
M-x view-register RET r- 显示寄存器
r中存储内容的描述信息。
所有需要指定寄存器的命令,默认情况下会经过短暂延迟后,弹出一个 preview window预览窗口 ,列出当前已存在的寄存器(若有)及其对应值。寄存器的提示相关行为(包括预览功能)可通过自定义变量 register-use-preview 实现,该变量可设置为以下值:
traditional- 默认值,Emacs 表现与 29 版本之前的所有版本一致:经过指定延迟后显示已有寄存器的预览,直接输入寄存器名即可覆盖该寄存器的原有值。预览的延迟时长由可自定义变量
register-preview-delay指定(单位为秒);将该变量设为nil则禁用预览功能(但在 Emacs 提示输入寄存器时,仍可通过按下C-h或F1显式调出预览窗口)。 t启用更灵活的寄存器预览功能。Emacs 提示输入寄存器时会 立即弹出预览窗口 (
register-preview-delay不再生效),且预览窗口支持导航:可通过C-n、C-p(或上下方向键)在预览窗口的寄存器间切换。在此模式下,若要覆盖已有寄存器的值,需通过导航选中该寄存器或直接输入其名称后,按下RET确认。此外,预览窗口显示的寄存器会根据调出预览的命令进行过滤:例如
insert-register命令调出的预览,仅显示可插入缓冲区的寄存器内容,隐藏存储窗口配置、位置及其他不可插入内容的寄存器。insist- 行为与
t一致,额外支持直接 再次按下寄存器名对应的按键 退出迷你缓冲区,无需按RET确认。 nil- 行为接近
traditional,但预览窗口会 无延迟弹出 ,且寄存器列表会根据命令进行过滤。 never- 行为与
nil一致,且 直接禁用预览功能 。
Bookmarks书签 用于记录文件及其对应的位置,方便再次打开该文件时快速跳转到对应位置。书签的设计思路与寄存器相似,因此也在本章介绍。
15.1. 在寄存器中保存位置
C-x r SPC r- 将光标位置与当前缓冲区记录至寄存器
r中 (point-to-register) 。 C-x r j r- 跳转到寄存器
r中保存的缓冲区及对应光标位置 (jump-to-register) 。
按下 C-x r SPC (point-to-register) ,随后输入字符 r ,即可将当前的 光标位置 和 所属缓冲区 一同保存至寄存器 r 。该寄存器会一直保留此信息,直至向其中存入其他内容。
执行 C-x r j r 命令,会切换至寄存器 r 中记录的缓冲区,设置标记点,并将光标移动到该寄存器保存的位置(若光标已处于记录的位置,或连续调用该命令时,不会重复设置标记点)。寄存器内的内容不会因该操作发生改变,因此你可以无限次跳转到这个保存的位置。
若使用 C-x r j 跳转到已保存的位置,但该位置所属的缓冲区已被关闭,Emacs 会尝试通过重新打开原文件来重建该缓冲区。当然,此功能仅对原本关联了文件的缓冲区生效。
15.2. 在寄存器中保存文本
若你需要多次插入同一段文本的副本,从删除环中粘贴会十分不便 —— 因为后续每一次的删除操作,都会让该文本条目在删除环中不断后移。此时可将文本存入寄存器,后续再从寄存器中调取使用,这是更优的替代方案。
C-x r s r- 将选中的区域文本复制到寄存器
r中 (copy-to-register) 。 C-x r i r- 从寄存器
r中插入文本至缓冲区 (insert-register) 。 M-x append-to-register RET r将选中的区域文本追加到寄存器
r中已存储的文本末尾。当寄存器
r中存储的是文本时,你可使用C-x r +(increment-register) 向该寄存器追加内容。请注意,若寄存器r中存储的是数字,C-x r +命令的执行行为会有所不同,详见《在寄存器中存储数字》章节。M-x prepend-to-register RET r- 将选中的区域文本添加到寄存器
r中已存储的文本开头。
执行 C-x r s r 会将区域内的文本副本存入名为 r 的寄存器。若标记处于未激活状态,Emacs 会先将标记重新激活在其上次被设置的位置,该命令执行完毕后标记会被取消激活,相关说明详见《标记与区域》章节。带前缀参数执行该命令( C-u C-x r s r )时,会将文本复制到寄存器 r 的同时,从缓冲区中删除该区域的文本;你可将此操作理解为将区域文本移动到寄存器中。
执行 M-x append-to-register RET r ,会将区域文本的副本追加至名为 r 的寄存器中已存储的文本末尾。若带前缀参数执行该命令,文本追加完成后,缓冲区中的对应区域会被删除。 prepend-to-register 命令的功能与之类似,区别仅在于该命令会将区域文本添加到寄存器内文本的开头,而非末尾。
当你使用 append-to-register 和 prepend-to-register 命令收集文本时,可能需要用分隔符将各段收集的文本区分开。这种情况下,你可 配置一个寄存器分隔符 register-separator ,并将分隔符文本存入该寄存器。例如,若要在文本收集过程中使用两个换行符作为分隔符,可进行如下设置:
(setq register-separator ?+) (set-register register-separator "\n\n")
执行 C-x r i r 会将寄存器 r 中的文本插入到缓冲区中。默认情况下,光标会停留在插入文本的末尾,标记会被设置在插入文本的开头,且标记不会被激活。若带前缀参数执行该命令,光标会被置于插入文本的开头,标记则会设置在文本末尾。
15.3. 在寄存器中保存矩形
15.4. 在寄存器中保存窗口与框架配置
你可将选中框架的窗口配置保存至寄存器,甚至能将所有框架中所有窗口的配置一并保存,后续再恢复该配置。关于窗口配置的相关信息,详见《窗口操作便捷功能》章节。
C-x r w r- 将选中框架的窗口状态保存至寄存器
r(window-configuration-to-register) 。 C-x r f r- 将所有框架的状态(包括其下所有窗口,亦称为 框架集 )保存至寄存器
r(frameset-to-register) 。
可使用 C-x r j r 恢复窗口或框架配置,该命令与恢复光标位置的命令为同一个。恢复框架配置时,所有未包含在该配置中的现有框架会变为不可见状态;若你希望直接删除这些框架,可执行 C-u C-x r j r 。
15.5. 在寄存器中存储数字
Emacs 提供了专门命令,可将数字存入寄存器、将寄存器中的数字以十进制形式插入缓冲区,还能对寄存器内的数字执行自增操作。这些命令在编写键盘宏时会十分实用(详见《键盘宏》章节)。
C-u number C-x r n r- 将指定数字存入寄存器
r(number-to-register) 。 C-u number C-x r + r- 若寄存器
r中存储的是数字,将该寄存器内的数字与指定数字相加(即完成自增指定数值的操作)。请注意,若寄存器r中存储的是文本,C-x r +(increment-register) 的执行行为会有所不同,详见《将文本保存到寄存器》章节。 C-x r i r- 将寄存器
r中的数字插入至缓冲区中。
C-x r i 是通用命令,既可插入寄存器中的数字,也可插入寄存器内存储的其他任意类型内容。执行 C-x r + 时若未指定数字参数,会将寄存器内的数值自增 1;执行 C-x r n 时若未指定数字参数,会将0存入目标寄存器。
15.6. 在寄存器中存储文件与缓冲区名称
若你需要频繁打开某些文件,可将其文件名存入寄存器,后续访问会更为便捷。将文件名存入寄存器 r 的 Lisp 代码如下:
(set-register r '(file . name))
例如,执行代码:
(set-register ?z '(file . "/gd/gnu/emacs/19.0/src/ChangeLog"))
即可将示例中的文件名存入寄存器 "z"。
要打开寄存器 r 中存储的文件名对应的文件,键入 C-x r j r 即可(该命令与跳转到保存的光标位置、恢复框架配置的命令为同一个)。
同理,若你需要频繁切换至某些缓冲区,也可将其缓冲区名存入寄存器。例如,若你经常打开 *Messages* 缓冲区,可执行以下代码将该缓冲区名存入寄存器 m :
(set-register ?m '(buffer . "*Messages*"))
要切换至寄存器 r 中存储的缓冲区名对应的缓冲区,键入 C-x r j r 即可。
15.7. 键盘宏寄存器(Keyboard Macro Registers)
15.8. 书签(Bookmarks)
Bookmarks 书签的作用与寄存器有相似之处,均可记录供跳转的位置;但与寄存器不同的是,书签支持长命名,且会自动永久保存,跨 Emacs 会话生效。书签的典型用法,是记录你在不同文件中阅读到的位置。
C-x r m RET- 为当前打开的文件,在光标位置创建书签(使用文件名作为默认书签名称)。
C-x r m 书签名称 RET- 在光标位置创建指定名称的书签 (
bookmark-set) 。 C-x r M 书签名称 RET- 功能与
C-x r m一致,但不会覆盖已存在的同名书签。 C-x r b 书签名称 RET- 跳转到指定名称的书签位置 (
bookmark-jump) 。 C-x r l- 列出所有已创建的书签 (
list-bookmarks) 。 M-x bookmark-save- 将当前所有书签的配置保存至默认书签文件。
要记录当前打开文件中的光标位置,可执行 C-x r m 命令,该命令会以当前文件名作为默认书签名称创建书签。若为每个书签按其指向的文件命名,后续即可通过 C-x r b (bookmark-jump) 便捷地重新打开对应文件,同时直接跳转到书签记录的位置。
在图形化显示界面中,执行 C-x r m 创建书签时,除记录位置外,还会在书签对应行的左侧页边距(参见《窗口页边距》章节)显示一个特殊图标,标识该位置存在书签。该功能可通过用户选项 bookmark-fringe-mark 控制:将其设为 nil 即可关闭页边距书签标识,默认值为 bookmark-mark (即用于标识书签的位图图标)。后续通过 C-x r b 跳转到该书签时,页边距的书签标识会重新显示。
C-x r M (bookmark-set-no-overwrite) 命令的功能与 C-x r m 基本一致,区别在于:若指定的书签名称已存在,该命令会抛出错误提示,而非直接覆盖原有书签。
键入 C-x r l (list-bookmarks) 可在独立缓冲区中列出所有书签;切换至该书签缓冲区后,你可对书签定义进行编辑,或为书签添加注释。在书签缓冲区中键入 C-h m ,可查看其专属编辑命令的更多说明。
当你关闭 Emacs 时,若书签配置有过修改,Emacs 会自动保存书签;你也可在任意时刻执行 M-x bookmark-save 命令手动保存。书签默认保存至文件 ~/.emacs.d/bookmarks (为兼容旧版 Emacs,若存在文件 ~/.emacs.bmk ,则会优先使用该文件)。书签相关命令会自动加载默认书签文件,正是通过这种 自动保存与加载 的机制,实现书签的跨 Emacs 会话永久保存。
若将变量 bookmark-save-flag 设为1,则每次执行书签创建命令后,Emacs 都会自动保存书签配置;即便 Emacs 意外崩溃,也不会丢失书签数据。该变量若设为数字值,代表每完成指定次数的书签修改后,自动执行一次保存操作;若将其设为 nil ,则 Emacs 仅会在你显式执行 M-x bookmark-save 时,才保存书签配置。
变量 bookmark-default-file 用于指定书签的默认保存文件。
若将变量 bookmark-use-annotations 设为 t ,创建书签时会弹出提示,让你为书签添加注释;当书签存在注释时,后续跳转到该书签位置,注释会自动在独立窗口中显示。
书签记录位置时,会同时保存位置周边的上下文内容,因此即便文件内容有轻微修改, bookmark-jump 仍能准确定位到书签位置。变量 bookmark-search-size 用于指定书签位置两侧需要记录的上下文字符数(注意:对于打开的加密文件,无论该变量如何设置,书签文件中都不会保存任何上下文内容)。
以下是书签的一些附加操作命令:
M-x bookmark-load RET 文件名 RET- 加载指定文件中的书签配置列表。除默认书签文件外,你可通过该命令与
bookmark-write命令,管理其他书签配置文件。 M-x bookmark-write RET 文件名 RET- 将当前所有书签配置保存至指定文件。
M-x bookmark-delete RET 书签名称 RET- 删除指定名称的书签。
M-x bookmark-insert-location RET 书签名称 RET- 在缓冲区中插入指定书签指向的文件名。
M-x bookmark-insert RET 书签名称 RET- 在缓冲区中插入指定书签指向文件的全部内容。
16. 显示控制
由于大缓冲区的内容无法在窗口中完整显示,Emacs 只能展示其中一部分内容。本章将介绍用于指定文本显示区域、设置文本显示方式的相关命令与变量。
- 滚动操作
- 居中显示(Recentering)
- 自动滚动
- 水平滚动
- 窄化显示(Narrowing)
- 查看模式(View Mode)
- 跟随模式(Follow Mode)
- 文本样式(Text Faces)
- 外观颜色设置
- 标准样式(Standard Faces)
- 图标(Icons)
- 文本缩放(Text Scale)
- 字体锁定模式(Font Lock mode)
- 交互式高亮(Interactive Highlighting)
- 窗口边缘(Window Fringes)
- 边界显示(Displaying Boundaries)
- 无用空白字符(Useless Whitespace)
- 选择性显示(Selective Display)
- 模式行可选功能
- 文本显示方式
- 光标显示(Displaying the Cursor)
- 行截断(Line Truncation)
- 视觉行模式(Visual Line Mode)
- 显示定制(Customization of Display)
16.1. 滚动操作
若窗口尺寸不足以显示缓冲区中的全部文本,只会展示其中一部分。 Scrolling commands 滚动命令可更改窗口中显示的缓冲区内容范围。
向前滚动 或 向上滚动 会推进窗口中显示的缓冲区内容;换言之,是让缓冲区文本相对窗口向上移动。向后滚动 或 向下滚动 会显示缓冲区中更靠前的内容,同时让文本相对窗口向下移动。
在 Emacs 中,“scrolling up向上滚动”或“scrolling down向下滚动” 指代 文本在窗口中的移动方向 ,而非窗口相对文本的移动方向。该术语在 “向上滚动”“向下滚动” 的现代含义普及前便已被 Emacs 采用,因此会出现一个看似反常的结果:按 PageDown 键,在 Emacs 的定义中属于 向上滚动 。
窗口中显示的缓冲区内容始终包含 光标位置 。若将光标移至窗口可视区域的下方或上方,Emacs 会自动执行滚动,让光标回到可视区域内(参见「自动滚动」)。你也可以通过以下命令手动执行滚动:
基础滚动命令
C-v/PageDown/next- 向前滚动近一整屏 (
scroll-up-command) M-v/PageUp/prior- 向后滚动 (
scroll-down-command)
C-v (scroll-up-command) 会向前滚动近整个窗口高度的内容,效果为将窗口底部的两行文本移至顶部,后续拼接此前未显示的内容。若光标原本在滚出窗口顶部的文本区域,滚动后光标会停在窗口新的首行。 PageDown (或 next )键与 C-v 功能完全等效。
M-v (scroll-down-command) 的向后滚动逻辑与之类似, PageUp (或 prior )键与 M-v 功能完全等效。
这些滚动命令执行后保留的 重叠行数 由变量 next-screen-context-lines 控制,其默认值为 2 。你可以为这些命令添加数字前缀参数 n ,实现滚动 n 行的效果;此时 Emacs 会尽量保持光标位置不变,让文本与光标同步上下移动。带负参数的 C-v 等效于 M-v ,反之亦然。
默认情况下,若窗口已到达缓冲区开头或末尾、无法继续滚动,这些命令会触发错误(通过蜂鸣或屏幕闪烁提示)。若将变量 scroll-error-top-bottom 设为 t ,命令会将光标移至当前可滚动的最远位置;若光标已处于该位置,才会触发错误。
保持光标屏幕位置
部分用户希望滚动命令能让光标停在 屏幕固定位置 ,这样滚动回同一屏时,光标可便捷地回到原位置。可通过变量 scroll-preserve-screen-position 启用该功能:
- 若值为
t:当滚动命令将光标移出窗口时,Emacs 会调整光标位置,让光标在屏幕上的位置保持不变(而非移至窗口首行 / 末行); - 若值为其他非nil值:即便滚动命令未将光标移出窗口,Emacs 也会按上述规则调整光标位置。
该变量对本节介绍的所有滚动命令、鼠标滚轮滚动均生效(参见「编辑用鼠标命令」);通常,所有带有非nil属性 scroll-command 的命令都会受其影响(参见《Emacs Lisp 参考手册》中的「属性列表」)。当 isearch-allow-scroll 为非nil时,该属性还会让 Emacs 在调用此类滚动命令时,不退出增量搜索模式(参见「不退出增量搜索」)。
优化高速滚动性能
当长按 C-v 、 M-v 等键触发 键盘自动重复 时,Emacs 有时无法跟上快速的滚动请求,会出现显示不更新、长时间无法响应输入的情况。可将变量 fast-but-imprecise-scrolling 设为非nil值,缓解该卡顿问题:该设置会让滚动命令跳过对滚过区域未做字体高亮的文本的着色(参见「字体锁定模式」),直接默认使用默认字体样式。
注意:若当前使用的字体并非统一尺寸,即便单次滚动(非自动重复),该设置也可能导致 Emacs 滚动到缓冲区的轻微错误位置。
作为 fast-but-imprecise-scrolling 的替代方案,你也可以启用 即时锁定延迟字体 高亮(参见「字体锁定模式」):将变量 jit-lock-defer-time 自定义为一个较小的正数(如 0.25,若打字速度快,可设为 0.1)。该设置能让长按 C-v 时的滚动更流畅,但滚动到缓冲区新区域时,窗口内容会短暂处于未着色状态。
第三种优化方案是设置变量 redisplay-skip-fontification-on-input :若值为非nil,当有未处理的输入时,Emacs 会跳过部分字体高亮操作。通常,若有未处理的输入,Emacs 本就会完全跳过重绘,因此该设置基本不影响显示,却能通过避免不必要的着色让滚动更顺滑。
其他滚动命令
M-x scroll-up/M-x scroll-down:与scroll-up-command/scroll-down-command功能类似,但 不遵循scroll-error-top-bottom变量的设置。Emacs 24 版本前,这两个命令是默认的上下滚动命令。M-x scroll-up-line/M-x scroll-down-line:让当前窗口逐行上下滚动。
若你打算常用上述命令,可为其绑定快捷键(参见「在初始化文件中重新绑定按键」)。
图形化界面滚动
在图形化显示界面中,你也可以通过 滚动条 实现窗口滚动(参见「滚动条」)。
16.2. 居中显示(Recentering)
C-l- 滚动选中的窗口,使当前行成为文本的正中间行;连续重复执行该命令时,会按循环顺序依次将当前行设为顶行、底行,依此类推。该命令也可能会重新刷新屏幕 (
recenter-top-bottom) 。 C-M-S-l- 滚动另一个窗口;效果等同于对另一个窗口执行
C-l命令。 M-x recenter- 滚动选中的窗口,使当前行成为文本的正中间行,也可能会重新刷新屏幕。
C-M-l- 通过启发式滚动,将有效信息显示在屏幕中 (
reposition-window) 。
C-l (recenter-top-bottom) 命令用于为选中的窗口重定中心,通过滚动让当前屏幕行恰好处于窗口正中间,或尽可能接近正中间的位置。
连续两次按下 C-l (C-l C-l),会滚动窗口使光标位于屏幕最顶行;第三次按下 C-l ,会让光标位于屏幕最底行。每一次连续按下的 C-l ,都会在这三个位置间循环切换。
你可以通过自定义列表变量 recenter-positions 来修改循环顺序。该列表的每个元素可以是符号 top(顶部)、middle(中间)、bottom(底部),也可以是数字:整数表示将当前行移动到指定的屏幕行号,0.0 到 1.0 之间的浮点数则表示将当前行定位在窗口顶部起的指定百分比位置。默认的列表值为 (middle top bottom) ,即上述的循环顺序。此外,若将变量 scroll-margin 设为非零值 n , C-l 命令会始终让光标与窗口顶部、底部保持至少 n 行的屏幕间距(参见「自动滚动」章节)。
你也可以为 C-l 命令添加前缀参数:单纯的前缀参数 C-u C-l 仅将光标所在行重定到窗口中心;正数值参数 n 会将光标所在行移至窗口顶部向下数第 n 行的位置;参数 0 会将光标所在行移至窗口顶行;负数值参数 −n 会将光标所在行移至窗口底部向上数第 n 行的位置。当指定了参数时, C-l 命令不会清空屏幕,也不会在不同屏幕位置间循环。
若变量 recenter-redisplay 设为非 nil 值,每次执行 C-l 命令都会清空并重新刷新屏幕;其特殊值 tty (默认值)表示仅在文本终端窗口中执行该刷新操作。当屏幕因任何原因出现显示错乱时,重新刷新屏幕会非常有用(参见「屏幕显示错乱」章节)。
更基础的命令 M-x recenter 与 recenter-top-bottom 功能类似,但不会在不同屏幕位置间循环。
C-M-l (reposition-window) 会通过启发式方式滚动当前窗口,旨在将有效信息展示在屏幕中。例如,在 Lisp 文件中,该命令会尽可能将当前整个函数定义(defun)完整显示在屏幕内。
16.3. 自动滚动
当光标移出文本的可视区域时,Emacs 会执行 automatic scrolling 自动滚动。默认情况下,自动滚动会将光标垂直居中在窗口中,不过有多种方式可以修改这一行为。
若将变量 scroll-conservatively 设为较小的数值 n ,当光标仅小幅移出屏幕(不超过n行)时,Emacs 会仅滚动必要的距离,将光标拉回屏幕可视范围;若此操作仍无法让光标显示,Emacs 会滚动至恰好让光标在窗口中居中的位置。若将 scroll-conservatively 设为较大的数值(大于 100),无论光标移出多远,自动滚动都不会让光标居中;Emacs 始终仅滚动必要距离让光标进入可视范围,光标最终会出现在窗口顶部或底部,具体取决于滚动方向。 scroll-conservatively 的默认值为 0 ,即始终让光标在窗口中居中。需要注意的是,在迷你缓冲区窗口中,默认的滚动行为始终为保守模式,因为变量 scroll-minibuffer-conservatively 的默认值为非空,且该变量的优先级高于 scroll-conservatively 。
控制自动滚动的另一种方式是自定义变量 scroll-step ,其值决定了光标移出屏幕时,自动滚动的行数。若滚动该行数后仍无法让光标回到可视范围,则会将光标居中显示。 scroll-step 的默认值为 0,这一设置(在默认情况下)会让滚动后光标始终保持居中。
第三种控制自动滚动的方式是自定义变量 scroll-up-aggressively 和 scroll-down-aggressively ,这两个变量可直接指定滚动后光标的垂直位置。 scroll-up-aggressively 的值可以是 nil (默认值),也可以是 0 到 1 之间的浮点数 f 。若设为浮点数,当光标超出窗口下边缘(即向前滚动)时,Emacs 会滚动窗口,使光标到窗口下边缘的距离为窗口高度的 f 倍。因此, f 值越大,滚动的激进程度越高,会有更多新文本进入可视范围。默认值 nil 等效于 0.5。
同理,当光标超出窗口上边缘(即向后滚动)时,会使用变量 scroll-down-aggressively 。其值指定了滚动后光标与窗口上边缘的距离比例,与 scroll-up-aggressively 一致,值越大,滚动的激进程度越高。
请注意,变量 scroll-conservatively 、 scroll-step 以及 scroll-up-aggressively / scroll-down-aggressively 对自动滚动的控制方式相互矛盾,因此你应仅选择其中一种方式来自定义自动滚动。若同时自定义了多个变量,其优先级顺序为: scroll-conservatively 最高,其次是 scroll-step ,最后是 scroll-up-aggressively / scroll-down-aggressively 。
变量 scroll-margin 会限制光标能靠近窗口顶部或底部的距离(即便激进滚动设置的比例 f ,超出了窗口上下边距之间的区域比例)。其值为屏幕行数,当光标与窗口顶部或底部的距离小于该行数时,Emacs 会执行自动滚动。 scroll-margin 的默认值为 0。默认情况下,有效边距的大小被限制为窗口高度的四分之一,不过可通过自定义变量 ~maximum-scroll-margin ,将该限制提高至窗口高度的一半(也可降低至 0)。
16.4. 水平滚动
Horizontal scrolling 水平滚动指将窗口内的所有行向侧面偏移,使左边缘附近的部分文本不显示。当窗口中的文本被水平滚动时,文本行将 truncated被截断 而非折行显示(参见《行截断》相关内容)。若窗口显示的是被截断的文本,每当光标移出屏幕的左边缘或右边缘时,Emacs 会执行自动水平滚动。默认情况下,窗口内的所有行会一起进行水平滚动;但如果将变量 auto-hscroll-mode 设为特殊值 current-line ,则仅显示光标的那一行会被滚动。若要完全关闭自动水平滚动,将变量 auto-hscroll-mode 设为 nil 即可。注意,当自动水平滚动关闭后,若光标移出屏幕边缘,光标会消失以作提示(在文本终端中,光标则会停留在边缘位置)。
变量 hscroll-margin 用于控制光标距离窗口左右边缘多近时触发自动水平滚动,其单位为列。例如,若该值设为 5,当光标移动到距离某一边缘 5 列范围内时,会触发水平滚动并远离该边缘。
变量 hscroll-step 决定了光标过近边缘时,窗口的滚动列数。默认值 0 表示将光标在窗口中水平居中;正整数值表示滚动的具体列数;0 到 1 之间的浮点数则表示按窗口宽度的该比例进行滚动。
你也可以通过以下命令执行显式水平滚动:
C-x <- 向左滚动当前窗口中的文本 (
scroll-left) 。 C-x >- 向右滚动 (
scroll-right) 。
C-x < (scroll-left) 会将选中窗口的文本向左滚动窗口的完整宽度减两列的距离(换言之,窗口内的文本相对窗口向左移动)。若带数字参数 n ,则向左滚动 n 列。
当文本被向左滚动后,若光标移出窗口左边缘,光标会固定在窗口左边缘,直至光标移回文本的显示区域。此行为与 auto-hscroll-mode 的当前设置无关 —— 对于向左滚动的文本,该变量仅影响窗口右边缘处的行为。
C-x > (scroll-right) 的向右滚动行为与之类似。当窗口恢复正常显示(每行均从窗口左边缘开始)后,无法再继续向右滚动,此时执行该操作无任何效果。这意味着你无需为 C-x > 精确计算参数,任何足够大的参数都能恢复正常显示。
若通过上述命令对窗口进行水平滚动,该操作会为自动水平滚动设置一个下限。自动水平滚动仍会继续作用于窗口,但向右滚动的距离绝不会超过你此前通过 scroll-left 命令设置的距离。当 auto-hscroll-mode 设为 current-line 时,除显示光标的行外,其他所有行都会按该最小距离滚动。
在图形化显示界面中,若开启可选的 horizontal-scroll-bar-mode (水平滚动条模式),你可通过水平滚动条对窗口进行水平滚动,参见《滚动条》相关内容
16.5. 窄化显示(Narrowing)
Narrowing 内容窄化指将操作焦点限定在缓冲区的某一部分,使其余部分暂时无法访问。仍可操作的这部分区域被称为 accessible portion可访问区域 。取消窄化、让整个缓冲区恢复可访问状态的操作,称为 widening内容展宽 。缓冲区当前生效的窄化范围,被称为缓冲区的 restriction访问限制 。
通过内容窄化隐藏无关内容,能让你更专注地处理单个子程序或段落;同时,它也可用于限制替换命令或重复执行的键盘宏的作用范围。
窄化相关核心命令
C-x n n- 窄化至光标与标记之间的区域 (
narrow-to-region) 。 C-x n w- 展宽缓冲区,恢复全部内容的可访问性 (
widen) 。 C-x n p- 窄化至光标所在的当前页面 (
narrow-to-page) 。 C-x n d- 窄化至光标所在的当前函数定义块 (
narrow-to-defun) 。
当缓冲区被窄化到某一部分后,该部分会呈现为缓冲区的全部内容:你无法看到其余部分,无法将光标移至该区域外(移动命令无法超出可访问区域),也无法对不可访问部分进行任何修改。但这些内容并未被删除,若你保存文件,所有不可访问的文本都会被一并保存。只要窄化状态生效,模式行中会显示Narrow(窄化)字样,提示当前的窄化状态。
核心的窄化命令为 C-x n n (narrow-to-region) ,执行该命令后,缓冲区的访问限制会被设定为当前选中的区域,仅该区域内的文本可访问,区域之前和之后的所有文本均变为不可访问,光标与标记的位置不会发生改变。
此外,可使用 C-x n p (narrow-to-page) 窄化至光标所在的当前页面(关于页面的定义,参见 “页面” 相关章节); C-x n d (narrow-to-defun) 可窄化至包含光标在内的当前函数定义块(参见 “顶层定义 或 函数定义块“ 相关章节)。
取消窄化的唯一方式是执行 C-x n w (widen) 进行内容展宽,该操作会清除缓冲区的访问限制,恢复全部文本的可访问性。
你可通过 C-x = 命令查看当前窄化的具体范围信息(参见 “光标位置信息” 相关章节)。
由于对于不了解窄化功能的用户而言,该操作极易造成操作困惑,因此 narrow-to-region 默认是 禁用命令 。首次尝试执行该命令时,Emacs 会弹出确认提示,并提供启用该命令的选项;若你选择启用,后续执行该命令将不再需要确认(关于禁用命令的相关说明,参见 “禁用命令” 相关章节)。
16.6. 查看模式(View Mode)
M-x view-mode 查看模式是一种次要模式,可按整屏顺序浏览缓冲区内容。该模式提供了便捷的缓冲区滚动命令,但不支持对内容进行修改。除常规的 Emacs 光标移动命令外,可按下 SPC (空格) 向下滚动一整屏,按下 S-SPC 或 DEL 向上滚动,按下s 启动增量搜索。
按下 q (View-quit) 会关闭查看模式,并切回开启该模式前的缓冲区及光标位置。按下 e (View-exit) 会关闭查看模式,同时保留当前的缓冲区及光标位置。
执行 M-x view-buffer会 提示选择一个已存在的 Emacs 缓冲区,切换至该缓冲区并启用查看模式。执行 M-x view-file 会提示选择一个文件,打开该文件并同时启用查看模式。
16.7. 跟随模式(Follow Mode)
Follow mode 跟随模式是一种次要模式,可让两个显示同一缓冲区的窗口,如同一个纵向的超大虚拟窗口般同步滚动。使用跟随模式的操作方法为:先打开一个仅含单个窗口的框架,通过 C-x 3 将其拆分为两个左右并排的窗口,再执行 M-x follow-mode 即可启用。启用后,你可在任意一个窗口中编辑缓冲区、滚动页面,另一个窗口会自动同步跟随操作。
在跟随模式下,若将光标从一个窗口的可视区域移出,移入另一个窗口的可视区域时,系统会自动选中该窗口 —— 这一逻辑同样将两个窗口视作同一个大窗口的不同部分。
再次执行 M-x follow-mode ,即可关闭跟随模式。
16.8. 文本样式(Text Faces)
在 Emacs 的世界里,Face 简单来说就是控制文本外观的“样式表”。
Emacs 可采用多种不同样式显示文本,这些样式被称为 faces外观 。每种外观均可定义各类 face attributes 外观属性,包括 font字体、height字号、wight字重、slant字体倾斜、foreground前景色、background背景色,以及underlining下划线或overlining上划线样式。绝大多数主模式会通过 Font Lock mode字体锁定模式 ,为文本自动分配对应外观。有关外观分配的详细规则,参见「字体锁定模式」相关内容。
若要查看当前已定义的所有外观及对应的显示效果,可执行命令 M-x list-faces-display 。若为该命令添加前缀参数,Emacs 会提示输入一个正则表达式,仅显示名称与该正则表达式匹配的外观(参见「正则表达式语法」)。
同一种外观在不同框架中,显示效果可能不同。例如,部分文本终端并不支持所有外观属性,尤其是font字体、height字号和width字符宽度,还有些终端仅支持有限的色彩范围。此外,为保证文字的可读性,Emacs 的绝大多数外观都做了特殊定义:在light浅色和dark深色的框架背景下,其属性会呈现不同效果。默认情况下,Emacs 会根据每个框架的当background前背景色,自动选择对应的外观属性集进行显示。你也可以通过将变量 frame-background-mode 设为非 nil 值,覆盖这一默认行为:将该变量设为 dark 时,Emacs 会将所有框架均视作深色背景;设为 light 时,则将所有框架均视作浅色背景。
你可对任意外观进行自定义,修改其属性,并将这些自定义设置保存,供后续的 Emacs 会话使用。具体方法参见「自定义外观」相关内容。
default 是文本显示的默认样式,其所有属性均已预先定义,且该外观的背景色会同时作为框架的背景色。有关色彩的设置细节,参见「外观颜色」章节。
另一种特殊的样式是 cursor face光标外观 。在图形化显示界面中,该外观的背景色会被用于绘制文本光标,而该外观的其他所有属性均不产生作用;光标覆盖区域内文本的前景色,会沿用底层文本的背景色。在文本终端中,文本光标的显示样式由终端本身决定,与光标外观无关。
你也可通过 X 资源 配置任意特定外观的属性,相关方法参见「X 资源」章节。
Emacs 支持显示 variable-width变宽字体 ,但部分 Emacs 命令(尤其是缩进相关命令)无法适配字符显示宽度的变化。因此,建议不要为绝大多数外观设置变宽字体,尤其是由字体锁定模式自动分配的外观。
16.9. 外观颜色设置
外观可设置不同的前景色和背景色。为外观指定颜色时(例如自定义面版的场景,参见「自定义外观」),可使用 color name 颜色名称或 RGB triplet RGB 三元组两种方式。
16.9.1. 颜色名称
颜色名称为 pre-defined name预定义名称,例如深橙色('dark orange')、中海绿色('medium sea green')。键入命令 M-x list-colors-display 可查看颜色名称列表;通过自定义变量 list-colors-sort ,可控制颜色的显示顺序。在图形化显示器中执行该命令,会显示 Emacs 支持的所有颜色名称(均为 X11 标准颜色名称,定义于 X 系统的 rgb.txt 文件);在文本终端中执行该命令,仅会显示可在该类终端上正常显示的少量颜色子集。即便在文本终端中,Emacs 仍能识别所有 X11 颜色名称;若为某一面版指定了 X11 颜色名称对应的颜色,终端会自动匹配最相近的颜色进行显示。
16.9.2. RGB 三元组(RGB Triplets)
RGB 三元组为 "#RRGGBB" 格式的字符串,其中红、绿、蓝三原色的分量各由一个十六进制数表示,取值范围为00(亮度为 0)至FF(最大亮度)。每个颜色分量也可使用 1 位、3 位或 4 位十六进制数表示,因此红色可写作 #F00 、 #fff000000 或 #ffff00000000 , 注意各分量的位数必须保持一致 。十六进制数中的 A-F 字符,大小写均可。
执行 M-x list-colors-display 命令时,也会同时显示每个命名颜色对应的 RGB 三元组,例如中海绿色(medium sea green)对应的 RGB 三元组为 #3CB371 。
你可通过命令 M-x set-face-foreground 和 M-x set-face-background ,分别修改面版的前景色和背景色。执行该类命令时,迷你缓冲区会提示你输入面版名称和颜色(支持补全),确认后即可为该面版应用指定颜色。这两个命令的效果会作用于所有 Emacs 窗口,但与使用自定义缓冲区或 X 资源的方式不同,其设置不会在后续的 Emacs 会话中保留。你也可通过窗口参数,为指定的单个窗口设置前景色和背景色,参见「框架参数」章节。
16.10. 标准外观(Standard Faces)
以下是用于指定文本显示样式的标准样式,可将其应用于特定文本以实现对应的显示效果。
default- (默认样式)该样式适用于未指定任何样式的普通文本,其背景色会作为 Emacs 窗口的背景色。
bold- (粗体样式)使用默认字体的粗体变体。
italic- (斜体样式)使用默认字体的斜体变体。
bold-italic- (粗斜体样式)使用默认字体的粗斜体变体。
underline- (下划线样式)为文本添加下划线样式。
fixed-pitch- (等宽样式)强制使用 fixed-width 等宽字体。可根据需求自定义该样式,替换为其他等宽字体,但不可将其设为 variable-width 变宽字体。
fixed-pitch-serif- (衬线等宽样式)与等宽样式功能一致,区别在于该样式使用 serifs 带衬线的字体,视觉上更接近传统打字机的字体样式。
variable-pitch- (变宽样式)强制使用变宽(即比例)字体,其字体大小与默认样式(通常为等宽字体)的字体大小保持一致。
variable-pitch-text- (文本变宽样式)继承自变宽样式,字体尺寸略大于变宽样式。与等宽字体同高度的比例字体,视觉上通常会显得更小,可读性也会随之降低。因此在显示大篇幅文本时,该样式是比变宽样式(尺寸略小)更优的选择。
shadow- (浅显样式)用于让文本比周围的普通文本更不显眼,通常通过使用灰色调,与黑色或白色的默认前景色形成对比来实现该效果。
以下是一组不完整的样式列表,这类样式用于为特定目的临时高亮文本的特定部分(许多其他模式也会为此定义专属样式表)。
highlight- (高亮样式)在多种场景下用于文本高亮,例如鼠标光标移至超链接上时的文本高亮。
isearch- (增量搜索高亮样式)用于高亮增量搜索的当前匹配结果(参见增量搜索)。
query-replace- (查询替换高亮样式)用于高亮查询替换的当前匹配结果(参见替换命令)。
lazy-highlight- (延迟高亮样式)用于高亮增量搜索和查询替换中的非当前匹配结果(延迟匹配项)。
region- (选区样式)用于显示激活的文本选区(参见《标记与选区》)。当 Emacs 编译时启用 GTK+ 支持时,该样式的颜色会继承当前的 GTK+ 主题。
secondary-selection- (二级选区样式)用于显示 X 系统的二级选区(参见二级选区)。
trailing-whitespace- (行尾空白样式)当变量
show-trailing-whitespace非空时,用于高亮行尾的多余空格和制表符(参见无用空白字符)。 escape-glyph- (转义符号样式)用于显示控制字符和转义序列(参见文本的显示方式)。
homoglyph- (形近字符样式)用于显示形近字符,即外观相似但实际并非所代表的字符(参见文本的显示方式)。
nobreak-space- (不换行空格样式)用于显示不换行空格字符(参见文本的显示方式)。
nobreak-hyphen- (不换行连字符样式)用于显示不换行连字符(参见文本的显示方式)。
以下样式用于控制 Emacs 框架各组成部分的显示样式:
mode-line(模式行样式)是模式行的基础样式,同时也适用于标题行,且在未使用工具包菜单时适用于菜单栏。默认情况下,在图形化显示器中会为其添加阴影效果以实现凸起视觉感;在文本终端中,其显示样式为默认样式的反色。
模式行实际使用的
mode-line-active和mode-line-inactive均继承自该样式。mode-line-active- (激活模式行样式)与
mode-line样式一致,专用于当前选中窗口的模式行。该样式继承自mode-line,因此对模式行样式的修改会作用于所有窗口的模式行。 mode-line-inactive- (非激活模式行样式) 与
mode-line一致,专用于非选中窗口的模式行(当变量mode-line-in-non-selected-windows非空时生效)。该样式继承自mode-line,因此对模式行样式的修改会作用于所有窗口的模式行。 mode-line-highlight- (模式行高亮样式) 与
highlight样式功能一致,专用于模式行上的鼠标敏感文本区域。鼠标指针悬停在该类文本区域时,通常会弹出工具提示(参见工具提示)。 mode-line-buffer-id- (模式行缓冲区标识样式)用于模式行中显示缓冲区标识的部分。
header-line- (标题行样式) 与
mode-line样式功能类似,专用于窗口的标题行;标题行显示在窗口顶部,模式行则显示在窗口底部。大多数窗口无标题行,仅部分特殊模式(如 info mode信息模式)会生成标题行。 header-line-highlight- (标题行高亮样式)与高亮样式、模式行高亮样式功能一致,专用于标题行上的鼠标敏感文本区域。该样式为独立样式,因标题行样式的自定义设置可能与高亮样式不兼容。
tab-line- (标签行样式)与
mode-line样式功能类似,专用于窗口的标签行;标签行显示在窗口顶部,以标签形式展示窗口的各个缓冲区(参见窗口标签行)。 vertical-border- (垂直边框样式)在文本终端中,用于显示窗口之间的垂直分隔线。
minibuffer-prompt- (迷你缓冲区提示符样式) 用于显示迷你缓冲区中的提示符字符串。默认情况下,Emacs 会自动将该样式添加至变量
minibuffer-prompt-properties的取值中;该变量是一个文本属性列表(参见《Emacs Lisp 参考手册》中的文本属性),用于控制提示符文本的显示(进入迷你缓冲区时该变量生效)。 fringe- (边距样式)在图形化显示器中,用于显示窗口左右两侧的边距区域(边距是 Emacs 窗口中,文本区域与窗口左右边框之间的窄条区域)(参见窗口边距)。
cursor- (光标样式)该样式的
:background属性用于指定文本光标的颜色(参见光标的显示)。 tooltip- (工具提示样式)用于显示工具提示的文本。默认情况下,若 Emacs 编译时启用 GTK+ 支持,工具提示会由 GTK+ 渲染,该样式将失效(参见工具提示)。
mouse- (鼠标指针样式)用于指定鼠标指针的颜色。
以下外观样式同样用于控制 Emacs 窗口各组成部分的显示样式,但仅在文本终端中,或Emacs 基于 X 系统编译且未启用工具包支持时生效。其他场景下,对应窗口组件的显示样式由系统全局设置决定。
scroll-bar- (滚动条样式)用于指定滚动条的视觉样式(参见滚动条)。
tool-bar- (工具栏样式)用于指定工具栏图标的颜色(参见工具栏)。
tab-bar- (标签栏样式)用于指定标签栏图标的颜色(参见标签栏)。
menu- (菜单样式)用于指定 Emacs 菜单的颜色和字体(参见菜单栏)。
tty-menu-enabled-face- (终端可用菜单项样式)在文本模式终端中,用于显示可用的菜单项。
tty-menu-disabled-face- (终端禁用菜单项样式)在文本模式终端中,用于显示禁用的菜单项。
tty-menu-selected-face- (终端选中菜单项样式)在文本模式终端中,用于显示待选中的菜单项(单击鼠标或按下
RET回车键即可选中该菜单项)
16.11. 图标(Icons)
Emacs 会在部分场景下显示可点击的按钮(或其他信息类图标),你可自定义这些图标的显示样式。
此处的核心自定义项为用户选项 icon-preference (图标偏好)。通过该选项,你可以向 Emacs 设定自己对图标的整体显示偏好。该选项的取值为 图标类型列表 ,Emacs 会选用列表中首个受支持的图标类型。目前支持的图标类型包括:
image- 使用图像作为图标显示
emoji- 使用彩色表情符号作为图标显示
symbol- 使用单色符号作为图标显示
text- 使用简单文本作为图标显示
此外,你可通过命令 M-x customize-icon 对单个图标进行个性化设置,主题也可进一步修改所有图标的显示样式。
若需快速查看某一图标的说明信息,可使用命令 M-x describe-icon 。
16.12. 文本缩放(Text Scale)
要增大当前缓冲区中默认面版的字体大小,可按下 C-x C-+ 或 C-x C-= ;要减小字体大小,按下 C-x C-- ;恢复默认(全局)字体大小则按下 C-x C-0 。这些快捷键均绑定至同一个命令 text-scale-adjust ,该命令会根据最后按下的按键判断执行的操作,并通过修改默认面版的高度属性相应调整字体大小。
大多数面版并未显式设置 :height 属性,因此会继承默认面版的高度,这类面版的字体大小也会随上述命令同步缩放。
对于默认面版之外、显式设置了 :height 属性的面版,其字体大小不会受上述命令影响; header-line 标题行面版为特例:即便显式设置了 :height 属性,该面版仍会随命令同步缩放。
同理,当鼠标指针置于缓冲区文本区域时,按住 Ctrl 键滚动鼠标滚轮,也会根据滚动方向增大或减小相关面版的字体大小。
执行上述缩放命令时,后续的调节按键可省略前置的 C-x 和修饰键直接重复按下。例如, C-x C-= C-= C-= 与 C-x C-= = = 两种操作,均可将面版高度增大三级。每级缩放会将文本高度乘以1.2的系数,若需修改该系数,可自定义变量 text-scale-mode-step 。为 text-scale-adjust 命令传入数字参数0,效果与按下 C-x C-0= 一致,均可恢复默认的文本高度。
若要全局修改所有区域的字体大小,可按下C-x C-M-+、C-x C-M-=、C-x C-M– 或C-x C-M-0,也可同时按住Ctrl 键和 Meta 键滚动鼠标滚轮。若希望全局修改字体大小时,Emacs 窗口也随之自动调整尺寸,可自定义变量 global-text-scale-adjust-resizes-frames (参见简易自定义界面)。
命令 text-scale-increase 和 text-scale-decrease ,分别实现与 C-x C-+ 、 C-x C-- 完全相同的功能,仅调整当前缓冲区的字体大小。相比绑定 text-scale-adjust ,直接绑定这两个命令可能会更便捷。
命令 text-scale-set 可根据其前缀参数,将当前缓冲区的字体大小缩放至指定的绝对级别。
当当前文本的缩放比例非 1 时,上述所有缩放命令会自动启用次要模式 text-scale-mode ;缩放比例恢复为 1 时,该模式则会自动关闭。
命令 text-scale-pinch 支持通过触控板的捏合手势调整文本缩放比例:将两根手指放在触控板上相互靠近或远离,命令会根据手指间的距离变化放大或缩小文本。该功能仅在部分搭载兼容硬件的系统上可用。
命令 mouse-wheel-text-scale 也可调整文本缩放比例,该命令通常在按住 Ctrl 键滚动鼠标滚轮时触发,向下滚动滚轮会放大文本,向上滚动滚轮则会缩小文本。
16.13. 字体锁定模式(Font Lock mode)
字体锁定模式是一种次要模式,仅作用于单个缓冲区,该模式会为缓冲区中的文本分配对应面版(即进行字体着色)。每个缓冲区的主模式会告知字体锁定模式需要对哪些文本进行着色;例如,编程语言相关主模式会为注释、字符串、函数名等语法相关结构进行字体着色。
支持字体锁定模式的主模式会默认启用该功能。在当前缓冲区中切换其开关状态,可执行命令 M-x font-lock-mode ;传入正数值参数会强制启用字体锁定模式,传入负数或 0 参数则会关闭该模式。
执行命令 M-x global-font-lock-mode 可在所有缓冲区中统一切换字体锁定模式的开关。若要让该设置在后续的 Emacs 会话中生效,可自定义变量 global-font-lock-mode (参见简易自定义界面),或在初始化文件中添加以下代码行:
(global-font-lock-mode 0)
若你已关闭全局字体锁定模式,仍可通过将函数 font-lock-mode 添加至模式钩子,为特定主模式单独启用字体锁定功能(参见钩子)。例如,为 C 语言文件编辑启用该模式,可添加以下配置:
(add-hook 'c-mode-hook 'font-lock-mode)
字体锁定模式会使用多个特定命名的面版完成着色工作,包括 font-lock-string-face (字符串着色面版)、 font-lock-comment-face (注释着色面版)等。查看所有相关面版的最简方式为执行 M-x customize-group RET font-lock-faces RET ,随后可在该自定义缓冲区中修改这些面版的显示样式(参见自定义面版)。
对超大缓冲区进行字体着色会消耗较多时间。为避免打开文件时出现长时间卡顿,Emacs 初始状态下仅会对缓冲区的可见区域进行着色。当你滚动浏览缓冲区时,新进入可见区域的文本会在显示的同时完成着色;这种字体锁定方式被称为 即时锁定 (Just-In-Time (or JIT))。你可通过自定义 jit-lock自定义组 中的相关变量,控制即时锁定的行为,包括设置让 Emacs 在空闲时执行着色操作(参见自定义特定项)。
主模式用于判断缓冲区中哪些文本需要着色、以及为其分配何种面版的依据,来自多种不同的文本分析方式:
- 基于正则表达式,检索关键字及其他文本模式(参见正则表达式搜索);
- 基于内置的语法表,识别文本中语法上彼此独立的部分(参见《Emacs Lisp 参考手册》中的《语法表》章节);
- 通过专用类库(如 tree-sitter 类库,参见《Emacs Lisp 参考手册》中的程序源代码解析章节)或外部程序,调用完整解析器生成的语法树进行分析。
- 传统字体锁定
- 基于解析器的字体锁定
16.13.1. 传统字体锁定
提供字体锁定信息的「Traditional传统」方法,基于正则表达式搜索,以及借助 Emacs 内置语法表开展的句法分析。本小节将介绍,针对采用这些传统方法的主模式,字体锁定功能的使用与自定义方式。
对于支持该特性的主模式,你可通过自定义变量 font-lock-maximum-decoration ,控制字体锁定模式的着色精细程度。该变量的取值可为数字(数字 1 代表最低程度的着色,部分模式支持最高至 3 级的着色程度);也可为 t ,表示「尽可能高的着色程度」(默认值)。若要让该自定义设置对某一文件缓冲区生效,需在打开文件前完成 font-lock-maximum-decoration 的配置;若已打开文件后才修改该变量,需关闭该缓冲区,重新打开文件使设置生效。
你也可为特定主模式单独指定不同的着色等级。例如,要将 C/C++ 模式的着色等级设为 1,其他模式使用默认等级,可将该变量设为以下值:
'((c-mode . 1) (c++-mode . 1)))
注释与字符串的着色(或称「句法性」着色),依赖对缓冲区文本句法结构的分析。为提升处理速度,包括 Lisp 模式在内的部分模式遵循一项特殊约定: 最左侧列中的左括号或左大括号,始终表示函数定义(defun)的起始位置,因此永远处于任意字符串或注释之外 。因此,若左括号或左大括号出现在字符串或注释内部,请勿将其放在最左侧列。详情参见「左边界约定」相关内容。
绝大多数模式都已预置字体锁定的高亮匹配规则,但若你需要为额外的内容模式添加着色,可使用函数 font-lock-add-keywords ,为特定模式自定义高亮匹配规则。例如,要在 C 语言的注释中高亮显示”FIXME:“字样,可使用以下代码:
(add-hook 'c-mode-hook
(lambda ()
(font-lock-add-keywords nil
'(("\\<\\(FIXME\\):" 1
font-lock-warning-face t)))))
若要从字体锁定的高亮匹配规则中移除关键词,可使用函数 font-lock-remove-keywords ,详情参见《Emacs Lisp 参考手册》中的「基于搜索的着色」章节。此外,你也可通过自定义 font-lock-ignore 选项,选择性禁用部分关键词的高亮效果,详情参见《Emacs Lisp 参考手册》中的「自定义关键词」章节。
16.13.2. 基于解析器的字体锁定
若你的 Emacs 编译时集成了 tree-sitter 库,便可利用该库对缓冲区文本的解析结果实现文本着色。这一方式通常比上一小节所述的「传统方法」更快、更精准,因为 tree-sitter 库为其所支持的编程语言及其他格式文本,提供了功能完善的专用解析器。基于 tree-sitter 库开发的主模式均命名为 foo-ts-mode 格式,其中的 '-ts-' 后缀即表示该模式启用了此解析库。本小节将介绍基于 tree-sitter 库的字体锁定功能相关用法。
对于基于 tree-sitter 的主模式,你可通过自定义变量 treesit-font-lock-level ,控制其字体锁定模式的着色精细程度。该变量的取值为 1 至 4 之间的整数,各等级对应的着色范围如下:
- 等级 1
- 仅对注释,以及函数定义中的函数名进行着色。
- 等级 2
- 在等级 1 基础上,新增对关键字、字符串和数据类型的着色。
- 等级 3
- 默认着色等级;在等级 2 基础上,新增对赋值语句、数字等内容的着色。
- 等级 4
- 最高着色等级;在等级 3 基础上,对所有可着色内容进行标注,包括运算符、分隔符、方括号、其他标点符号、函数调用中的函数名、属性查找表达式、变量等。
上述各类句法范畴的具体判定标准,由对应主模式及 tree-sitter 为该模式所属语言提供的解析器语法共同决定。但总体而言,这些范畴均遵循该主模式所支持的编程语言或文件格式的通用规范。变量 treesit-font-lock-feature-list 的缓冲区局部值,存储了基于 tree-sitter 的主模式所支持的所有着色特性,其中每个子列表对应一个着色等级,展示该等级所包含的具体着色特性。
通过 M-x customize-variable 命令修改 treesit-font-lock-level 的取值后(参见「自定义特定项」),该设置会立即在当前 Emacs 会话的所有已打开缓冲区中生效,且后续打开的文件也会沿用此设置。
16.14. 交互式高亮(Interactive Highlighting)
Highlight Changes mode 变更高亮模式是一种次要模式,会为缓冲区中 最近修改过的内容 应用不同的文本外观,实现高亮标记。启用或关闭该模式可执行命令 M-x highlight-changes-mode 。
Hi Lock 模式是一款次要模式,可高亮显示缓冲区中与 你指定的正则表达式 相匹配的文本。例如,可通过该模式高亮程序源文件中某个变量的所有引用、某程序大量输出结果中的特定内容,或是一篇文章里的指定名称。启用或关闭 Hi Lock 模式执行命令 M-x hi-lock-mode ;若要为所有缓冲区全局启用该模式,可执行 M-x global-hi-lock-mode ,或在 .emacs 配置文件中添加代码 (global-hi-lock-mode 1) 。
Hi Lock 模式的工作逻辑与字体锁定模式类似(参见字体锁定模式相关内容),区别在于前者需由用户显式指定要高亮的正则表达式。可通过以下命令对该模式的高亮规则进行控制(下述以 C-x w 开头的快捷键已被弃用,官方推荐使用全局的 M-s h 系列快捷键,这些旧快捷键将在未来的 Emacs 版本中移除)。
M-s h r 正则表达式 回车 外观 回车C-x w h regexp RET face RET使用指定的文本外观,高亮所有匹配该正则表达式的文本 (
highlight-regexp) 。该高亮效果会在缓冲区存续期间一直保留。例如,要使用默认高亮外观(黄色背景)标记所有 “whim” 单词,可输入M-s h r whim RET RET。任意文本外观均可用于高亮,Hi Lock 模式自身提供了多款专属外观,且已预加载至默认外观列表中;在命令提示选择外观时,可通过M-n和M-p循环切换该列表中的外观。若为该命令添加数字前缀参数,仅会对正则表达式中的对应子表达式匹配内容进行高亮。若将选项
hi-lock-auto-select-face设为非 nil 值,该命令(及其他所有需要选择外观的 Hi Lock 命令)会自动从默认外观列表中选取下一个外观,无需手动交互选择。该命令可多次执行,为不同正则表达式配置不同的高亮方式。
M-s h u regexp RETC-x w r regexp RET- 取消指定正则表达式对应的高亮效果 (
unhighlight-regexp) 。若通过菜单调用该命令,可从列表中选择要取消的正则表达式;若通过键盘调用,需在迷你缓冲区中操作 —— 迷你缓冲区会默认显示最近添加的高亮正则表达式,按M-n可切换至更早添加的表达式,按M-p可切换至更新的表达式(也可手动输入表达式,支持补全功能)。当要取消的表达式出现在迷你缓冲区时,按RET回车即可退出迷你缓冲区并取消对应高亮。 M-s h l regexp RET face RETC-x w l regexp RET face RET- 使用指定的文本外观, 高亮所有包含该正则表达式匹配内容的整行文本 (
highlight-lines-matching-regexp) 。 M-s h p phrase RET face RETC-x w p 短语 回车 外观 回车- 使用指定的文本外观,高亮匹配该短语的内容 (
highlight-phrase) 。该短语可是任意正则表达式,且命令会自动将短语中的 空格 匹配为任意空白字符,将短语中 首字母小写的字符 设为大小写不敏感匹配。 M-s h .C-x w .- 使用下一个可用的高亮外观,高亮 光标附近的符号 (
highlight-symbol-at-point) 。 M-s h wC-x w b将当前所有的「高亮正则表达式 / 外观」匹配对,插入到 光标所在的缓冲区位置 ,并为其添加注释分隔符,避免该内容干扰程序运行 (
hi-lock-write-interactive-patterns) 。若执行
M-x hi-lock-find-patterns,或在 Hi Lock 模式启用状态下打开某文件(该操作会自动调用hi-lock-find-patterns),程序会从文件的注释中 提取合适的高亮匹配 对并生效。M-s h fC-x w i从当前缓冲区的注释中提取「正则表达式 / 外观」匹配对 (
hi-lock-find-patterns) 。借助该功能,你可先通过highlight-regexp交互式添加高亮匹配对,再通过hi-lock-write-interactive-patterns将其保存到文件中,对其进行编辑(例如为正则表达式中不同括号匹配的部分配置不同高亮外观),最后通过该命令让 Hi Lock 模式根据编辑后的匹配实现高亮。变量
hi-lock-file-patterns-policy用于控制:在打开文件时,Hi Lock 模式是否 自动提取并应用 文件中包含的高亮匹配对。其取值可为:nil(从不自动高亮)、ask(询问用户,为默认值)、或一个函数。若设为函数,hi-lock-find-patterns会将提取到的匹配对作为参数调用该函数;若函数返回非 nil 值,则应用这些匹配对。注意,若直接调用hi-lock-find-patterns,无论该变量取何值,都会对提取到的匹配对执行高亮。此外,若当前主模式的符号存在于列表
hi-lock-exclude-modes中,调用hi-lock-find-patterns时将 不执行任何操作 。
16.15. 窗口边缘(Window Fringes)
在图形化显示界面中,每个 Emacs 窗口的左右两侧默认都会显示窄版的 fringes窗口边缘 区域。该区域用于显示各类符号,以此标注窗口中文本的相关状态信息。你可执行命令 M-x fringe-mode ,切换窗口边缘的显示状态或修改其宽度;该命令会作用于所有框架,若仅需修改当前选中框架的窗口边缘,可使用 M-x set-fringe-style 。通过自定义变量 fringe-mode ,可将你对窗口边缘的设置永久保存。
窗口边缘最常用的功能,是标记 continuation line折行文本 (参见《折行》相关内容):当一行文本被拆分为多个 screen lines 屏幕行显示时,除首个屏幕行外,其余所有屏幕行对应的左侧边缘会显示弯曲箭头,表明此位置并非文本的实际起始处;除最后一个屏幕行外,其余所有屏幕行对应的右侧边缘也会显示弯曲箭头,表明此位置并非文本的实际结束处。若文本的显示方向为从右到左(参见《双向编辑》相关内容),窗口边缘中弯曲箭头的含义会相应互换。
窗口边缘也会用于标记 line truncation行截断 状态(参见行《截断》相关内容):当某行文本因水平滚动而有部分内容超出可视范围时,边缘会显示短水平箭头,箭头方向即为未显示内容的所在方向。用鼠标点击该箭头,窗口会沿箭头方向水平滚动,展示隐藏的文本内容。
此外,窗口边缘还可标注其他文本状态,例如缓冲区边界(参见《显示边界》相关内容)、窗口末尾附近的未使用行(参见 indicate-empty-lines 相关配置),以及正在调试的程序当前的执行位置(参见 Emacs 下运行调试器相关内容)。
当某行文本的宽度与窗口宽度完全一致,且光标处于该行末尾时,窗口边缘区域也会被用于绘制光标。若要关闭该功能,可将变量 overflow-newline-into-fringe 设为 nil ,此时 Emacs 会对宽度与窗口完全一致的文本行执行折行或截断处理。
若你通过自定义 fringe-mode ,隐藏了窗口单侧或双侧的边缘区域,原本显示在边缘处的各类状态标记功能将无法使用。但 折行与行截断的标记 是例外情况:当窗口边缘不可用时,Emacs 会使用每行最左侧和最右侧的字符位,通过特殊 ASCII 字符标记折行与行截断状态(参见折行、行截断相关内容)。这一处理会减少每行可用于显示文本的宽度,因为用于标记折行和截断的字符位会被专门预留,无法再显示普通文本。由于缓冲区中的文本可能包含双向显示内容,即同时存在从左到右和从右到左的段落(参见双向编辑相关内容),因此即便是仅隐藏单侧的窗口边缘,Emacs 仍会在窗口两侧各预留一个字符位,用于标注折行和截断状态 —— 这是因为在从右到左的段落中,这类标记会显示在窗口的对侧位置。
16.16. 边界显示(Displaying Boundaries)
Emacs 可显示 fill-column填充列 位置的标记(参见显式填充命令相关内容)。填充列标记是一项实用功能,在编程模式及其派生模式中尤为常用(参见主模式相关内容),用于标记一个特定列的位置,该列对程序源代码的格式化排版具有特殊意义。此功能的生效前提是,缓冲区使用 fixed-pitch font等宽字体 —— 即除全角字符外,所有字符在显示时宽度一致;若缓冲区使用 variable-pitch fonts变宽字体,不同行的填充列标记可能出现对不齐的情况。
要启用填充列标记的显示功能,可使用次要模式 display-fill-column-indicator-mode 和 global-display-fill-column-indicator-mode ,二者分别用于在当前缓冲区本地启用、在所有缓冲区全局启用该标记。
你也可通过设置两个缓冲区局部变量 display-fill-column-indicator 和 display-fill-column-indicator-character ,来启用填充列标记并控制标记所使用的字符。注意,只有当两个变量均设为非 nil 值时,填充列标记才会显示(启用上述次要模式会自动为这两个变量赋值)。
可通过以下 2 个缓冲区局部变量和 1 个文本外观,对该模式进行自定义配置:
display-fill-column-indicator-column指定填充列标记的显示列号。该变量可设为正整数(表示具体列号),也可设为特殊值t(表示使用变量
fill-column的取值作为标记列号);设为其他任意值则会禁用填充列标记,该变量默认值为
t。display-fill-column-indicator-character指定用于填充列标记的字符。该字符可为任意有效字符,若字体支持,也可使用 Unicode 字符;变量设为
nil则禁用填充列标记。当通过
display-fill-column-indicator-mode或global-display-fill-column-indicator-mode启用该模式时,若此变量为非 nil 值,将使用该变量指定的字符作为标记;若为 =nil=,Emacs 会默认使用字符U+2502(细竖线绘制符),若该字符无法显示,则回退使用竖线符号 "|"。fill-column-indicator- 指定用于显示填充列标记的文本外观。该外观默认继承
shadow外观的属性,但不包含背景色;若要修改填充列标记的颜色,仅需设置该外观的前景色即可。
在图形化显示界面中,Emacs 还可在 窗口边缘 区域标记缓冲区的边界。启用该功能后,缓冲区的首行和末行会在边缘区域显示角度图标,同时可搭配上下箭头图标,标识当前窗口是否可进行滚动操作。
缓冲区局部变量 indicate-buffer-boundaries ,用于控制缓冲区边界和窗口滚动状态在边缘区域的显示方式:
- 若变量值设为
left或right,则角度图标和箭头图标会一同显示在左侧边缘或右侧边缘区域; - 若变量值设为 关联列表 (参见《Emacs Lisp 参考手册》中的关联列表相关内容),列表中的每个元素均为 (标记类型。显示位置) 的形式,用于指定单个标记的显示位置。其中,标记类型可为 top(顶部)、bottom(底部)、up(向上)、down(向下),或特殊值 t(为列表中未指定的标记设置默认显示位置);显示位置可为 left(左侧)、right(右侧),或 nil(不显示该标记)。
例如,设置值为 ((top . left) (t . right)) ,表示将顶部角度图标显示在左侧边缘,底部角度图标和上下箭头图标均显示在右侧边缘;若仅需在左侧边缘显示角度图标、不显示箭头图标,可将变量值设为 ((top . left) (bottom . left)) 。
16.17. 无用空白字符(Useless Whitespace)
编辑时很容易在 行尾 无意间留下多余的空格,或在 缓冲区末尾 留下空行。多数情况下,这些尾随空白字符不会产生实际影响,但有时会造成不必要的麻烦。
将缓冲区局部变量 show-trailing-whitespace 设为 t,即可让行尾的尾随空白字符变为可见状态,Emacs 会通过 trailing-whitespace 文本外观对其进行标记显示。
该功能在 光标位于含空白字符的行尾 时会暂时失效。严格来说,此时的空白字符仍属于尾随空白,但在输入新文本的过程中,对其进行特殊标记会影响视觉体验,而光标所处的位置本身就足以提示用户此处存在空白字符。
执行命令 M-x delete-trailing-whitespace 可删除所有尾随空白字符,该命令会清除缓冲区中 每行行尾 的所有多余空格,以及 缓冲区末尾 的所有空行;若要保留缓冲区末尾的空行,可将变量 delete-trailing-lines 设为 nil 。若当前区域处于激活状态,该命令仅会删除该区域内每行行尾的多余空格。
在图形化显示界面中,Emacs 可在 左侧窗口边缘 通过小图标标记出窗口末尾的未使用行(参见窗口边缘相关内容)。该图标会显示在所有不对应缓冲区文本的屏幕行处,因此缓冲区末尾的空行会因 缺少该图标 而变得醒目。启用该功能需将缓冲区局部变量 indicate-empty-lines 设为非 nil 值;若要为所有新建缓冲区启用该功能,可设置该变量的默认值,例如添加配置 (setq-default indicate-empty-lines t) 。
空白字符模式 是一款缓冲区局部次要模式,可通过 特殊文本外观标记或特殊符号替代显示 的方式,让缓冲区中的各类空白字符可视化。执行 M-x whitespace-mode 可切换该模式的开启与关闭。需可视化的空白字符类型由列表变量 whitespace-style 决定,执行 M-x whitespace-toggle-options 可在当前缓冲区中单独开启或关闭该列表中的任意配置项。以下是该变量的部分可选配置项(完整列表参见该变量的官方文档):
face- 启用所有基于特殊文本外观的空白字符可视化功能。该配置项具有特殊含义:若列表中缺少此项,则除space-mark、tab-mark和newline-mark外,其余所有可视化功能均失效。
trailing- 高亮显示行尾的尾随空白字符。
tabs- 高亮显示制表符。
spaces- 高亮显示普通空格和不换行空格字符。
lines- 高亮显示超过 80 列的长行,可通过自定义变量
whitespace-line-column修改列数限制。 newline- 高亮显示换行符。
missing-newline-at-eof- 若缓冲区末尾未以换行符结尾,则高亮显示最后一个字符。
empty- 高亮显示缓冲区开头和 / 或末尾的空行。
big-indent- 高亮显示过深的缩进。默认情况下,连续至少 4 个制表符或 32 个普通空格组成的缩进会被高亮,可通过自定义正则表达式
whitespace-big-indent-regexp修改该判定规则。 space-mark- 使用特殊符号替代显示普通空格和不换行空格。
tab-mark- 使用特殊符号替代显示制表符。
newline-mark- 使用特殊符号替代显示换行符。
全局空白字符模式 是一款全局次要模式,可让所有缓冲区中的空白字符实现可视化,执行 M-x global-whitespace-toggle-options 可单独切换该模式下的各项功能。
16.18. 选择性显示(Selective Display)
Emacs 支持隐藏 缩进量超过指定列数 的行,你可利用该功能快速概览程序的部分内容结构。
在当前缓冲区中,带数字参数 n 执行快捷键 C-x $ (set-selective-display) ,即可让缩进量不少于 n 列的行从屏幕中隐藏。若某条可见行后紧跟一行或多行隐藏行,该行末尾会显示三个点(…),作为隐藏内容的标识。
快捷键 C-n 和 C-p 在跳转行时,会直接跳过隐藏的行,如同这些行不存在一般。
被隐藏的行仍会保留在缓冲区中,且绝大多数编辑命令会照常识别这些行,因此光标位置可能会出现在隐藏文本的中间。出现这种情况时,光标会显示在 前一可见行的末尾、三个点之后 ;若光标位于可见行的末尾(换行符之前),则会显示在 三个点之前 。
不带任何参数执行 C-x $ ,即可恢复显示所有被隐藏的行。
若将变量 selective-display-ellipses 设为 nil ,那么紧跟隐藏行的可见行末尾将 不再显示三个点 ,此时缓冲区中无任何视觉标识提示隐藏行的存在。该变量被设置后会自动成为缓冲区局部变量。
你也可使用 《大纲模式》 实现缓冲区文本的部分隐藏,这是另一种文本隐藏的实现方式。
16.19. 模式行可选功能
模式行中的缓冲区百分比 pos 表示窗口顶部之上的内容占整个缓冲区的比例。你可执行命令 M-x size-indication-mode 开启大小指示模式,额外显示缓冲区的字符规模,该数值会紧跟在缓冲区百分比后展示,格式如下:
pos of size
其中 size 是缓冲区字符数的 人性化可读表示 ,会使用缩写单位:k代表 10^3、M代表 10^6、G代表 10^9,依此类推。
开启行号模式后,光标所在的当前行号会显示在模式行中,可通过命令 M-x line-number-mode 开关该模式(默认处于开启状态)。行号会显示在缓冲区百分比 pos 之后,以字母"L"标识行号属性。
同理,执行 M-x column-number-mode 开启列号模式,即可在模式行显示光标当前的列号,列号以字母 'C' 标识。若同时开启行号和列号模式,行号和列号会以 括号包裹 的形式显示(行号在前、列号在后),而不是分别标注 'L'和 'C',例如显示为:'(561,2)'。有关次要模式的详细介绍及上述命令的使用方法,参见「次要模式」相关内容。
列号模式下,显示的列号以窗口左边界为0 起始位计数;若希望列号从 1 开始计数,可将变量 column-number-indicator-zero-based 设为 nil 。
若你对缓冲区进行了窄化操作(参见「窄化」相关内容),模式行显示的行号为相对窄化后可访问区域的行号,因此该数值不能作为 goto-line 命令的参数( what-line 命令可显示相对于整个文件的绝对行号)。你可使用 goto-line-relative 命令,将光标移至窄化后缓冲区可访问区域的指定相对行号位置。
若缓冲区体积过大(字符数超过变量 line-number-display-limit 的取值),Emacs 将不会计算行号(因计算过程会大幅卡顿),模式行也不会显示行号;若要取消该限制,将 line-number-display-limit 设为 nil 即可。
若缓冲区中的行过长,行号计算也会变慢。因此,当光标附近行的平均字符宽度超过变量 line-number-display-limit-width 的取值时,Emacs 同样不会显示行号,该变量的默认值为 200 个字符。
Emacs 支持在所有窗口的模式行中可选显示系统时间和负载,执行命令 M-x display-time 或自定义选项 display-time-mode 即可启用该功能。模式行中新增的相关信息格式如下:
hh:mmPM l.ll
其中 hh 为小时、 mm 为分钟,其后始终跟随 AM (上午)或 PM (下午); l.ll 为系统最近几分钟的平均负载值,即系统中处于运行或就绪状态(等待可用处理器)的进程数量(若操作系统不支持,部分字段可能不会显示)。若偏好 24 小时制时间显示,将变量 display-time-24hr-format 设为 t 即可。
若你存在未读邮件,模式行的系统负载值后会显示单词'Mail'。在图形化显示界面中,可通过自定义变量 display-time-use-mail-icon ,使用图标替代Mail文字,节省模式行的显示空间;也可自定义 display-time-mail-face 文本外观,让邮件提示标识更醒目。你可通过 display-time-mail-file 指定待检查的邮件文件,或设置 display-time-mail-directory 指定收件目录(该目录下所有非空的普通文件均会被视为新收到的邮件)。
在笔记本电脑上运行 Emacs 时,执行命令 display-battery-mode 或自定义变量 display-battery-mode ,即可在模式行中 显示电池电量 。变量 battery-mode-line-format 决定了电池电量的显示格式,具体的模式行提示信息因操作系统而异,通常会以百分比形式展示当前电池电量占总电量的比例。变量 battery-update-functions中 的函数会在模式行更新后运行,可基于电池状态触发自定义操作。
在图形化显示界面中,模式行默认以 3D 方框样式绘制;若你不喜欢该效果,可通过自定义 mode-line 文本外观,将其 box 属性设为 nil 来关闭 3D 效果,详情参见「自定义文本外观」相关内容。
默认情况下,未选中窗口的模式行会使用 mode-line-inactive 外观显示,仅选中窗口的模式行使用 mode-line 外观,该设计可清晰区分当前选中的窗口。当迷你缓冲区被选中时,由于其无模式行,触发迷你缓冲区的原窗口会继续使用 mode-line 外观显示模式行,因此常规的迷你缓冲区操作不会改变任何窗口的模式行显示样式。
若要关闭 mode-line-inactive 外观的使用,将变量 mode-line-in-non-selected-windows 设为 nil 即可,此后所有窗口的模式行均会使用 mode-line 外观显示。
你可通过自定义变量 eol-mnemonic-unix 、 eol-mnemonic-dos 、 eol-mnemonic-mac 和 eol-mnemonic-undecided ,为每种换行格式设置自定义的字符串,实现模式行中换行格式标识的个性化显示。
16.20. 文本显示方式
绝大多数字符为 printing character可打印字符 :这类字符出现在缓冲区中时,会直接按字面形式显示在屏幕上。可打印字符包括 ASCII 数字、字母、标点符号,以及众多非 ASCII 字符。
ASCII 字符集中包含 非打印control characters控制字符 ,其中有两个字符会以特殊形式显示:换行符(Unicode 编码点 U+000A)的显示方式为另起一行,制表符(U+0009)则会显示为连续空格,直至下一个制表位(默认每 8 列一个制表位)。每个制表符对应的空格数由缓冲区局部变量 tab-width 控制,该变量的取值必须是 1 到 1000 之间的整数(包含边界值)。注意,缓冲区中制表符的显示方式,与制表键( TAB )作为命令的定义无任何关联。
其余 ASCII 控制字符(编码小于 U+0020,即八进制 40、十进制 32),会以脱字符 '^' 后跟对应非控制形式字符的样式显示,并应用 escape-glyph 文本外观。例如,'contraol-A' 控制字符 A(U+0001)会显示为'^A'。
编码为 U+0080(八进制 200)至 U+009F(八进制 237)的原始字节,会以八进制转义序列的形式显示,同样应用escape-glyph外观。例如,编码 U+0098(八进制 230)会显示为'\230'。若将缓冲区局部变量 ctl-arrow 设为 nil ,所有 ASCII 控制字符都会改为以八进制转义序列显示,而非脱字符转义序列(你也可设置让原始字节以十六进制形式显示,参见变量display-raw-bytes-as-hex)。
部分非 ASCII 字符的视觉外观,与 ASCII 空格或连字符(减号)完全相同。若这类字符在你不知情的情况下被插入缓冲区(例如通过粘贴操作),可能会引发问题 —— 比如源代码编译器通常不会将非 ASCII 空格识别为空白字符。为解决该问题,Emacs 会对这类字符做特殊显示处理:U+00A0 不换行空格,以及 Unicode 水平空格类的其他字符,会应用 nobreak-space 外观显示;U+00AD 软连字符、U+2010 连字符、U+2011 非断连字符,会应用 nobreak-hyphen 外观显示。若要关闭该特殊显示功能,将变量 nobreak-char-display 设为 nil 即可。若该变量设为非 nil 且非 t 的取值,Emacs 会将这类字符显示为 高亮反斜杠 后跟普通空格或连字符的形式。
你可通过显示表自定义任意特定编码字符的显示方式,详情参见《Emacs Lisp 参考手册》中的「显示表」章节。
在图形化显示界面中,部分字符可能在 Emacs 可用的所有字体中均无对应字形。这类 glyphless characters无字形字符 默认会显示为包含其十六进制编码的方框。同理,在文本终端中,无法通过终端编码显示的字符(参见「终端输入输出的编码系统」),默认会显示为问号。你可通过自定义变量 glyphless-char-display-control ,控制无字形字符的显示方式;也可自定义 glyphless-char 文本外观,让这类字符在屏幕上更醒目。具体细节参见《Emacs Lisp 参考手册》中的「无字形字符的显示」章节。
启用 glyphless-display-mode 次要模式,可切换当前缓冲区中无字形字符的显示样式 —— 切换后,无字形字符会显示为方框,内部标注其字符名称的缩写。
Emacs 会自动检测当前显示设备是否支持显示弯引号 ( ‘ 和 ’ ) 。默认情况下,若检测到设备支持,Emacs 会将消息和帮助文本中的 ASCII 引号 (‘ ` ’ 和 ‘ ' ’) 自动转换为这类弯引号。你可通过自定义用户选项 text-quoting-style ,调整或禁止该转换行为,详情参见《Emacs Lisp 参考手册》中的「文档中的按键」章节。
若检测到弯引号 ‘ 、 ’ 、 “ 和 ” 的显示效果与 ASCII 字符完全一致,这些弯引号会应用 homoglyph 外观显示;若检测到设备不支持显示某类弯引号,该弯引号会替换为对应的 ASCII 近似字符 ` 、 ' 、 和 " ,并同样应用 homoglyph 外观。
16.21. 光标显示(Displaying the Cursor)
在文本终端中,光标的显示样式由终端本身控制,Emacs 基本无法干预。部分终端提供两种光标样式可选:常规可见的静态光标,以及高亮显示的闪烁光标。Emacs 默认使用高亮 闪烁光标 ,并在启动或恢复 Emacs 时自动切换至该样式;若 Emacs 启动或恢复时,变量 visible-cursor 的值为 nil ,则会使用常规静态光标。
在图形化显示界面中,文本光标的多项属性均可自定义。若要修改光标颜色,可调整cursor文本外观的: background (背景色)属性(参见自定义文本外观相关内容)。(该外观的其他属性均无实际效果,光标覆盖区域的文本会使用框架的背景色绘制。)若要修改光标形状,可自定义缓冲区局部变量 cursor-type ,其可选值包括:
box:方块光标(默认样式)(box . size):方块光标(当遮罩图像的宽或高超过 size 像素时,光标变为空心方块)hollow:空心方块光标bar:竖线光标(bar . n):宽度为 n 像素的竖线光标hbar:横线光标(hbar . n):高度为 n 像素的横线光标nil:隐藏光标
默认情况下,若 Emacs 在 10 次光标闪烁期间未接收到任何输入,光标会停止闪烁;任意输入事件都会重置闪烁计数。你可通过自定义变量 blink-cursor-blinks 控制闪烁次数,该变量的取值为无输入时的最大闪烁次数;将其设为 0 或负数,光标会一直闪烁。若要彻底关闭光标闪烁,可将变量 blink-cursor-mode 设为 nil(参见简易自定义界面),或在初始化文件中添加以下配置行:
(blink-cursor-mode 0)
此外,你也可通过自定义列表变量 blink-cursor-alist ,修改光标熄灭时的显示样式。该列表的每个元素均为 (on-type . off-type) 的形式,含义为:若光标闪烁亮起时为 on-type 亮灯样式(可为上述任意光标类型),则熄灭时显示为 off-type 熄灯样式。
部分字符(如制表符)为 宽字符 ,光标默认定位在这类字符上时,仍会以默认字符宽度绘制。若要让光标自动拉伸以覆盖整个宽字符,可将变量 x-stretch-cursor 设为非 nil 值。
默认情况下, 未选中窗口 中的光标会显示为不闪烁的空心方块(若为竖线光标,则显示为更细的竖线)。若要隐藏未选中窗口中的光标,可将变量 cursor-in-non-selected-windows 设为 nil 。
若要让光标辨识度更高,你可启用行高亮模式(HL Line mode)—— 这是一款次要模式,会高亮显示光标所在的整行文本。执行 M-x hl-line-mode 可在当前缓冲区中开关该模式,执行 M-x global-hl-line-mode 可全局开关该模式。
16.22. 行截断(Line Truncation)
作为折行显示的替代方案(参见折行相关内容),Emacs 可通过 truncation行截断 方式显示长行。行截断指的是,超出屏幕或窗口宽度的字符会被直接隐藏,不再显示。在图形化显示界面中,窗口边缘会显示一个小直箭头,标记行的左侧或右侧存在截断内容;在文本终端中,会在最右侧或最左侧列显示 ‘$’ 符号作为截断标识。
水平滚动会自动触发行截断(参见水平滚动相关内容)。你也可通过快捷键 C-x x t (toggle-truncate-lines) ,为特定缓冲区手动启用行截断功能,该命令的实现原理是修改缓冲区局部变量 truncate-lines 的取值:当该变量为非 nil 值时,长行将被截断显示;当该变量为 nil 值时,长行将折行显示为多个屏幕行。无论通过何种方式设置 truncate-lines ,该变量都会自动成为当前缓冲区的局部变量;在未手动设置前,该变量会使用默认值 nil (即折行显示)。
由于行截断与自动换行(下一节将介绍)功能互斥,执行 toggle-truncate-lines 命令启用行截断时,会同时禁用自动换行功能。
当拆分后的窗口宽度过窄时,Emacs 可能会自动启用行截断。相关控制变量为 truncate-partial-width-windows ,详情参见窗口拆分相关内容。
16.23. 视觉行模式(Visual Line Mode)
作为普通折行显示的另一种替代方案(参见折行相关内容),Emacs 支持使用 word wrap自动换行 功能。开启该功能后,较长的逻辑行会被拆分为两个或多个screen lines屏幕行(也称作「visual lines视觉行」),这一点与普通折行显示类似;不同的是,Emacs 会尝试 在窗口右边缘附近的单词边界处进行换行 (若文本显示方向为从右到左,则在窗口左边缘的单词边界处换行)。这种换行方式不会在单词中间拆分文本,能让内容更易阅读。
自动换行功能由视觉行模式开启,该模式是一款可选的次要模式。在当前缓冲区中执行命令 M-x visual-line-mode 即可开启视觉行模式,重复执行该命令则关闭此模式;也可通过菜单栏操作:在「Options选项」菜单中选择「'Line Wrapping in this Buffer'本缓冲区的换行方式」子菜单,再点击「'Word Wrap (Visual Line mode)'自动换行(视觉行模式)」选项。视觉行模式开启后,模式行的模式显示区域会出现字符串wrap作为标识。执行命令 M-x global-visual-line-mode ,可对所有缓冲区全局切换视觉行模式的开启与关闭。
由于自动换行与上一节介绍的行截断功能互斥,开启视觉行模式的同时会自动禁用行截断功能。
在视觉行模式下,部分编辑命令的操作对象会从 logical lines逻辑行 变为 screen lines视觉行 :
C-a(beginning-of-visual-line):将光标移至当前视觉行的行首C-e(end-of-visual-line):将光标移至当前视觉行的行尾C-k(kill-visual-line):删除光标至当前视觉行尾的文本
若要按 逻辑行 进行光标移动,可使用命令 M-x next-logical-line 和 M-x previous-logical-line ,二者分别将光标移至下一个和上一个逻辑行,且操作效果不受视觉行模式开启状态的影响。若你频繁使用这两个命令,可为其绑定快捷键,具体方法参见「在初始化文件中重新绑定按键」相关内容。
默认情况下,自动换行产生的视觉行 不会在窗口边缘显示标识 。视觉行模式常被用于编辑包含大量长逻辑行的文件,若为每个折行的视觉行都添加边缘标识,会造成视觉干扰;你可通过自定义变量 visual-line-fringe-indicators ,修改这一默认设置。
Emacs 默认仅在空格、制表符这类空白字符后进行换行,不会在「全角空格」等空白字符后折行。Emacs 提供了 word-wrap-whitespace-mode 次要模式,开启后可在当前模式下启用自定义规则的自动换行,并通过用户选项 word-wrap-whitespace-characters 设置允许触发换行的字符;该模式也提供全局版本 global-word-wrap-whitespace-mode ,可对所有缓冲区生效。
当文本中混合了中日韩(CJK)字符与拉丁字符时,仅在空白字符后换行会导致排版效果异常(原因是中日韩字符无需通过空白字符分隔单词)。此时可自定义选项 word-wrap-by-category ,让 Emacs 允许在所有属于 '|' 字符类的字符后换行(参见《Emacs Lisp 参考手册》中的「字符类」章节),该设置能更好地支持中日韩字符的排版。此外,若通过 Emacs 的自定义界面设置该变量,程序会自动加载 kinsoku.el 文件;该文件加载后,Emacs 会 遵循禁则排版规则 进行换行,即属于 '>' 字符类的字符(如 U+FF0C 全角逗号)不会出现在行首,属于 '<' 字符类的字符(如 U+300A 左双角括号)不会出现在行尾。
你可通过命令 char-category-set 和 category-set-mnemonics 查看某个字符所属的字符类;也可将光标移至目标字符处,执行 C-u C-x = ,在弹出的信息报告中查看「category(字符类)」部分的内容。若要为字符添加字符类属性,可使用命令 modify-category-entry 。
16.24. 显示定制(Customization of Display)
本节介绍用于控制 Emacs 界面各类外观细节的变量,初级用户可跳过本节内容。
若希望 Emacs 为缓冲区中的每一行显示行号,可自定义缓冲区局部变量 display-line-numbers (该变量默认值为 nil )。其支持多种取值,对应不同的行号显示模式:
t- 在每一行显示缓冲区文本的 non-continuation screen line非折行屏幕行 前,显示 绝对行号 。若为折行屏幕行,或整行屏幕行仅显示展示字符串 / 覆盖字符串,则不会为该行编号。
relative- 在显示缓冲区文本的非折行屏幕行前,显示 相对行号 。行号以光标所在行为基准,距离当前行越远,行号数值向上下两侧依次递增。
visual- 让 Emacs 按 视觉效果统计行号 —— 仅对实际显示在界面上的行计数(忽略文本隐藏部分的所有行),折行后占用多个屏幕行的逻辑行,会为每个屏幕行依次编号。显示的行号为相对行号,规则与上述
relative取值一致。该模式适用于大纲模式等支持文本折叠的模式(参见大纲模式),也适合需要按屏幕行精确移动光标的场景。 其他值- 任何非 nil 的其他取值,均按
t模式处理。
执行命令 M-x display-line-numbers-mode ,可便捷开启行号显示功能,该模式也提供全局版本 global-display-line-numbers-mode 。用户选项 display-line-numbers-type 用于指定上述两个模式启用时,采用的具体行号显示子模式。
注意,即便全局开启 display-line-numbers-mode , 迷你缓冲区和工具提示 区域也不会显示行号。
当 Emacs 显示相对行号时,可自定义光标所在行的行号显示规则。默认情况下,即便其他行均为相对行号,光标所在行仍会显示 绝对行号 。若将变量 display-line-numbers-current-absolute 设为 nil ,光标所在行的显示行号会变为0。若你无需关注当前行的绝对行号,且希望为大缓冲区的文本预留更多水平显示空间,该设置会非常实用。
在经过窄化的缓冲区中(参见窄化),行号默认从窄化区域的起始位置开始计数。若将变量 display-line-numbers-widen 设为非 nil 值,行号会忽略所有窄化操作,从缓冲区的第一个字符开始计数。
若变量 display-line-numbers-offset 的取值非 0,该数值会被叠加到每个绝对行号上,且行号始终从缓冲区起始位置开始计数(效果等同于 display-line-numbers-widen 设为非 nil)。若该变量设为 0,或行号非绝对行号模式,则此变量不产生任何效果。
在选择性显示模式(参见选择性显示)及其他会隐藏大量行的模式中(如大纲模式、Org 模式),你可自定义变量 display-line-numbers-width-start 和 display-line-numbers-grow-only ,或将 display-line-numbers-width 设为足够大的数值,避免行号预留显示区域出现偶尔的计算错误。
行号会通过专用的 line-number 文本外观显示,光标所在行的行号则使用 line-number-current-line 外观显示,你可通过该设置让当前行号呈现独特样式,便于快速定位光标所在行。此外,还可使用 line-number-major-tick 和 line-number-minor-tick 外观,高亮显示行号为特定数字倍数的行,分别自定义变量 display-line-numbers-major-tick 和 display-line-numbers-minor-tick 即可设置对应的倍数。
若将变量 visible-bell 设为非 nil 值,当 Emacs 原本需要发出提示音时,会改为让整个屏幕闪烁。若你的终端不支持屏幕闪烁功能,该变量将无效。
变量 echo-keystrokes 用于控制多字符按键的回显功能,其取值为触发回显所需的暂停秒数;若设为 0,则表示完全禁用回显。该取值仅在存在可回显内容时生效(参见回显区)。
若变量 echo-keystrokes-help 设为非 nil 值(默认值),根据 echo-keystrokes 规则回显的多字符按键序列,会附带一段简短的帮助文本 —— 按下对应按键可调用 describe-prefix-bindings 命令(参见其他帮助命令),查看已输入前缀对应的所有命令列表。相关的帮助功能可参见 which-key。
在图形化显示界面中,当 Emacs 处于忙碌状态时,鼠标指针会变为沙漏样式。若要禁用该功能,将变量 display-hourglass 设为 nil 即可。变量 hourglass-delay 用于设置 Emacs 忙碌多久后显示沙漏指针,单位为秒,默认值为 1。
当鼠标指针位于 Emacs 框架内时,每次输入字符插入文本时,Emacs 会将鼠标指针隐藏,避免其遮挡文本(准确来说,仅在输入自插入字符时会隐藏指针,参见插入文本)。移动鼠标指针后,其会重新显示。若要禁用该功能,将变量 make-pointer-invisible 设为 nil 即可。
在图形化显示界面中,变量 underline-minimum-offset 用于设置带下划线文本的基线与下划线之间的最小距离,单位为像素,默认值为 1。增大该数值,可提升部分字体下带下划线文本的可读性(但 Emacs 绝不会将下划线绘制到当前行区域之外)。变量 x-underline-at-descent-line 用于控制下划线的绘制位置,默认值为 nil ,表示在字体的基线位置绘制;若设为 t ,则在字体的下沿线位置绘制。(若为带下划线的文本设置了非默认的行间距,参见《Emacs Lisp 参考手册》中的行高章节,Emacs 会将下划线绘制到额外行间距的下方。)
变量 overline-margin 用于设置文本上方上划线的垂直位置(包含上划线自身的高度),单位为像素,默认值为 2。
在部分文本终端中,粗体与反显模式同时使用时,会导致文本难以辨认。调用函数 tty-suppress-bold-inverse-default-colors 并传入非 nil 参数,可在该场景下屏蔽粗体的显示效果。
原始字节默认以八进制格式显示,例如十进制值为 128 的字节会显示为 \200 。若要改为十六进制格式显示(如 \x80 ),将变量 display-raw-bytes-as-hex 设为 t 即可。从包含 Emacs 会话的终端复制文本,或终端的 escape-glyph 外观与默认外观一致时,解析原始字节需格外注意。例如,Emacs 默认会将十进制值 128 的字节,显示为与字符 \ 、 2 、 0 、 0 完全相同的样式;十六进制显示的问题会更严重 —— 原始字节 128 后跟字符 7 会显示为 \x807 ,而 Emacs Lisp 会将其解析为单个字符 U+0807 撒玛利亚字母 IT;对应的八进制显示 \2007 则不会出现该混淆问题,因为八进制转义序列最多包含三位数字。
17. 搜索与替换
与其他编辑器相同,Emacs 提供了字符串查找命令,也支持将指定字符串替换为其他字符串;同时还提供了同类功能的命令,可基于匹配模式而非固定字符串进行查找和替换。
你也可通过 xref 工具在多个文件中执行搜索替换操作(参见《通过标识符进行搜索与替换》),或使用 Dired 中的 A 命令(参见《文件操作》),亦可调用 grep 程序完成该操作(参见《在 Emacs 中使用 Grep 搜索》)。
17.1. 增量搜索(Incremental Search)
Emacs 中的核心搜索命令为 incremental增量搜索 :键入搜索字符串的第一个字符后,搜索即刻开始。在输入搜索字符串的过程中,Emacs 会实时展示当前已键入内容的匹配位置。当键入的字符足以定位到目标位置时,即可停止输入。根据后续的操作需求,你可选择是否通过回车键显式终止本次搜索。
C-s- 正向增量搜索 (
isearch-forward) 。 C-r- 反向增量搜索 (
isearch-backward) 。
你也可通过菜单栏的 'Edit->Search' 菜单调用增量搜索功能。
17.1.1. 增量搜索基础
C-s- 启动正向增量搜索 (
isearch-forward) 。 C-r- 启动反向增量搜索 (
isearch-backward) 。
按下 C-s (isearch-forward) 会开启正向增量搜索,该命令会读取键盘输入的字符,并将光标移至缓冲区中 下一个 匹配字符组合的末尾位置。
例如,按下 C-s 后再键入字母 F ,光标会跳至起始位置之后缓冲区中第一个 F 的后方;若接着键入字母 O,光标会移至第一个 FO 的后方,该 FO 中的 F 未必是此前找到的第一个 F;再键入一个 O,光标则会移至第一个 FOO 的后方。
搜索过程的每一步,Emacs 都会使用 isearch 文本外观,高亮显示当前匹配内容 —— 即缓冲区中与搜索字符串相匹配的文本(参见文本外观)。有关自定义该高亮效果的各类选项,可参见根据需求自定义搜索行为章节。当前的搜索字符串也会同时显示在回显区中。
若输入搜索字符串时出现错误,按下 DEL (isearch-delete-char) 即可撤销,每按一次 DEL 键,都会取消搜索过程中最后输入的一个内容项。当你键入的命令导致 搜索字符串、光标位置、搜索结果的成败状态、搜索方向、当前搜索结果的另一端位置或搜索的循环匹配状态 发生变化时,Emacs 都会记录一个新的 input item 输入内容项。有关处理搜索失败的更多方法,可参见增量搜索中的错误处理章节。
当光标定位到目标位置后,按下回车键 RET (isearch-exit) 即可结束搜索,光标将停留在搜索定位的位置。此外, 所有在搜索中无特殊含义的命令 ,都会先终止搜索,再执行该命令本身。例如,按下 C-a 会先退出搜索,再将光标移至行首;按下方向键会先退出搜索,再执行对应的光标移动操作,依此类推。仅当你接下来要输入的是可打印字符、 DEL 键、 RET 回车键,或搜索中的其他特殊字符( C-q 、 C-w 、 C-r 、 C-s 、 C-y 、 M-y 、 M-r 、 M-c 、 M-e ,以及下文将介绍的部分字符)时,才需要先按 RET 回车键退出搜索。你也可自定义退出搜索的相关命令,具体参见不退出增量搜索的操作章节。
有一个特殊情况:若 搜索字符串为空 时按下 RET 回车键,会直接启动 非增量搜索 (参见非增量搜索章节)。(该行为可自定义,参见根据需求自定义搜索行为章节。)
若要放弃搜索并返回搜索起始位置,按下 ESC ESC ESC (isearch-cancel) 或 C-g C-g (isearch-abort) 即可。
退出增量搜索时,Emacs 会将光标的原始位置添加到 标记环 中,且不会激活标记;你可通过按下 C-u C-SPC 或 C-x C-x ,回到启动搜索前的光标位置(参见标记环章节)。注意,该功能仅在 标记未被激活 时生效;若启动搜索时标记已处于激活状态,按下 C-u C-SPC 或 C-x C-x 都会直接跳至标记位置。
若要进行反向搜索,可按下 C-r (isearch-backward) 而非 C-s 来启动搜索。反向搜索会查找 起始位置之前 结束的匹配内容,这与正向搜索查找起始位置之后开始的匹配内容的规则相对应。
17.1.2. 重复增量搜索
若你正向搜索 “FOO” 并找到匹配项,却并非目标结果 —— 你要找的 “FOO” 出现在缓冲区更靠后的位置,此时可再次按下 C-s (isearch-repeat-forward)跳至该搜索字符串的下一个匹配项,或按下 C-r (isearch-repeat-backward) 跳至上一个匹配项,这些命令可重复执行任意次数。你也可为 C-s 和 C-r 添加数字前缀参数 n ,直接定位到第 n 个下一个或上一个匹配项。若跳转过度,可按下 DEL 键撤销部分 C-s 的执行结果。同理,在反向增量搜索中,每次按下 C-r (isearch-repeat-backward) 都会重复执行反向搜索。
在增量搜索过程中稍作停顿,Emacs 会高亮显示屏幕上该搜索字符串的 所有其他潜在匹配项 ,帮你预判按下 C-s 或 C-r 重复搜索时可跳转的位置。这些其他匹配项会采用与当前匹配项不同的样式高亮,使用可自定义的 lazy-highlight 文本外观(参见文本外观)。若你不需要该功能,可将变量 isearch-lazy-highlight 设为 nil 来禁用。有关匹配项高亮的其他自定义设置,参见根据需求自定义搜索行为章节。
退出某次搜索后,只需连续按下 C-s C-s ,即可再次搜索相同的字符串。第一个 C-s 用于调用增量搜索功能,第二个 C-s 表示再次搜索上一次的搜索字符串。同理,连续按下 C-r C-r 会反向搜索上一次的搜索字符串。判定上一次的搜索字符串时,无论该字符串此前是通过 C-s 还是 C-r 搜索的,均无影响。
若你正在执行正向搜索,却发现目标内容出现在搜索起始位置之前,可按下 C-r 切换为反向搜索,且搜索字符串保持不变。同理,在反向搜索中按下 C-s ,即可切换为正向搜索。
默认情况下,当你切换搜索方向时,首次键入的方向切换命令会让光标停留在原匹配项上,仅移动至该匹配项的另一端。若希望切换方向后直接跳至其他匹配项,可将变量 isearch-repeat-on-direction-change 设为 t 。
若搜索已无匹配结果,你仍按下 C-s 尝试重复搜索,搜索会从 缓冲区起始位置 重新开始;若反向搜索已无匹配结果,按下 C-r 重复搜索,会从 缓冲区末尾位置 重新开始。这种行为被称为 wrapping around循环匹配 ,发生后搜索提示中会显示 “Wrapped”(已循环)。若你继续搜索并越过最初的搜索起始位置,提示会变为 “Overwrapped”(过度循环),表示你正在重新访问已经查看过的匹配项。
你可通过自定义用户选项 isearch-wrap-pause ,控制搜索无更多匹配项时的行为:
- 设为 t(默认值):触发错误提示(再次重复搜索会执行循环匹配);
- 设为 no:发出提示音,且在定位到最后一个匹配项后立即执行循环匹配;
- 设为 no-ding:不发出提示音,直接执行循环匹配; 当取值为 no 或 no-ding 时,键入字符时搜索也会尝试执行循环匹配;
- 设为 nil:永不执行循环匹配,仅在最后一个匹配项处停止搜索。
若要复用此前的搜索字符串,可使用 search ring搜索环 功能。按下 M-p (isearch-ring-retreat)和 M-n (isearch-ring-advance)(下翻搜索环)可遍历搜索环,选择要复用的搜索字符串。这两个命令会将选中的搜索环项显示在迷你缓冲区中,你可对其进行编辑,按下 C-s / C-r 或 RET 回车键即可确认该字符串并开始搜索。搜索环中可保存的最近使用的搜索字符串数量,由变量 search-ring-max 指定,默认值为 16。
若你希望在迷你缓冲区中编辑当前搜索字符串,且 不使用搜索环中的项替换 它,可按下 M-e (isearch-edit-string) ,或在迷你缓冲区中单击鼠标左键。编辑完成后,按下 RET 回车键、 C-s 或 C-r ,即可结束编辑并开始搜索该字符串;按下 C-f 或右方向键,可将搜索起始缓冲区中光标后方的字符添加至当前搜索字符串中。
17.1.3. 增量搜索中的粘贴(Isearch Yanking)
多数情况下,你会希望将光标所在位置或其附近的文本作为搜索字符串,本节介绍的命令可让你便捷地实现这一操作。
C-w (isearch-yank-word-or-char) 会将光标处的下一个字符或单词追加至搜索字符串中,这是查找光标处文本其他匹配项的简便方法(程序会通过启发式规则判断撷取单个字符还是整词)。带数字前缀参数 n 执行该命令,会追加后续 n 个字符或 n 个单词。
C-M-w (isearch-yank-symbol-or-char) 会将光标处的下一个字符或符号追加至搜索字符串中,适用于快速查找光标处符号的其他匹配项(程序会通过启发式规则判断撷取单个字符还是整符号)。带数字前缀参数 n 执行该命令,会追加后续 n 个字符或 n 个符号。
M-s C-e (isearch-yank-line) 会将当前行光标后的剩余内容追加至搜索字符串中;若光标已位于行尾,则追加下一行内容。带数字前缀参数 n 执行该命令,会追加后续 n 行内容。
类似地, C-M-z (isearch-yank-until-char) 会将从光标位置开始,到指定字符下一次出现位置前的所有内容追加至搜索字符串(不包含该指定字符)。该命令在键盘宏中尤为实用,例如在编程语言或标记语言中,可通过指定字符定位语法单元的边界。带数字前缀参数 n 执行该命令,会追加从光标位置到指定字符第 n 次出现位置前的所有内容。
在增量搜索过程中, C-y (isearch-yank-kill) 会将当前剪切板中的内容追加至搜索字符串。若在增量搜索中按下 C-y 后再执行 M-y (isearch-yank-pop) ,会用更早的剪切内容替换此前追加的文本,其作用与常规的 M-y (yank-pop) 命令一致。在回显区 mouse-2 单击鼠标右键,会将当前的 X 窗口选择文本追加至搜索字符串 (isearch-yank-x-selection) ,参见与其他窗口程序的剪切粘贴 。
C-M-d (isearch-del-char) 会删除搜索字符串的最后一个字符, C-M-y (isearch-yank-char) 会将光标后的单个字符追加至搜索字符串。也可通过其他方式添加光标后的字符:按下 M-e 进入迷你缓冲区(参见重复执行增量搜索),在迷你缓冲区的搜索字符串末尾按下 C-f 或 RIGHT 右方向键,每按一次都会将光标后的下一个字符追加至搜索字符串。
默认情况下,若搜索为不区分大小写模式,撷取并追加至搜索字符串的文本会被转换为小写,以保持搜索的大小写无关性(参见大小写折叠)。但如果变量 search-upper-case (参见 search-upper-case)的取值并非 not-yanks ,该小写转换行为会被禁用。
若要将光标附近的文本拉取为初始搜索字符串,启动新的增量搜索,可按下 M-s M-. ,该快捷键执行 isearch-forward-thing-at-point 命令。若区域处于激活状态,命令会将区域内的文本撷取为搜索字符串;若区域未激活,程序会尝试撷取光标附近的网址、符号或表达式。具体撷取的内容类型由用户选项 isearch-forward-thing-at-point 定义。
17.1.4. 增量搜索错误处理
若输入的搜索字符串完全无匹配结果,回显区会显示 “搜索失败(Failing I-Search)”,同时光标会移至 Emacs 能匹配到该字符串最长前缀的位置后方。例如,若你搜索 “FOOT” 但缓冲区中无该内容,光标可能会停在 “FOOL” 里的 “FOO” 后方。回显区中,搜索字符串里无匹配结果的部分,会使用 isearch-fail 文本外观高亮显示。
此时你可执行多种操作:若输入的搜索字符串存在拼写错误,可按 DEL 键撤销上一个输入项(参见增量搜索基础操作),按 C-M-d 键逐个删除字符,或按 M-e 键编辑搜索字符串;若你希望停留在当前匹配到的位置,按 RET 回车键即可;也可按 C-g 键,该操作会从搜索字符串中移除无匹配结果的字符(如 “FOOT” 中的 “T”),仅保留能匹配到的部分(如 “FOOT” 中的 “FOO”)。若此时再次按下 C-g 键,则会彻底取消本次搜索,将光标恢复至搜索启动时的位置。
退出命令 C-g 在搜索过程中会执行特殊操作,具体行为取决于当前的搜索状态:若搜索已匹配到指定内容并处于等待输入状态,按 C-g 键会直接彻底取消搜索,将光标移回搜索启动的初始位置;若按下 C-g 键时,搜索字符串中仍有未匹配到的字符 —— 无论 Emacs 仍在尝试搜索该部分,还是已确认搜索失败 —— 这些未匹配的字符都会从搜索字符串中被移除。移除后搜索会恢复为成功状态并等待后续输入,因此再次按下 C-g 键,才会彻底取消本次搜索。
17.1.5. 增量搜索的特殊输入
除前文介绍的字符外,在增量搜索过程中键入部分其他字符会触发特殊功能,本节将对其逐一说明。
按下 M-s SPC ,可切换宽松空格匹配的开启 / 关闭状态(参见宽松空格匹配)。
按下 M-c 或 M-s c ,可切换搜索的大小写敏感状态(参见大小写折叠)。若搜索字符串中包含大写字母,搜索默认会开启大小写敏感模式。
按下 M-s ' ,可切换搜索是否将相似且等效的字符判定为匹配项(参见字符折叠)。若搜索字符串中包含带重音的字符,本次搜索会自动禁用字符折叠功能。
按下 M-s i (isearch-toggle-invisible) ,可切换搜索是否查找由覆盖属性隐藏的文本(参见大纲模式中的搜索)。若希望所有增量搜索都能查找因文本属性或覆盖属性而隐藏的文本中的匹配项,可将变量 search-invisible 自定义为 t 。
按下 M-r 或 M-s r (isearch-toggle-regexp) ,可在普通增量搜索与正则表达式增量搜索间切换(参见正则表达式搜索)。
按下 M-s _ ,可切换符号模式的开启 / 关闭状态(参见符号搜索)。
若要搜索换行符,可在输入搜索字符串时按下 C-j 。
若要搜索非 ASCII 字符,可在增量搜索过程中使用以下任意一种方法:
- 按下
C-q(isearch-quote-char) ,随后键入非图形字符或一组八进制数字,即可将对应字符添加至搜索字符串,其用法与在缓冲区中使用C-q插入字符一致(参见插入文本)。例如,在增量搜索中按下C-q C-s,会将 'control-S' 控制字符 S 添加至搜索字符串。 使用输入法(参见输入法)。若启动搜索时当前缓冲区已启用某输入法,在输入搜索字符串时,迷你缓冲区会沿用该输入法。输入搜索字符串期间,可按下
C-\(isearch-toggle-input-method) 切换输入法状态;也可按下C-^(isearch-toggle-specified-input-method) ,根据提示选择并启用非默认输入法。当增量搜索中启用输入法时,搜索提示会显示该输入法的助记符,格式如下:I-search [im]:
其中的输入法助记符
im为当前激活输入法的标识。在增量搜索中启用的任意输入法,后续会一直保持在当前缓冲区的启用状态。此外,可按下C-x \(isearch-transient-input-method) 临时启用临时输入法(参见临时输入法),通过该输入法向搜索字符串中插入单个字符,插入完成后输入法会自动禁用。- 按下
C-x 8 RET(isearch-char-by-name) ,随后键入字符的 Unicode 名称或十六进制编码点,即可将指定字符添加至搜索字符串,其用法与常规的insert-char命令一致(参见插入文本)。
你也可在搜索字符串中包含表情符号序列:按下 C-x 8 e RET (isearch-emoji-by-name) ,随后键入表情符号的 Unicode 名称(例如 smiling face 微笑脸、 heart with arrow 带箭头的心形),即可将指定表情符号添加至搜索字符串。若不清楚目标表情符号的名称,可使用 C-x 8 e l (emoji-list) 和 C-x 8 e d (emoji-describe) 命令查询(参见输入法)。
在增量搜索中按下 M-s o ,会调用 isearch-occur 命令,该命令会以当前搜索字符串为检索条件执行 occur 命令(参见 occur 命令)。
在增量搜索中按下 M-% (isearch-query-replace) ,会调用查询替换或正则表达式查询替换命令(具体取决于当前搜索模式),并将当前搜索字符串设为待替换的目标字符串。若为该命令添加负的数字前缀参数,会执行反向替换(参见查询替换)。按下 C-M-% (isearch-query-replace-regexp) ,会调用正则表达式查询替换命令,并将当前搜索字符串设为待替换的正则表达式。
在增量搜索中按下 M-TAB ,会调用 isearch-complete 命令,该命令会以搜索环(你此前使用过的所有搜索字符串)为补全候选列表,尝试对当前搜索字符串进行补全(参见补全功能)。在许多操作系统中, M-TAB 快捷键会被窗口管理器拦截;若你需要使用该功能,需将 isearch-complete 命令重新绑定至其他快捷键(参见交互式修改按键绑定)。
按下 M-s h r (isearch-highlight-regexp) ,可退出搜索并保持匹配项的高亮状态。该命令会调用 highlight-regexp 命令(参见交互式高亮),将由当前搜索字符串转换而来的正则表达式作为检索条件,并提示你选择用于高亮的文本外观。若希望高亮包含匹配项的整行文本(而非仅高亮匹配项本身),可按下 M-s h l (isearch-highlight-lines-matching-regexp) 。无论使用上述哪种高亮方式,按下 M-s h u (unhighlight-regexp) 即可取消所有高亮效果。
当增量搜索处于激活状态时,按下 C-h C-h (isearch-help-map) 可打开交互式帮助选项,其中包含所有特殊快捷键的列表。这些快捷键均属于按键映射表 isearch-mode-map (参见按键映射表)。
当增量搜索处于激活状态时,按下 M-s M-> 会跳至搜索字符串的最后一个匹配项,按下 M-s M-< 会跳至搜索字符串的第一个匹配项。若为这两个命令添加数字前缀参数 n ,会分别从缓冲区起始位置和末尾位置开始计数,跳至搜索字符串的第 n 个匹配项。
17.1.6. 不退出增量搜索
本节介绍如何控制在键入 搜索中无特定含义 的命令时,是否先退出搜索再执行该命令;同时还将说明三类特殊命令,键入这类命令时无需退出当前增量搜索,尽管其本身并非增量搜索的内置命令。
默认情况下,若键入的命令未被增量搜索绑定相关功能,Emacs 会 先退出搜索,再执行该命令 ,因此该命令会作用于启动搜索的原缓冲区。但如果将变量 search-exit-option 自定义为 append ,增量搜索无法解析的键入字符会直接 追加至搜索字符串中 。借助该设置,你可将 C-a 等控制字符纳入搜索字符串 —— 这类字符在默认情况下会触发退出搜索,并在缓冲区中执行其绑定的命令。
- 前缀参数
在增量搜索中,当你键入用于指定数字前缀参数的命令时(参见数字参数),该参数默认会作用于搜索的下一个操作,或退出搜索后执行的命令。换言之,输入前缀参数本身不会终止增量搜索。
在早期的 Emacs 版本中,输入前缀参数总会终止搜索。若要恢复该旧版行为,可将变量
isearch-allow-prefix设为nil。当
isearch-allow-scroll为非 nil 值时(见下文),无论isearch-allow-prefix是否为nil,前缀参数均会遵循上述默认行为,即不会终止搜索。- 滚动命令
默认情况下,执行滚动命令会退出增量搜索。但如果将变量
isearch-allow-scroll设为非 nil 值,即可在不退出搜索的前提下,使用滚动条,以及C-v、M-v、C-l等键盘滚动命令(参见滚动)—— 这类命令的scroll-command属性均为非 nil。该特性仅适用于通过 绑定的快捷键 调用这些命令,键入M-x仍会触发退出搜索。你可按常规方式为这些滚动命令添加前缀参数。该特性默认会防止当前匹配项被滚动至视野外;若将
isearch-allow-scroll自定义为特殊值unlimited,则会取消该限制。isearch-allow-scroll特性还会作用于其他部分命令,例如C-x 2(split-window-below) 和C-x ^(enlarge-window)(放大窗口)—— 这类命令并非严格意义上的滚动命令,但会影响文本在屏幕上的显示位置。事实上,所有isearch-scroll属性为非 nil 的命令,都会受该特性影响。因此,你可通过修改这些命令的属性,控制其是否被该特性作用。例如,若希望在后续所有 Emacs 会话的增量搜索中,均可使用
C-h l命令,可先通过C-h c查询该快捷键绑定的命令(参见按键的文档说明),即view-lossage;随后在初始化文件中添加以下配置行(参见Emacs 初始化文件):(put 'view-lossage 'isearch-scroll t)
该特性可应用于所有不会永久修改以下内容的命令:光标位置、缓冲区内容、匹配数据、当前缓冲区,以及选中的窗口和框架。且该命令本身不能尝试执行增量搜索。当
isearch-allow-scroll为nil时(默认值),该特性会被禁用。同理,若将变量
isearch-allow-motion设为非 nil 值,即可在不退出搜索的前提下,使用M-<、M->、C-v、M-v等键盘移动命令,分别跳至缓冲区中当前搜索字符串的第一个匹配项、最后一个匹配项、当前窗口后方的第一个匹配项和当前窗口前方的最后一个匹配项。执行这些移动命令时,搜索方向默认不会改变;若将变量
isearch-motion-changes-direction设为非 nil 值,则会改变搜索方向:执行M-<和C-v后搜索方向为正向,执行M->和M-v后搜索方向为反向。- 移动命令
若将
isearch-yank-on-move自定义为shift,你可在按住shift键的同时键入光标移动命令,以此扩展搜索字符串。该操作会将当前缓冲区中,光标移动后新位置之前的文本撷取并追加至搜索字符串。若将
isearch-yank-on-move设为t,无需按住Shift键,键入光标移动命令即可扩展搜索字符串;但该效果仅适用于符号上带有isearch-move属性的特定移动命令。
17.1.7. 迷你缓冲区搜索
若在迷你缓冲区处于激活状态时启动增量搜索,Emacs 会对迷你缓冲区的内容进行检索。与搜索普通缓冲区不同,搜索字符串不会显示在回显区中,因为该区域会被用于显示迷你缓冲区本身的内容。
若在迷你缓冲区中执行增量搜索未找到匹配结果,Emacs 会尝试 检索迷你缓冲区的历史记录 (参见迷你缓冲区历史记录)。你可将迷你缓冲区及其历史记录视作一系列连续的页面:最早的历史记录项位于第一页,当前的迷你缓冲区内容则在最后一页。正向搜索( C-s )会向后检索后续页面的内容,反向搜索( C-r )则会向前检索更早页面的内容。与搜索普通缓冲区的规则一致,无匹配结果的搜索会执行循环检索,从最后一页跳转至第一页,或从第一页跳转至最后一页。
当当前匹配项出现在某条历史记录项中时,该历史记录项会被调取至迷你缓冲区中。若你以常规方式退出增量搜索(例如按下 RET 回车键),该历史记录项会保留在迷你缓冲区中;若通过按下 C-g 取消搜索,迷你缓冲区的内容会恢复为启动搜索时的状态。
17.2. 非增量搜索(Nonincremental Search)
Emacs 也提供常规的非增量搜索命令,这类命令要求你在搜索开始前输入 完整的搜索字符串 。
C-s RET string RET- 搜索指定字符串。
C-r RET string RET- 反向搜索指定字符串。
启动非增量搜索时,先按下 C-s RET ,此时会调出迷你缓冲区用于输入搜索字符串;输入完成后按 RET 回车键确认,搜索随即执行。若未找到该字符串,搜索命令会触发错误提示。
按下 C-s RET 时, C-s 会照常调用增量搜索功能,而该功能被专门设定为:当你输入的搜索字符串为空时,自动调用非增量搜索命令(空参在增量搜索中并无实际作用)。 C-r RET 的执行逻辑同理,会调用反向非增量搜索命令。
非增量搜索也可通过菜单栏的 'Edit->Search' 菜单调用。
你也可使用两个更简洁的命令: M-x search-forward (正向搜索)和 M-x search-backward (反向搜索)。这两个命令仅对指定的字面字符串进行检索,除了大小写折叠外,不支持任何宽松搜索相关特性(参见搜索中的宽松匹配)。
17.3. 单词搜索(Word Search)
ward search单词搜索 会查找连续的单词序列,且忽略单词之间的标点符号类型。例如,若你输入的搜索字符串是由单个空格分隔的两个单词,该搜索会匹配这两个单词以一个或多个空格、换行符或其他标点符号分隔的任意序列。此功能在搜索文本文档时尤为实用,你无需担心目标单词之间是用换行符还是空格分隔。需注意,编程语言对应的主模式或其他专用模式可修改单词的定义,以适配其语法需求。
M-s w- 若增量搜索已激活,切换单词搜索模式 (
isearch-toggle-word);若未激活,启动正向增量单词搜索 (isearch-forward-word) 。 M-s w RET words RET- 执行正向非增量单词搜索,查找指定单词序列。
M-s w C-r RET words RET- 执行反向非增量单词搜索,查找指定单词序列。
M-s M-w- 在网络上搜索选区中的文本内容。
启动正向增量单词搜索,按下 M-s w 即可。若增量搜索尚未激活,该快捷键会执行 isearch-forward-word 命令;若增量搜索已激活(无论正向还是反向), M-s w 会执行 isearch-toggle-word 命令,切换为单词搜索模式,且保持搜索方向和当前搜索字符串不变。再次按下 M-s w ,可关闭单词搜索模式。
启动非增量单词搜索,按下 M-s w RET 执行正向搜索,按下 M-s w C-r RET 执行反向搜索,二者分别对应 word-search-forward 和 word-search-backward 命令。
增量单词搜索与非增量单词搜索的匹配规则略有不同:非增量单词搜索中,搜索字符串中的每个单词都必须与完整的单词精确匹配;增量单词搜索的匹配规则则更为宽松,在你输入搜索字符串的过程中,其首个和最后一个单词无需匹配完整单词,目的是让匹配过程能随你的输入实时增量进行。这一额外的宽松规则不适用于延迟高亮功能(参见增量搜索),该功能始终会匹配完整的单词。输入搜索字符串时,搜索提示中会显示 “待匹配(Pending)”,直至你按下 C-s 等重复搜索的快捷键。
单词搜索命令不执行字符折叠,切换宽松空格匹配模式(参见宽松空格匹配)对其也无任何效果。
在网络上搜索选区中的文本,按下 M-s M-w 即可。该命令会通过互联网搜索选区中的单词,使用的搜索引擎地址由变量 eww-search-prefix 指定(参见《Emacs 网页浏览器手册》中的 EWW 相关内容)。若选区未激活,或选区中无任何单词,该命令会提示用户输入待搜索的网址或关键词。
你也可通过 RFC 2229 定义的 DICT 协议查询词典服务器,查找单词的释义。Emacs 内置了该协议的客户端,按下 M-x dictionary-search RET ,即可连接至 DICT 词典服务器,查询指定单词的所有可用释义。该命令会提示用户输入待查询单词,默认使用光标所在位置的单词,随后请求词典服务器在一个或多个词典中返回该单词的释义。默认情况下,该命令会先尝试连接本地主机上的 DICT 词典服务器,若连接失败,经用户确认后会尝试连接 dict.org 服务器;可自定义变量 dictionary-server ,将其设为字符串类型的服务器地址,指定唯一使用的词典服务器(若仅需查询本地服务器,设为 “localhost” 即可)。通常, dictionary-search 命令会让服务器在其所有可用词典中检索单词,若为该命令添加数字前缀参数,其会提示用户指定单个词典进行检索。服务器的所有可用词典列表,可通过下方所述的 *Dictionary* 缓冲区中显示的「选择词典(Select dictionary)」按钮查看。
首次使用 dictionary-search 命令时,Emacs 会新建一个 *Dictionary* 缓冲区,并在其中启用专用模式。该缓冲区提供了选择词典、搜索其他单词释义等功能按钮,后续执行的 dictionary-search 命令会复用此缓冲区。若需新建一个同类缓冲区(例如在另一本词典中查询其他单词),按下 M-x dictionary RET 即可。
若在某一缓冲区中启用 dictionary-tooltip-mode 模式,Emacs 会自动查询鼠标指针所在位置单词的释义,并在工具提示中显示。当你阅读包含大量陌生单词的文本时,该功能会非常实用。
关于 dictionary-search 命令的其他配置选项,参见词典自定义组(参见自定义特定项)。
17.4. 符号搜索(Symbol Search)
symbol search符号搜索 与普通搜索极为相似,区别在于 搜索内容的边界必须与符号的边界相匹配 。此处的「symbol符号」含义由主模式决定,通常指源代码中的语法标记,例如 Emacs Lisp 模式中的 Lisp 符号。举例来说,若对 Lisp 符号 forward-word 执行增量符号搜索,该搜索不会匹配 isearch-forward-word 。因此,该功能主要适用于搜索源代码。
M-s _- 若增量搜索已激活,切换符号搜索模式 (
isearch-toggle-symbol) ;若未激活,启动正向增量符号搜 (isearch-forward-symbol) 。 M-s .- 启动正向增量符号搜索,且会将光标附近找到的符号预先加入搜索字符串。
M-s _ RET symbol RET- 执行正向非增量符号搜索,查找指定符号。
M-s _ C-r RET symbol RET- 执行反向非增量符号搜索,查找指定符号。
启动正向增量符号搜索,按下 M-s _ 即可(若待搜索符号就在光标附近,也可按下 M-s . )。若增量搜索尚未激活, M-s _ 会执行 isearch-forward-symbol 命令, M-s . 会执行 isearch-forward-symbol-at-point 命令。为 M-s . 添加数字前缀参数 n 时,该命令会查找光标处符号的第 n 个后续匹配项;若 n 为负值,则执行反向搜索。若增量搜索已激活,按下 M-s _ 会切换至符号搜索模式,同时保留原有的搜索方向和当前搜索字符串;再次按下 M-s _ ,即可关闭符号搜索模式。在增量符号搜索中,输入搜索字符串的过程中, 仅要求搜索字符串的开头与符号的开头相匹配 ,且搜索提示中会显示「待匹配(Pending)」,直至按下 C-s 等重复搜索的快捷键。
启动非增量符号搜索,按下 M-s _ RET 执行正向搜索,按下 M-s _ C-r RET 执行反向搜索。在非增量符号搜索中, 要求搜索字符串的开头与结尾分别与符号的开头和结尾严格匹配 。
符号搜索命令不执行字符折叠,切换宽松空格匹配模式(参见宽松空格匹配)对其也无任何效果。
17.5. 正则表达式搜索(Regular Expression Search)
regular expression 正则表达式(简称regexp)是一种匹配模式,可匹配一类符合规则的备选字符串。Emacs 同时提供了增量和非增量两种正则表达式搜索方式,正则表达式的语法将在下一节中讲解。
C-M-s- 启动正向增量正则表达式搜索 (
isearch-forward-regexp) 。 C-M-r- 启动反向增量正则表达式搜索 (
isearch-backward-regexp)。
启动正向增量正则表达式搜索可按下 C-M-s ,也可给 C-s 添加任意数值的前缀参数后执行,或在正向增量搜索中键入 M-r 切换。该命令与 C-s 的操作方式一致,会增量式读取输入的搜索字符串,但不会将其作为固定字符串去精确匹配缓冲区文本,而是将其视作正则表达式进行匹配。每向搜索字符串中添加字符,正则表达式就会相应延长,Emacs 也会用新的正则表达式重新执行搜索。执行反向增量正则表达式搜索,可按下 C-M-r 、给 C-r 添加前缀参数执行,或在反向增量搜索中键入 M-r 切换。
普通增量搜索中的所有特殊快捷键(参见增量搜索的特殊输入),在增量正则表达式搜索中均有类似功能。例如,启动搜索后立即按下 C-s ,会调取上一次使用的增量正则表达式搜索串并执行正向搜索。增量正则表达式搜索和普通增量搜索拥有相互独立的默认搜索串,且各自配有独立的搜索环,均可通过 M-p 和 M-n 进行遍历。搜索环中可保存的正则表达式最大数量由变量 regexp-search-ring-max 指定,默认值为 16。
与普通增量搜索不同,增量正则表达式搜索 默认不启用lax space宽松空格匹配 ,可按下 M-s SPC (isearch-toggle-lax-whitespace) 切换该功能。启用后,在增量正则表达式搜索中键入的任意空格,均可匹配一个或多个空白字符组成的任意序列。变量 search-whitespace-regexp 用于指定宽松空格匹配所使用的正则表达式,详情参见增量搜索的特殊输入。
此外,增量正则表达式搜索 不支持字符折叠功能 (参见搜索中的宽松匹配)。若在增量正则表达式搜索中按下 M-s ' 尝试切换字符折叠,搜索会自动转为普通字符串搜索,此前输入的匹配模式也会被当作字面量字符串解析。
在某些情况下,为增量正则表达式搜索的匹配串添加字符,可能会导致光标回退并重新执行搜索。例如,当你已搜索过 'foo' ,再为其添加 '\|bar' 后,光标会回退重新检索 —— 这是为了匹配出现在首个foo之前的首个bar(此时搜索提示会显示「待匹配(Pending)」,告知用户程序正在重新计算匹配结果),相关语法详情参见正则表达式语法。
正向和反向正则表达式搜索并非对称操作,因为 Emacs 中的正则表达式匹配始终 正向执行 ,从正则表达式的起始位置开始匹配。因此,正向正则表达式搜索会正向扫描文本,在每个可能的起始位置尝试正向匹配;反向正则表达式搜索会反向扫描文本,但同样在每个可能的起始位置执行正向匹配,这两种搜索方式并非镜像关系。
非增量正则表达式搜索可通过 re-search-forward 和 re-search-backward 命令实现,可通过 M-x 直接调用,也可在增量正则表达式搜索中按下 C-M-s RET 或 C-M-r RET 触发。通过 M-x 直接调用这两个命令时,程序会严格按照你指定的正则表达式执行搜索,因此除大小写折叠外,不支持任何宽松搜索特性(参见搜索中的宽松匹配)。
若为增量正则表达式搜索命令添加前缀参数执行,该命令会切换为普通字符串搜索,功能与 isearch-forward 和 isearch-backward 一致,详情参见增量搜索。
17.6. 正则表达式语法
本节(以及本手册整体)介绍的是用户日常使用的正则表达式特性。更多主要用于 Lisp 程序的扩展特性,参见《Emacs Lisp 参考手册》中的正则表达式相关章节。
正则表达式拥有专属语法:其中少量字符为 special constructs特殊构造符 ,其余均为 ordinary普通字符 。普通字符仅匹配其自身,无其他匹配效果。特殊字符包括 '$^.*+?[\' 仅在作为方括号表达式的结束符 ']' 时具有特殊性(见下文); '-' 仅在方括号表达式内具有特殊性。正则表达式中出现的其他所有字符均为普通字符,除非其前带有反斜杠 '\' 转义(在 Lisp 程序中使用正则表达式时,每个 '\' 都必须写为双反斜杠 '\\' ,参见本节末尾示例)。
例如, 'f'并非特殊字符,因此属于普通字符,正则表达式 'f' 仅匹配字符串 'f' ,不匹配其他任何字符串(也不匹配 'ff')。同理, 'o' 作为正则表达式仅匹配 'o'。(当忽略大小写匹配时,这些正则表达式也会匹配 'F' 和 'O' ,我们将此视为「匹配相同字符串」的扩展规则,而非例外情况。)
任意两个正则表达式 a 和 b 均可进行 拼接 ,拼接后的正则表达式匹配规则为:若字符串的开头部分能匹配 a ,剩余部分能匹配 b ,则该字符串可被拼接后的正则表达式匹配。一个简单的例子是,将 'f' 和 'o' 拼接得到正则表达式 'fo',其仅匹配字符串 'fo' 。若要实现更复杂的匹配效果,就需要使用特殊字符。以下是所有正则表达式特殊字符的说明:
.(句点)- 特殊字符,匹配除换行符外的任意单个字符。例如,正则表达式 ‘a.b’ 匹配以 ‘a’ 开头、以 ‘b’ 结尾的任意三字符字符串。
*本身并非独立构造符,而是后缀操作符,表示将其前面的正则表达式重复匹配任意次数(包括 0 次),且遵循 贪婪匹配原则 (尽可能多匹配)。因此, ‘o*’ 匹配任意数量的 ‘o’,也包括空字符串。
*始终作用于其前方最小的有效正则表达式。因此, ‘fo*’ 表示 ‘o’ 可重复匹配,而非 ‘fo’整体,该表达式可匹配f、fo、foo等字符串。正则表达式匹配器处理
*构造符的逻辑为:首先尽可能多地匹配 ‘*’ 修饰的表达式,再继续匹配模式的剩余部分;若剩余部分匹配失败,则进行 回溯 ,舍弃部分 ’*‘ 的匹配结果,直至模式剩余部分能成功匹配。例如,用 ‘ca*ar’ 匹配字符串 ‘caaar’ 时, ‘a*’ 最初会匹配全部 3 个 ‘a’ ,但模式剩余部分为 ‘ar’ ,而字符串中仅剩 ‘r’ ,因此此次匹配失败;随后进行回溯, ‘a*’ 仅匹配 2 个 ‘a’,此时正则表达式的剩余部分可成功匹配,整体匹配完成。+- 后缀操作符,与 ‘*’ 类似,但要求其前方的表达式至少匹配 1 次。因此, ‘ca+r’ 可匹配 ‘car’ 、 ‘caaaar’,但不匹配 ‘cr’ ;而 ‘ca*r’ 可匹配上述三个字符串。
?- 后缀操作符,与 ‘*’ 类似,但其前方的表达式匹配 0 次或 1 次,二者择一。因此, ‘ca?r’ 仅匹配 ‘car’ 或 ‘cr’ ,无其他匹配结果。
*?、+?、??上述操作符的 non-greedy非贪婪匹配 变体。默认的 ‘*’ 、 ‘+’ 、‘?’ 为贪婪匹配,即在保证整个正则表达式能匹配的前提下,尽可能多匹配字符;后缀添加 ‘?’ 后,变为非贪婪匹配,即在保证整个正则表达式能匹配的前提下, 尽可能少匹配字符 。
例如, ‘ab*’ 和 ‘ab*?’ 均可匹配字符串 ‘a’ 和 ‘abbbb’ ;但用二者匹配文本 ‘abbb’ 时, ‘ab*’ 会匹配整个字符串( 贪婪匹配,最长有效匹配 ),而 ‘ab*?’ 仅匹配 ‘a’ ( 非贪婪匹配,最短有效匹配 )。
非贪婪操作符会在指定起始位置匹配 最短的有效字符串 ;但在正向搜索中,始终会选择 最早出现的有效起始位置 进行匹配。例如,用 ‘a.*?$’ 匹配文本 ‘abbab’ (后接换行符)时,该表达式会匹配整个字符串 —— 因为从第一个 ‘a’ 开始即可完成匹配,匹配器会优先选择该起始位置。
[…]也称作 bracket expression备选字符集,匹配集合中的任意单个字符。
最简单的情况是,方括号之间的所有字符即为该集合的匹配范围。例如, ‘[ad]’ 匹配单个 ‘a’ 或单个 ‘d’; ‘[ad]*’ 匹配由任意数量a和d组成的字符串(包括空字符串)。由此可得, ‘c[ad]*r’ 可匹配 ‘cr’ 、‘car’ 、 ‘cdr’ 、 ‘caddaar’ 等字符串。
在字符集中,可通过 连字符 ‘-’ 连接起始和结束字符,表示字符范围 。例如, ‘[a-z]’ 匹配任意小写 ASCII 字母;字符范围可与单个字符自由混合,如 ‘[a-z\(%.]’ 匹配任意小写 ASCII 字母,或 ‘\)’ 、 ‘%’ 、 ‘.’ 。再如, ‘[α-ωί]’ 匹配所有小写希腊字母。
字符集中还可包含 special character classes特殊字符类 ,以 ‘[:’ 开头、 ‘:]’ 结尾的内容即为字符类,嵌在方括号表达式内使用。例如,
[[:alnum:]]匹配任意字母或数字。字符类的完整列表参见《Emacs Lisp 参考手册》中的字符类相关章节。若要在字符集中包含 ‘]’ ,必须将其设为 第一个字符 ,例如 ‘[]a]’ 匹配 ‘]’ 或 ‘a’ ;若要包含 ‘-’ ,可将其设为字符集的 最后一个字符 ,也可放在开头或字符范围之后,例如 ‘[]-]’ 匹配 ‘]’ 和 ‘-’ 。
若要在字符集中包含 ‘^’ ,可将其放在 除开头外的任意位置 (在开头时,字符集会变为补集 —— 见下文)。
在 忽略大小写 的搜索中使用字符范围时,范围的首尾字符需统一大小写(均大写、均小写),或均为非字母字符。 ‘A-z’ 这类混合大小写的字符范围,其匹配行为未被明确定义,且在未来的 Emacs 版本中可能发生变化。
[^ …]以 ‘[^’ 开头的方括号表达式为 complemented character set补集字符集 ,匹配 除指定字符外的任意单个字符 。例如, ‘
[^a-z0-9A-Z]’ 匹配所有非 ASCII 字母和数字的字符。‘^’ 仅在字符集开头时具有特殊性,其余位置均为普通字符; ‘^’ 后的第一个字符,其 ‘-’ 和 ‘]’ 均无特殊性(即无需转义即可直接表示自身)。
补集字符集 可以匹配换行符 ,除非将换行符明确列入不匹配的字符中。这一点与
grep等程序中的正则表达式处理逻辑不同。^特殊字符,匹配空字符串,但 仅在被匹配文本的行首生效 ,其余位置均匹配失败。因此, ‘
^foo’ 仅匹配出现在行首的 ‘foo’ 。出于历史兼容性考虑, ‘^’ 仅在 正则表达式的开头 ,或 ‘\(’ 、‘\|’ 之后使用时,才具有行首匹配的含义。
$其用法与脱字符 ‘^’ 类似,但仅在行尾位置完成匹配。例如,正则表达式 ‘x+$’ 可匹配行尾由一个或多个 ‘x’ 组成的字符串。
出于历史兼容性考量, ‘$’ 仅在正则表达式的末尾,或在 ‘\)’ 、 ‘\|’ 之前使用时,才具备上述行尾匹配的含义。
\拥有两个功能:转义特殊字符(包括自身 ‘\’ ),以及引入扩展的特殊构造符。
由于 ‘\’ 的转义作用, '
\$' 作为正则表达式仅匹配 '$' , ‘\[’ 仅匹配 ‘[’ ,依此类推。以 ‘\’ 开头的扩展特殊构造符,参见下一节内容。
注意:出于历史兼容性,若特殊字符出现在 其特殊含义无意义的上下文 中,会被当作普通字符处理。例如, ‘*foo’ 中的 ‘*’ 会被视为普通字符,因为其前方无任何可被修饰的表达式。不建议依赖此行为编写正则表达式,无论特殊字符出现在何处,都建议通过转义明确其普通字符的含义。
’\‘ 反斜杠在方括号表达式内无特殊性 ,因此无法取消 ‘-’ 、 ‘^’ 、 ‘]’ 的特殊含义。当这些字符无特殊含义时,无需为其添加反斜杠——这一操作无任何实际意义;而当它们具有特殊含义时,反斜杠可合法地加在其前方,例如 ‘[^\]’ (在 Lisp 字符串语法中需写为 "[^\\]"),该表达式匹配除反斜杠外的任意单个字符。
17.7. 正则表达式中的反斜杠
在绝大多数情况下,反斜杠 '\' 后接任意字符,仅会匹配该字符本身。但存在若干例外情况:以 '\' 开头的双字符序列拥有特殊含义,而该序列的第二个字符单独使用时,始终为普通字符。以下是所有以 '\' 构成的特殊构造符说明:
\|表示匹配备选项。在两个正则表达式
a和b之间加入 '\|' ,构成的新表达式可匹配任意能被a或b匹配的文本。其匹配逻辑为:先尝试用a匹配,若匹配失败,再尝试用b匹配。例如, '
foo\|bar' 仅匹配 'foo' 或 'bar' ,不匹配其他任何字符串。'
\|' 的作用范围为 其两侧最大的有效正则表达式 ,仅能通过圆括号组 '\( … \)' 限定其作用范围。正则表达式的完整回溯机制可处理 '
\|' 的多次嵌套使用场景。\( … \)表示分组构造符,主要有三项作用:
- 为其他操作符包裹一组由 '
\|' 分隔的备选项。例如, '\(foo\|bar\)x' 可匹配 'foox' 或 'barx' ; - 为后缀操作符 '
*' 、 '+' 、 '?' 包裹复杂的表达式,使其成为操作符的作用对象。例如, 'ba\(na\)*' 可匹配 'banana' 、 'bananana' 等包含任意数量(0 个及以上) 'na' 的字符串; - 记录匹配到的子串,供后续引用使用。
上述第三项作用并非括号分组的固有属性,而是为同一 '
\( … \)' 构造符赋予的另一重独立功能。实际使用中,这两种含义通常不会产生冲突;若出现冲突,可使用下文介绍的匿名分组解决。- 为其他操作符包裹一组由 '
\(?: … \)- 表示 shy group匿名分组 ,该分组不会记录匹配到的子串,也无法通过后文的 '
\d' 语法引用(见下文)。此构造符在正则表达式的机械拼接场景中十分实用,可仅为语法需求添加分组,而不会干扰需要被引用的分组的编号顺序。 \d表示反向引用,匹配第
d个 '\( … \)' 分组此前匹配到的完全相同的文本。当 '
\( … \)' 分组完成匹配后,正则表达式匹配器会记录该分组匹配到的文本的起始和结束位置。在正则表达式的后续位置,使用 '\' 后接数字d,即可表示「匹配第d个 '\( … \)' 分组匹配到的文本」。正则表达式中出现的前 9 个 '
\( … \)' 分组,会按照左括号在表达式中出现的先后顺序,被依次分配编号1至9。因此,可使用 '\1' 至 '\9' 引用对应分组匹配到的文本。例如, '
\(.*\)\1' 可匹配任意无换行符、且由两个完全相同的子串拼接而成的字符串。其中 '\(.*\)' 会匹配前半部分(可为任意内容),而后续的 '\1' 则必须匹配与前半部分完全一致的文本。若某个 '
\( … \)' 分组因后接 '*' 等操作符而完成多次匹配,匹配器 仅会记录最后一次的匹配结果 。\{m\}- 作为后缀操作符,表示 精确匹配 m 次 ,即其前方的正则表达式必须连续匹配恰好
m次。例如, 'x\{4\}'仅匹配字符串 'xxxx' ,不匹配其他任何内容。 \{m,n\}- 作为后缀操作符,表示 匹配 m 至 n 次 ,即其前方的正则表达式必须连续匹配至少
m次、至多n次。若省略n,则表示无上限,仅要求前方表达式匹配至少m次。- '
\{0,1\}' 与 '?' 等价; - '
\{0,\}' 与 '*' 等价; - '
\{1,\}' 与 '+' 等价。
- '
\`- 匹配空字符串,且仅在被匹配的字符串 或 缓冲区(或其可访问部分)的起始位置生效。
\'- 匹配空字符串,且仅在被匹配的字符串 或 缓冲区(或其可访问部分)的结束位置生效。
\=- 匹配空字符串,且仅在当前光标位置生效。
\b表示 单词边界 ,匹配空字符串,且仅在单词的起始或结束位置生效。因此, '
\bfoo\b' 可匹配作为独立单词出现的 'foo' , '\bballs?\b' 可匹配作为独立单词出现的 'ball' 或 'balls' 。无论缓冲区首尾的相邻字符为何, '
\b' 均可在缓冲区的起始和结束位置匹配。\B- 匹配空字符串,且仅在非单词边界的位置生效(与 '
\b' 含义相反)。 \<- 匹配空字符串,且仅在单词的起始位置生效。仅当缓冲区起始位置后接单词构成字符时, '
\<' 才可在该位置匹配。 \>- 匹配空字符串,且仅在单词的结束位置生效。仅当缓冲区的内容以单词构成字符结尾时, '
\>' 才可在缓冲区结束位置匹配。 \w- 匹配任意单词构成字符,具体的字符范围由 Emacs 的语法表定义,参见《Emacs Lisp 参考手册》中的《语法表》相关章节。
\W- 匹配任意非单词构成字符(与 '
\w' 含义相反)。 \_<- 表示符号边界,匹配空字符串,且仅在符号的起始位置生效。符号指由一个或多个符号构成字符组成的序列,而符号构成字符指语法类型为 '
w' (单词)或 '_' (下划线)的字符。仅当缓冲区起始位置后接符号构成字符时, '\_<' 才可在该位置匹配。与单词规则一致,符号构成字符的范围也由语法表定义。 \_>- 匹配空字符串,且仅在符号的结束位置生效。仅当缓冲区的内容以符号构成字符结尾时, '
\_>' 才可在缓冲区结束位置匹配。 \sc- 匹配任意语法类型为
c的字符。其中c为指定语法类别的标识字符,例如 'w' 代表单词构成字符、 '-' 或 ' ' 代表空白字符、 '.' 代表普通标点字符等。语法类别的完整列表参见《Emacs Lisp 参考手册》中的《语法类代表格》。 \Sc- 匹配任意语法类型非
c的字符(与 '\sc' 含义相反)。 \cc- 匹配任意属于类别
c的字符。例如, '\cc' 匹配中文字符、 '\cg' 匹配希腊字符等。若要查看所有已定义的字符类别,可执行命令M-x describe-categories RET。 \Cc- 匹配任意不属于类别
c的字符(与 '\cc' 含义相反)。
所有与单词、语法相关的构造符,其行为均由语法表的配置决定,参见《Emacs Lisp 参考手册》中的语法表相关章节。
17.8. 正则表达式示例
以下为一个正则表达式示例 —— 该表达式与 Emacs 默认用于识别句子结尾(不含后续空格)的正则表达式类似,对应变量为 sentence-end-base :
[.?!][]\"')}]*
该表达式由两个连续的部分构成:第一部分是匹配句点、'?' 问号或 '!' 感叹号的字符集,第二部分是匹配 ']' 右括号、引号或 ')' 圆括号、'}'大括号的字符集,且第二部分可匹配零次或多次。
17.9. 搜索中的宽松匹配(Lax Matching During Searching)
通常情况下,你会希望搜索命令忽略输入的搜索字符串与待搜索文本之间的某些细微差异。例如,不同长度的空白字符序列通常被视为等效;字母的大小写差异通常不影响匹配,这类规则被称为 character equivalence字符等效性 。
本节将介绍 Emacs 的 lax search 宽松搜索 特性,以及如何根据自身需求对其进行定制。
默认情况下,搜索命令会执行 lax space matching宽松空格匹配 :搜索字符串中的单个空格或连续空格序列,可匹配文本中任意一个或多个空白字符组成的序列。更准确地说,Emacs 会将搜索字符串中的每段空格序列,匹配为用户选项 search-whitespace-regexp 所指定的正则表达式。该选项的默认值将任意空格和制表符序列视为空白字符,因此搜索字符串 'foo bar' 可匹配文本中的 'foo bar' 、'foo bar'、'foo bar' 等形式(但不匹配 'foobar')。若你希望让空格同时匹配换行符、空格和制表符组成的序列,可自定义该选项,将其值设为正则表达式 '[ \t\n]+' (增量正则表达式搜索的默认行为与此不同,参见正则表达式搜索章节)。
若你需要让空白字符 精确匹配 ,可在增量搜索过程中按下 M-s SPC (isearch-toggle-lax-whitespace) 关闭宽松空格匹配,再次按下该快捷键则可重新开启。若要对所有搜索禁用宽松空格匹配,可将 search-whitespace-regexp 设为 nil ,此时搜索字符串中的每个空格将仅匹配文本中的单个空格。
在 Emacs 中,若你输入的搜索字符串均为小写字母,搜索命令默认 会忽略待搜索文本的大小写 。例如,搜索 'foo' 时,文本中的 'Foo' 和 'fOO' 也会被匹配。正则表达式(尤其是字符集)的匹配规则同理, '[ab]' 会匹配'a' 、 'A' 、 'b' 、 'B' 。该特性被称为 case folding大小写折叠 ,增量搜索和非增量搜索模式均支持此特性。
若搜索字符串中 任意位置包含大写字母 ,则搜索会变为 大小写敏感 模式。例如,搜索 'Foo' 时,不会匹配文本中的 'foo' 或 'FOO' 。该规则同时适用于正则表达式搜索和字面字符串搜索,若将搜索字符串中的大写字母删除,大小写敏感的效果也会随之消失。变量 search-upper-case 用于控制该特性:若其值为非nil,搜索字符串中的大写字母会触发大小写敏感搜索;若设为 nil ,则会禁用大写字母的该作用。该变量的默认值为 not-yanks ,此配置下,若搜索字符串包含大写字母则开启大小写敏感,同时会将撷取到搜索字符串中的文本(参见增量搜索中的文本撷取)转换为小写,使这类搜索默认保持大小写不敏感。
若将变量 case-fold-search 设为 nil ,则所有字符 必须完全精确匹配 (包括大小写)。该变量为缓冲区局部变量,修改其值通常仅对当前缓冲区生效,除非你更改其默认值(参见局部变量章节)。该变量同样适用于非增量搜索,包括替换命令(参见替换命令章节)和迷你缓冲区历史记录匹配命令(参见迷你缓冲区历史记录章节)执行的搜索。
在增量搜索过程中,按下 M-c 或 M-s c (isearch-toggle-case-fold) 可切换本次搜索的大小写敏感状态。该切换效果仅对当前增量搜索有效,但会覆盖因在当前搜索字符串中添加或删除大写字母而产生的大小写匹配规则。
另有多个相关变量用于控制特定命令或操作的搜索与匹配大小写敏感性,例如 tags-case-fold-search 控制 find-tag 命令的大小写敏感性。若要查找这类变量,可执行 M-x apropos-variable RET case-fold-search RET 。
大小写折叠会忽略字符间的大小写差异,使大写字符与对应小写字符相互匹配。 character folding字符折叠 是大小写折叠的扩展特性,它会忽略相似字符之间更广泛的差异。例如,开启字符折叠后,字母 a 会匹配其所有带重音的变体(如 ä 和 á ),即匹配时会忽略区分这些变体的变音符号;此外, a 还会匹配其他外形相似、或在图形表示中包含 a 的字符,如 Unicode 字符 U+00AA(阴性序数指示符)和 U+24D0(圆形小写字母 a)。同理,ASCII 双引号 " 会匹配 Unicode 标准中定义的所有双引号变体。字符折叠甚至可让一个或多个字符组成的序列,匹配另一个不同长度的字符序列,例如双字符序列 ff 会匹配 Unicode 字符 U+FB00(拉丁文连字小写 ff),序列 (a) 会匹配 U+249C(带圆括号的拉丁文小写字母 a)。那些并非完全相同、但在字符折叠规则下可相互匹配的字符序列,被称为 equivalent character sequences等效字符序列 。
通常情况下,Emacs 的搜索命令 默认不执行字符折叠 ,即不会匹配等效字符序列。你可通过将变量 search-default-mode 自定义为 char-fold-to-regexp 来启用该特性(参见根据需求自定义搜索行为章节)。在增量搜索过程中,按下 M-s ' (isearch-toggle-char-fold) 可切换本次搜索的字符折叠状态,该效果仅对当前搜索有效(替换命令的默认行为与此不同,由独立选项控制,参见替换命令与宽松匹配章节)。
默认情况下,若在搜索字符串中输入某字符的显式变体(如 ä ),不会匹配其基础字符(如 a )。但如果将变量 char-fold-symmetric 自定义为 t ,搜索命令会将等效字符同等对待:在搜索字符串中使用任意一个等效字符,都会匹配待搜索文本中的所有等效字符,因此输入带重音的 ä 时,会同时匹配基础字母a及其所有变体(如 á )。
你可通过可自定义变量 char-fold-include 添加新的字符折叠规则,或通过 char-fold-exclude 移除现有规则;也可将 char-fold-override 自定义为 t ,此时会禁用所有默认字符等效性规则,仅保留你通过 char-fold-include 自行添加的规则。
17.10. 替换命令
Emacs 提供了多个用于执行查找替换操作的命令。除简单的 M-x replace-string (字符串替换)命令外,还有 M-% (查询替换)命令,该命令会逐个定位搜索模式的匹配项,并询问你是否执行替换。
替换命令默认对 从光标位置到缓冲区末尾 的文本生效 ;当选区处于激活状态时,替换操作将仅作用于选区内的文本(参见标记与选区)。基础替换命令可将一个 search string搜索字符串 (或正则表达式)替换为一个指定的 replacement string替换字符串 。你也可以使用 expand-region-abbrevs 命令(参见缩写展开的控制),并行执行多项替换操作。
17.10.1. 无条件替换
M-x replace-string RET string RET newstring RET- 将字符串的每一处匹配项替换为新字符串。
若要将光标位置之后的所有 'foo' 替换为 'bar' ,可执行命令 M-x replace-string ,并传入两个参数 'foo' 和 'bar' 。替换操作仅作用于光标位置之后的文本,因此如果需要覆盖整个缓冲区,必须先将光标移至缓冲区起始位置。从光标处到缓冲区末尾的所有匹配项都会被替换;若要将替换范围限定在缓冲区的某一部分,需先选中该区域。当区域处于激活状态时,替换操作将仅在该区域内进行(详见《标记与区域》章节)。
replace-string 命令执行完毕后,光标会停留在最后一个被替换的匹配项位置。该命令执行前的光标位置会被添加到标记环中,但不会激活标记;可使用 C-u C-SPC 快捷键返回该位置(详见《标记环》章节)。
若为该命令添加前缀参数,则仅会替换那些被单词边界包围的匹配项。
关于替换命令中大小写敏感性与字符折叠的详细说明,详见《替换命令与宽松匹配》章节。
17.10.2. 正则表达式替换
M-x replace-string 命令用于替换指定字符串的 精确匹配项 。与之类似的命令 M-x replace-regexp ,则可替换符合指定正则表达式模式的 任意匹配 内容(详见《正则表达式语法》章节)。
M-x replace-regexp RET regexp RET newstring RET- 将所有匹配该正则表达式的内容替换为新字符串。
在 replace-regexp 命令中, newstring新字符串并非必须是固定文本:它可以 引用正则表达式匹配结果的全部或部分内容 。新字符串中的 '\&' 代表被替换的 整个匹配内容 ;新字符串中的 '\d' (其中 d 是从 1 开始的数字),代表正则表达式中 第 d 个带括号的分组所匹配的内容 (这一用法被称为 “反向引用”)。 '\#' 代表当前命令 已完成的替换次数 ,以十进制数字表示 —— 第一次替换时, '\#' 代表 0;第二次替换时,代表 1,依此类推。例如:
M-x replace-regexp RET c[ad]+r RET \&-safe RET
可将(例如) 'cadr' 替换为 'cadr-safe' ,将 'cddr' 替换为 'cddr-safe' 。
M-x replace-regexp RET \(c[ad]+r\)-safe RET \1 RET
则可实现上述操作的逆向转换。若需在替换文本中包含反斜杠 '\' ,必须输入 '\\' 。
如果希望在 每次替换时手动输入部分替换字符串 ,可在替换字符串中使用 '\?' 。执行替换时,Emacs 会在迷你缓冲区中打开替换字符串供你编辑,光标会自动定位在 '\?' 所在的位置。
本小节的剩余内容适用于 特定专业任务 ,且需要掌握 Lisp 语言相关知识,多数读者可跳过此部分。
你可以使用 Lisp 表达式来计算替换字符串的部分内容。具体方法是,在替换字符串中写入 '\,' ,并在其后跟上对应的表达式。每次替换时,Emacs 会计算该表达式的值,将其直接转换为文本(若表达式的值为字符串,则直接使用字符串内容),并将该文本代入替换字符串,替代原表达式的位置。若表达式为一个符号,那么符号名称后的一个空格会被视为符号名称的一部分,表达式的值会同时替换符号名称与该空格。
在这类表达式内部,你可以使用一些特殊序列。与常规用法一致, '\&' 和 '\d' 分别代表整个匹配内容的字符串形式,以及对应子匹配内容的字符串形式。其中 d 可以是多位数字;若第 d 个带括号的分组未匹配到任何内容, '\d' 的值则为 nil 。你也可以使用 '\#&' 和 '\#d',将对应匹配内容 以数字形式引用 (此用法仅在匹配内容或子匹配内容为数字格式时有效)。此处的 '\#' 同样代表已完成的替换次数。
例如,我们可以通过以下方式交换文本中的 x 和 y:
M-x replace-regexp RET \(x\)\|y RET \,(if \1 "y" "x") RET
在通过 '\' , 构造替换字符串时, format 函数往往能发挥重要作用(详见《Emacs Lisp 参考手册》中的《格式化字符串》章节)。例如,要在第 73 至 80 列的位置添加连续编号的字符串(如 'ABC00042'),且仅在这些列原本无内容时执行添加操作,可执行以下命令:
M-x replace-regexp RET ^.\{0,72\}$ RET \,(format "%-72sABC%05d" \& \#) RET
17.10.3. 替换命令与宽松匹配
本节介绍替换命令在宽松匹配下的行为(参见搜索中的宽松匹配)及其自定义方法。总体而言,替换命令的默认匹配规则,相较于对应的搜索命令会更为严格。
与增量搜索不同,替换命令默认不启用宽松空格匹配(参见宽松空格匹配)。若要为替换操作启用该功能,需将变量 replace-lax-whitespace 设为非nil值(该设置仅影响 Emacs 查找待替换文本的方式,不作用于替换文本本身)。
配套变量 replace-regexp-lax-whitespace ,用于控制 query-replace-regexp 命令在查找匹配模式时,是否启用宽松空格匹配。
若替换命令的第一个参数(搜索串) 全部由小写字母组成 ,则在查找待替换匹配项时会忽略大小写 —— 此行为的前提是 case-fold-search 和 search-upper-case 均为非nil值。若 search-upper-case (参见 search-upper-case)设为 nil ,则搜索是否忽略大小写仅由 case-fold-search 单独决定,与第一个参数的字母大小写无关。若 case-fold-search 设为 nil ,则所有搜索均始终区分大小写。
此外,若替换命令的第二个参数(替换串) 全部或部分为小写字母 , 替换命令会尝试保留每个匹配项的大小写格式 。例如执行命令:
M-x replace-string RET foo RET bar RET
会将小写的 'foo' 替换为小写的 'bar' 、全大写的 'FOO' 替换为 'BAR' 、首字母大写的 'Foo' 替换为 'Bar' (小写、全大写、首字母大写,是 replace-string 命令唯一能识别的三种大小写格式)。
需注意,Emacs 会通过分析 待替换文本中的每个单词 ,决定是否对替换文本进行大写或首字母大写转换;仅当待替换文本的所有单词采用 相同的大小写格式 时,才会保留其格式。例如执行命令:
M-x replace-string RET foo bar RET baz quux RET
会将 'Foo Bar' 替换为 'Baz Quux' ,原因是 'Foo Bar' 中的两个单词均为首字母大写格式;而对于 'Foo bar' ,该命令会将其替换为 'baz quux' (即保持替换文本的原始大小写不变),因为 'Foo bar' 中的两个单词大小写格式不同。
关于何为 “word单词”,由当前缓冲区生效的语法表决定(参见《Emacs Lisp 参考手册》中的语法表章节);例如在文本模式中, 'Foo_Bar' 会被视为两个单词,而在部分支持编程语言的主模式中,它可能被视作单个单词。
若替换串中包含 大写字母 ,则该部分内容在每次插入时,均会保持大写形式。若第一个参数(搜索串)中包含大写字母,第二个参数(替换串)会 严格按照输入内容原样替换 ,不进行任何大小写转换。同理,若 case-replace 或 case-fold-search 任一变量设为 nil ,替换操作也会直接执行,不做大小写转换。
替换命令在查找待替换文本时, 默认不启用字符折叠 (参见字符折叠)。若要在 query-replace 和 replace-string 命令的匹配过程中启用字符折叠,需将变量 replace-char-fold 设为非nil值(该设置仅影响 Emacs 查找待替换文本的方式,不作用于替换文本本身,也对 replace-regexp 命令无效)。
17.10.4. 查询替换(Query Replace)
M-% string RET newstring RET- 将指定字符串的部分匹配项替换为新字符串。
C-M-% regexp RET newstring RET- 将指定正则表达式的部分匹配项替换为新字符串。
若你无需替换foo的所有匹配项,仅需修改其中一部分为bar,可使用 M-% (query-replace) 命令。该命令会逐个查找foo的匹配项,高亮展示每个匹配项并询问是否执行替换。除了交互式确认这一特性,该命令的其余行为与 replace-string (无条件替换)完全一致(参见无条件替换);特别地,在默认开启 case-replace 的情况下,命令会自动保留匹配项的大小写格式(参见替换命令与宽松匹配)。带数字前缀参数执行该命令时,仅会匹配以单词分隔符为边界的完整单词匹配项;带负的前缀参数执行时,会反向向前查找并替换匹配项。
C-M-% 命令执行的是正则表达式的交互式查询替换 (query-replace-regexp) ,其行为与 replace-regexp (正则表达式替换)一致,仅增加了交互式确认替换的步骤。
你可复用上述命令的历史替换规则:当 query-replace 或 query-replace-regexp 命令提示输入搜索串时,按下 M-p 和 M-n 可翻阅历史替换记录,记录将以 'from -> to' 原内容 -> 替换内容的形式展示(其中原内容为搜索模式,替换内容为目标字符串,分隔符由变量 query-replace-from-to-separator 定义),按下 RET 回车键即可选中并复用该条替换规则。若将该变量设为 nil ,替换记录将不会被加入命令历史,也无法被复用。
这类交互式替换命令会通过 query-replace 高亮样式标记当前匹配项,将变量 query-replace-highlight 设为 nil 可关闭该高亮;同时会像增量搜索一样,通过 lazy-hightlight 延迟高亮标记其他匹配项(参见增量搜索),将 query-replace-lazy-highlight 设为 nil 可关闭此效果。默认情况下, query-replace-regexp 会在迷你缓冲区中展示当前匹配项经替换后的结果;若希望保留 '\&' 、 '\n' 等特殊序列不被展开,可自定义 query-replace-show-replacement 变量。与增量搜索中通过 search-highlight-submatches 高亮子表达式匹配项的功能类似(参见根据需求自定义搜索行为),变量 query-replace-highlight-submatches 用于控制正则表达式替换命令是否高亮子表达式的匹配项。
将变量 query-replace-skip-read-only 设为非 nil 值后,替换命令会忽略只读文本中的匹配项,该变量默认值为 nil (即不忽略只读文本中的匹配项)。
当命令定位到字符串或正则表达式的匹配项并发出询问时,可输入以下字符执行对应操作:
SPCy- 将当前匹配项替换为新字符串,继续查找下一个匹配项。
DELDeleteBACKSPACEn- 跳过当前匹配项,不执行替换,直接查找下一个。
, (逗号)替换当前匹配项并展示替换结果,随后需再次输入字符决定后续操作。因替换已完成,此场景下删除键和空格的作用一致,均为跳至下一个匹配项。
此时可按下
C-r(详见下文)编辑已替换的文本,也可使用撤销命令(如C-x u=,参见[[#Undo][撤销操作]])撤销本次替换; *撤销操作会直接退出交互式查询替换* ,若需继续替换,需通过 =C-x ESC ESC RET重新启动命令(参见重复迷你缓冲区命令)。RETq- 直接退出命令,不再执行后续任何替换。
. (句点)- 替换当前匹配项,且替换后直接退出命令,不再查找后续匹配项。
! (感叹号)- 无需再次确认,直接替换剩余所有匹配项。
^ (脱字符)- 返回上一个匹配项的位置(或原匹配项的位置),适用于误操作修改匹配项,或需要重新检查上一个匹配项的场景。
u- 撤销最后一次的替换操作,并回到该次替换的匹配项位置。
U- 撤销本次命令中所有的替换操作,回到第一次替换的匹配项位置。
C-r- 进入递归编辑模式,适用于无需直接替换、需手动编辑当前匹配项的场景。编辑完成后,按下
C-M-c退出递归编辑模式,继续查找下一个匹配项(参见递归编辑模式)。 C-w- 删除当前匹配项,随后进入与
C-r相同的递归编辑模式,可手动输入文本替代被删除的匹配项;编辑完成后,按下C-M-c退出递归编辑模式,继续查找下一个匹配项。 e- 在迷你缓冲区中编辑新的替换字符串,按下回车键退出迷你缓冲区后,会用编辑后的内容替换当前匹配项,且该内容会成为后续所有匹配项的默认替换字符串。
E- 功能与
e类似,但本次替换会 严格按替换串的原始大小写执行 。例如,原替换规则为将foo替换为bar时,Foo会默认被替换为Bar;按下E后,当前匹配项会直接替换为小写的bar,不做大小写适配。 C-l- 重绘屏幕刷新显示,操作后需再次输入字符,决定当前匹配项的处理方式。
Y (大写)- 在多缓冲区替换场景中(如
Dired的Q命令,对选中文件执行交互式查询替换),替换当前缓冲区及剩余所有缓冲区中的全部未处理匹配项。该操作会对本次及后续所有替换询问均自动回答 “yes”,无需用户再手动确认。 N (大写)- 在多缓冲区替换场景中,跳过当前缓冲区的剩余所有匹配项,直接切换至下一个缓冲区。该操作会对当前替换询问回答 “no”,并放弃当前缓冲区的所有后续替换询问,继续处理序列中的下一个缓冲区。
C-h?F1- 展示上述所有操作选项的汇总提示信息,查看后需再次输入字符,决定当前匹配项的处理方式。
除上述字符外,输入 其他任意字符都会直接退出 query-replace交互式查询替换 ,且该字符会被重新读取作为按键序列的一部分执行对应操作。例如,输入 C-k 会先退出 query-replace 命令,再执行 “删除至行尾” 的操作;输入 C-g 则会直接退出 query-replace ,无其他后续操作。
若替换命令已退出,需重新启动时,可按下 C-x ESC ESC —— 该快捷键会重复执行上一次的交互式查询替换(因命令的参数均通过迷你缓冲区读取),详见 C-x ESC ESC 相关说明。
变量 search-invisible 决定了交互式查询替换命令对隐藏文本的处理方式,参见大纲模式中的搜索。
关于对选中文件执行交互式查询替换的 Dired Q 命令,参见文件操作相关章节;此外,在 Dired 中通过正则表达式匹配重命名、复制或创建文件链接的相关命令,参见 Dired 中的文件名转换。
17.11. 其他搜索与循环命令
以下是一些用于查找正则表达式匹配项的其他命令。若模式中不包含大写字母且 case-fold-search 变量非空,这些命令在匹配时均忽略大小写。除始终搜索整个缓冲区的 multi-occur 和 multi-occur-in-matching-buffers 外,所有命令均作用于 从光标位置到缓冲区末尾 的文本;若选区处于激活状态,则作用于选区。
M-x multi-isearch-buffers- 提示输入一个或多个缓冲区名称,按
RET回车键结束;随后在这些缓冲区中 启动多缓冲区增量搜索 。(若在某个缓冲区中搜索失败,按下下一个C-s会尝试在指定的下一个缓冲区中继续搜索,依此类推。)带前缀参数执行时,会提示输入一个正则表达式,并在匹配该正则表达式的所有缓冲区中启动多缓冲区增量搜索。 M-x multi-isearch-buffers-regexp- 该命令与
multi-isearch-buffers功能基本一致,区别在于它执行的是 多缓冲区增量正则表达式搜索 。 M-x multi-isearch-files- 提示输入一个或多个文件名,按
RET回车键结束;随后在这些文件中启动 多文件增量搜索 。(若在某个文件中搜索失败,按下下一个C-s会尝试在指定的下一个文件中继续搜索,依此类推。)带前缀参数执行时,会提示输入一个正则表达式,并在匹配该正则表达式的所有文件中启动多文件增量搜索。 M-x multi-isearch-files-regexp该命令与
multi-isearch-files功能基本一致,区别在于它执行的是 多文件增量正则表达式搜索 。在部分设置了缓冲区局部变量
multi-isearch-next-buffer-function的模式中(例如Change Log mode变更日志模式),多文件增量搜索会被自动激活。M-x occurM-s o提示输入一个正则表达式,随后显示缓冲区中 所有包含该匹配项的行 的列表。在提示界面按下
M-n,可复用之前增量搜索使用过的搜索字符串。匹配到的文本会通过match(字体样式)高亮显示。带数字参数n执行时,会在每个匹配行的前后各显示n行上下文内容。上下文的默认行数由变量
list-matching-lines-default-context-lines指定。当变量list-matching-lines-jump-to-current-line非空时,当前行会以list-matching-lines-current-line-face样式高亮显示,且光标会定位到该行后的第一个匹配项处。若增量搜索正在进行,直接按下
M-s o即可基于 当前的搜索字符串 执行该命令。注意:输入的正则表达式匹配项会被扩展为 整行匹配 ,且若某个匹配项的起始位置在前一个匹配项的结束位置之前,该匹配项将不被计入。
*Occur*缓冲区以Occur 模式作为主模式:- 按下
n和p键可跳至下一个 / 上一个匹配项;带数字前缀参数时,可按指定次数跳至对应匹配项(数字键绑定了 ~digit-argument~ ,因此输入5 n即可跳至后面第5个匹配项,无需先按C-u); - 按下空格键(
SPC)和删除键(DEL)可上下滚动*Occur*缓冲区; - 点击某个匹配项,或将光标移至该匹配项处并按回车键,会跳转到被搜索的原始缓冲区中对应的位置;
- 按下
o和C-o可在另一个窗口中显示该匹配项(=C-o= 不会选中新窗口); - 也可使用 M-g M-n(next-error,下一个错误)命令逐个访问所有匹配项(参见编译模式);
- 按下
q可关闭显示*Occur*缓冲区的窗口,并将该缓冲区隐藏。
在
*Occur*缓冲区中按下e,会将该缓冲区设为可写状态并进入Occur 编辑模式,此时可编辑匹配行,且所有编辑操作会同步至原始缓冲区的对应文本。按下C-c C-c可退出 Occur 编辑模式,恢复为普通 Occur 模式。命令
M-x list-matching-lines是M-x occur的同义词。- 按下
M-x multi-occur- 该命令与
occur功能基本一致,区别在于它可在 多个缓冲区中同时搜索 ,执行时会提示逐个指定需要搜索的缓冲区名称。 M-x multi-occur-in-matching-buffers- 该命令与 ~multi-occur~ 功能类似,区别在于 待搜索的缓冲区 通过 匹配已访问文件名的正则表达式 指定;带前缀参数执行时,会改为通过正则表达式匹配 缓冲区名称 来指定待搜索缓冲区。
M-x how-many- 提示输入一个正则表达式,随后 统计并打印 光标位置之后的缓冲区中该表达式的匹配次数;若选区处于激活状态,则仅统计选区中的匹配次数。
M-x flush-lines- 提示输入一个正则表达式,随后 删除 光标位置之后的文本中 所有包含该匹配项的行 ;命令执行完毕后,会打印被删除的匹配行数量。
- 若当前行中光标位置之后存在匹配项,该行会被删除;
- 若选区处于激活状态,则仅对选区生效:若某行部分包含在选区内,且其匹配项 完全位于选区内 ,该行会被删除;
- 若某个匹配项跨越多行,这些行都会被一并删除;该命令会先删除匹配行,再继续查找下一个匹配项,因此会忽略在前一个匹配项结束行的同一行起始的新匹配项。
M-x keep-lines- 提示输入一个正则表达式,随后 删除 光标位置之后的文本中 所有不包含该匹配项的行 ;
- 若光标未位于行首,该命令始终保留当前行;
- 若选区处于激活状态,则仅对选区生效:永远不会删除仅部分包含在选区内的行(行尾的换行符视为该行的一部分);
- 若某个匹配项跨越多行,这些行都会被一并保留。
M-x kill-matching-lines- 功能与
flush-lines一致,区别在于该命令会 将被删除的匹配行 添加至 删除环(kill ring) 中,且所有匹配行会被合并为单个字符串(包含行之间的换行符)后存入删除环。 M-x copy-matching-lines- 功能与
kill-matching-lines一致,区别在于该命令不会 从缓冲区中删除匹配行 ,仅将其复制至删除环。
17.12. 根据需求定制搜索
本节介绍其他章节未提及的各类搜索相关自定义配置。
增量搜索的默认模式由变量 search-default-mode 指定,其值可为 nil 、 t 或一个函数:
- 若值为
nil,默认执行 字面量搜索 ,不进行字符折叠,但会根据case-fold-search和~search-whitespace-regexp~ 分别开启大小写折叠和宽松空白匹配(参见「搜索中的宽松匹配」); - 若值为
t,增量搜索默认执行 正则表达式搜索 ; - 该变量的默认值为一个函数,仅会执行大小写折叠和宽松空白匹配。
正在进行的增量搜索中, 当前匹配项 会通过 isearch 面(字体样式)高亮显示,将变量 search-highlight 设为 nil 可关闭该高亮效果。
当搜索正则表达式时(例如使用快捷键 C-M-s ),子表达式的高亮规则由变量 search-highlight-submatches 决定:
- 若该变量值为
nil,子表达式无特殊高亮; - 若值非nil,正则表达式中由 '
\( … \)' 定义的子表达式匹配到的文本,会用不同的面进行高亮。
默认情况下,Emacs 定义了两个专用高亮面: isearch-group-1 和 isearch-group-2 。基于这两个面的规则: 奇数序号的子表达式 由 isearch-group-1 高亮, 偶数序号的子表达式 由 isearch-group-2 高亮。例如搜索正则表达式 'foo-\([0-9]+\)\([a-z]+\)' 时, '[0-9]+' 匹配的内容会显示 isearch-group-1 样式, '[a-z]+' 匹配的内容会显示 isearch-group-2 样式。
若按相同命名规则自定义更多高亮面(如 isearch-group-3 、 isearch-group-4 等),则第 M 、 N+M 、 2N+M 个(以此类推)子表达式会由 isearch-group-M 高亮,其中 N 为所有 isearch-group-M 格式高亮面的总数。
当前屏幕中 可见的其他匹配项 ,会通过 lazy-highlight 面样式进行高亮,将变量 isearch-lazy-highlight 设为 nil 可关闭该懒高亮效果。以下是用于自定义懒高亮的其他变量:
lazy-highlight-initial-delay- 高亮可见匹配项前的等待时间,单位为秒。仅当搜索字符串的长度小于
lazy-highlight-no-delay-length的取值时,该配置才生效。 lazy-highlight-no-delay-length- 当搜索字符串的长度大于或等于该变量的取值时,懒高亮会立即触发,无等待时间。
lazy-highlight-interval- 依次高亮多个匹配项时的时间间隔,单位为秒。
lazy-highlight-max-at-a-time- 一次最多高亮的匹配项数量,达到该数量后会先检查用户输入再继续。若该值设置过大,高亮过程会耗时较久;此期间若按下
C-s或C-r继续搜索,Emacs 需完成所有高亮后才会响应,因此 更小的取值 能提升 Emacs 的响应速度。 isearch-lazy-count- 在搜索提示栏中显示当前匹配项的序号和匹配项的总数。
lazy-count-prefix-formatlazy-count-suffix-format- 这两个变量共同决定了
isearch-lazy-count的显示格式,用于定义当前匹配数和总匹配数的前后缀样式。
默认情况下,若增量搜索中搜索字符串为空,按下回车键( RET )会启动非增量搜索(实际流程为:先允许编辑搜索字符串,再次按下回车键后执行搜索)。若将变量 search-nonincremental-instead 设为 nil ,则无论搜索字符串是否为空,按下回车键都会直接退出增量搜索。
默认情况下,增量搜索和查询替换命令会 匹配不可见文本 ,但当当前匹配项离开该不可见文本区域后,会立即隐藏相关匹配的高亮。若将变量 isearch-hide-immediately 设为 nil ,则找到匹配项的不可见文本会保持显示,直到搜索或替换命令执行完毕。
在低速终端中进行增量搜索(例如通过低速网络连接远程机器的显示器),搜索过程中需要重绘屏幕的大部分区域,操作体验会较差。Emacs 为低速终端提供了专用的显示模式:搜索时会弹出一个独立的小窗口,仅在该窗口中显示匹配项周边的文本。小窗口的重绘速度更快,能有效缓解低速终端的操作卡顿问题。相关配置变量如下:
search-slow-speed:设置波特率阈值,当终端波特率低于该值时,Emacs 会自动启用该低速终端显示模式;search-slow-window-lines:控制搜索结果弹出窗口的行数,默认值为 1 行。该窗口默认出现在启动 搜索的缓冲区窗口底部 ;若该变量取负值,则窗口会显示在顶部,且窗口行数为该负值的绝对值。
18. 拼写错误修正命令
本章介绍在编辑过程中发现错误时可使用的实用命令。其中最基础的是撤销命令 C-/ (同时绑定至 C-x u 和 C-_ )。该命令可撤销单个操作命令、某一命令的部分执行结果(如查询替换的部分操作),或连续的多次字符输入操作。连续按下 C-/ 可依次撤销更早的修改操作,直至达到撤销记录的存储上限。
除本章介绍的命令外,你也可使用删除类命令清除文本,例如 DEL (delete-backward-char) 。这类命令已在本手册的前文介绍,详见「文本删除」章节。
18.1. 撤销(Undo)
撤销命令可还原缓冲区文本中近期的修改操作。每个缓冲区会单独记录自身的修改,撤销命令始终作用于 当前缓冲区 。你可以根据缓冲区的记录,撤销其中所有的修改操作。通常,每个编辑命令都会在撤销记录中生成一条独立条目;但为了提升撤销操作的灵活性,部分命令(如查询替换)会将自身的修改拆分为多条记录。连续的字符输入操作则通常会合并为 单条撤销记录 ,让撤销操作更简洁。
撤销快捷键
C-/C-x uC-_- 撤销当前缓冲区撤销记录中的一条条目 (
undo) 。
基础撤销操作
要执行撤销,按下 C-/ (或其等效快捷键 C-_ 、 C-x u ) 6 即可。该操作会还原缓冲区中最近一次的修改,并将光标移回修改前的位置。连续按下 C-/ (或其等效快捷键),可依次还原当前缓冲区中更早的修改。若所有已记录的修改均已被还原,执行撤销命令会触发错误提示。
撤销序列的中断与重做
除撤销命令外的任意操作,都会中断连续的撤销序列。从操作执行的那一刻起,你此前完成的整段撤销操作,会自身被写入撤销记录。因此,若要重新应用已被撤销的修改,可按下 C-f (前移字符)或其他无副作用的命令中断撤销序列,随后多次按下 C-/ ,撤销部分此前的撤销操作即可。
若你希望继续执行撤销,而非重做已完成的撤销操作,可使用 M-x undo-only 命令。该命令功能与 undo 一致,但不会重做已被撤销的修改。与之互补的是 M-x undo-redo 命令,它可撤销此前的撤销操作,且自身不会被记录为可撤销的操作。
恢复意外修改的缓冲区
若发现缓冲区被意外修改,最简便的恢复方式是反复按下 C-/ ,直至模式行开头的星号消失(参见「模式行」章节)。当撤销命令让模式行的星号消失时,意味着缓冲区内容已恢复至最近一次读取或保存文件时的状态。若你不确定是否是有意修改了缓冲区,可先按一次 C-/ ,看到最近一次的修改被还原后,即可判断该修改是否为操作失误:若是意外修改,保持撤销后的状态即可;若是有意修改,按上述方法重做该修改即可。
此外,你也可使用 M-x revert-buffer 命令,丢弃缓冲区自最近一次打开或保存后所有的修改(参见「还原缓冲区」章节)。
选区的选择性撤销
当存在激活的选区时,执行任意撤销操作都会触发选择性撤销:仅还原选区内最近一次的修改,而非整个缓冲区的修改。但当瞬时标记模式关闭时(参见「关闭瞬时标记模式」), C-/ 会始终作用于整个缓冲区,忽略选区的存在。这种情况下,可为撤销命令添加前缀参数来执行选择性撤销:按下 C-u C-/ 即可;若要继续还原同一选区内更早的修改,直接重复执行撤销命令即可,无需再添加前缀参数。
无撤销记录的特殊缓冲区
部分专用缓冲区不会生成撤销记录: 名称以空格开头 的缓冲区始终不会记录,这类缓冲区由 Emacs 内部使用,用于存储用户通常不会查看或编辑的文本。
撤销记录的内存限制
当某个缓冲区的撤销信息占用空间过大时,Emacs 会在垃圾回收过程中 不定期丢弃最旧的记录 。你可通过设置变量 undo-limit 、 undo-strong-limit 和 undo-outer-limit ,指定 Emacs 保留的撤销信息容量,变量值均以字节为单位。
undo-limit(软限制):Emacs 会保留足够多的命令撤销数据,直至达到该容量上限,甚至可小幅超出,但不会保留超出部分的更早命令数据,默认值为 160000 字节。undo-strong-limit(硬限制):更严格的容量上限,若某条历史命令的撤销数据会让总占用量超出该值,该命令的记录会被直接丢弃(最近一次的修改记录除外),默认值为 240000 字节。
无论上述两个变量的取值如何, 最近一次的修改记录永远不会被丢弃 ,除非其占用空间超过 undo-outer-limit (默认值为 24000000 字节)。当达到该极限时,Emacs 会丢弃此次的撤销数据并向你发出警告 —— 这是 唯一无法撤销上一条命令 的情况。若出现该问题,你可增大 undo-outer-limit 的取值,降低后续出现该情况的概率;但如果该命令并非预期会生成超大撤销数据,这很可能是程序漏洞,建议你进行反馈(参见「漏洞反馈」章节)。
18.2. 文本交换(Transposing Text)
C-t- 调换两个字符 (
transpose-chars) 。 M-t- 调换两个单词 (
transpose-words) 。 C-M-t- 调换两个配对表达式 (
transpose-sexps) 。 C-x C-t- 调换两行文本 (
transpose-lines) 。 M-x transpose-sentences- 调换两个句子 (
transpose-sentences) 。 M-x transpose-paragraphs- 调换两个段落 (
transpose-paragraphs) 。 M-x transpose-regions- 调换两个区域的文本。
相邻两个字符输反是最常见的输入错误,可使用 C-t 命令 (transpose-chars) 修正。默认情况下, C-t 会调换 光标两侧 的两个字符;若光标位于行尾,该命令不会将行尾字符与换行符无效调换,而是调换该行的 最后两个字符 。因此,若发现字符输反后立即操作,直接按 C-t 即可修正;若发现较晚,需先将光标移至输反的两个字符之间,再按下 C-t 。若你误将单词末尾的字符与后方的空格调换,可使用单词移动命令( M-f 、 M-b 等)快速定位光标;其他情况则常用反向搜索( C-r )定位,详见「搜索与替换」章节。
M-t 命令会调换 光标前的单词 与 光标后的单词 (transpose-words) ,执行时光标会向前跳过一个单词,同时将光标前方或包含光标的单词一并向前拖动,单词之间的标点符号位置保持不变。例如,文本 'FOO, BAR' 经调换后会变成 'BAR, FOO' ,而非 'BAR FOO,' 。若光标位于行尾,该命令会将光标前的单词与下一行的第一个单词调换。
C-M-t (transpose-sexps) 是功能类似的配对表达式调换命令(详见「带配对括号的表达式」), C-x C-t (transpose-lines) 用于调换两行文本。 M-x transpose-sentences 和 M-x transpose-paragraphs 则分别用于调换句子和段落,这两个命令的工作逻辑与 M-t 一致,仅调换的文本单位不同。
为调换命令添加数字前缀参数,该参数会作为重复执行的次数:命令会将光标前方或包含光标的字符(/ 单词 / 表达式 / 行),跨越多个同类文本单位进行调换。例如,按下 = C-u 3 C-t= ,会将光标前的字符向前跨 3 个字符调换,将文本 'f∗oobar' 转换为 'oobf∗ar',效果等同于连续按 3 次 C-t ;按下 C-u -4 M-t ,会将光标前的单词向后跨 4 个单词调换;按下 C-u - C-M-t ,可撤销普通 C-t 命令的调换效果。
数字前缀参数为 0时被赋予特殊含义(若无特殊定义,重复次数为 0 的命令将无任何操作):调换光标后结束的文本单位,与标记后结束的文本单位(字符 / 单词 / 表达式 / 行)。
M-x transpose-regions 命令用于调换两类文本:一类是光标与标记之间的文本,另一类是标记环中最后两个标记之间的文本(详见「设置标记」)。若为该命令添加数字前缀参数,会将光标与标记之间的文本,与标记环中向前数指定次数的 连续两个标记之间 的文本进行调换。该命令最适合一次性调换多段字符、单词、句子或段落。
18.3. 大小写转换(Case Conversion)
M-- M-l- 将最后一个单词转换为小写。注意,
M--即Meta键-减号。 M-- M-u- 将最后一个单词全部转换为大写。
M-- M-c- 将最后一个单词转换为首字母大写、其余小写的格式。
输错单词大小写是极为常见的输入错误。因此,大小写转换命令 M-l 、 M-u 、 M-c 搭配负参数使用时,会触发一项特殊功能:执行命令时光标不会移动。当你发现刚输入的最后一个单词大小写有误,只需直接执行对应的大小写转换命令,即可继续后续输入,无需调整光标位置。详见「大小写转换命令」章节。
18.4. 拼写检查与修正
本节介绍用于检查单个单词或部分缓冲区文本拼写的命令。这些命令仅在安装了拼写检查程序(Hunspell、Aspell、Ispell 或 Enchant 中的任意一款)时才能运行。上述程序并非 Emacs 的组成部分,但通常会预装在 GNU/Linux 及其他自由操作系统中。详见《Aspell 使用手册》中的 Aspell 相关章节。
若仅安装了一款拼写检查程序,首次调用本节所述命令时,Emacs 会自动检测并加载该程序。若安装了多款,则可通过自定义变量 ispell-program-name 来指定使用哪一款。
M-$- 检查并纠正光标所在位置单词的拼写 (
ispell-word) 。若选区处于激活状态,则检查选区范围内所有单词 C-u M-$- 若上一次拼写检查操作被中断,执行此命令可恢复该操作 (
ispell-continue) M-x ispell- 检查并纠正整个缓冲区的拼写。若选区处于激活状态,则仅检查选区内容
M-x ispell-buffer- 检查并纠正整个缓冲区的拼写
M-x ispell-region- 检查并纠正选区范围内的拼写
M-x ispell-message- 检查并纠正邮件草稿的拼写,自动排除引用内容
M-x ispell-comments-and-strings- 检查并纠正缓冲区或选区中代码的注释与字符串内容的拼写
M-x ispell-comment-or-string-at-point- 检查光标所在位置的代码注释或字符串的拼写
M-x ispell-change-dictionary RET dict RET- 重启拼写检查进程,并指定使用 词典名 对应的词典
M-x ispell-kill-ispell- 终止拼写检查子进程
M-TABESC TABC-M-i- 基于拼写词典及其他补全来源,补全光标前方的单词 (
completion-at-point) M-x flyspell-mode- 启用 Flyspell 模式,该模式会高亮显示所有拼写错误的单词
M-x flyspell-prog-mode- 启用适用于编程场景的 Flyspell 模式,仅检查代码注释与字符串中的拼写
基础拼写检查操作流程
要检查并选择性纠正光标附近或前方单词的拼写,可按下 M-$ (ispell-word) 。若选区已激活, M-$ 会检查选区中所有单词(详见 “标记与选区” 章节)。当暂态标记模式关闭时, M-$ 会忽略选区,始终作用于光标附近的单词(详见 “关闭暂态标记模式” 章节)。若带前缀参数执行 C-u M-$ ,则会调用 ispell-continue 命令,恢复此前被 X 或 C-g 中断的拼写检查操作。
同理, M-x ispell 命令会在选区激活时检查选区,否则检查整个缓冲区。 ispell-buffer 和 ispell-region 命令则分别明确指定对整个缓冲区或选区进行拼写检查。编写电子邮件时,可使用 M-x ispell-message 命令,该命令会检查整个缓冲区,但自动排除缩进内容或疑似引用自其他邮件的文本(详见 “发送邮件” 章节)。处理源代码时,可使用 ispell-comments-and-strings 或 ispell-comment-or-string-at-point 命令,仅检查注释或字符串字面量的拼写。
拼写错误的处理方式
当拼写检查命令检测到疑似拼写错误的单词时,会提示用户进行处理。程序通常会显示一份带编号的近似单词列表 —— 即与错误单词拼写相近的正确词汇。此时需输入单个字符来执行相应操作,有效操作指令如下:
digit- 数字键。仅本次将错误单词替换为列表中对应编号的近似单词。
SPC- 跳过当前单词 —— 标记其为拼写错误,但不做修改。
r new RET- 仅本次将错误单词替换为输入的 “新单词”(替换后的字符串会被重新扫描,排查是否存在其他拼写错误)。
R new RET- 将错误单词替换为输入的 “新单词”,并启动查询替换功能,可选择在缓冲区其他位置批量替换该单词(替换后的内容会被重新扫描)。
a- 接受当前单词 —— 在本次编辑会话中,将其视为正确拼写。
A- 接受当前单词 —— 在本次编辑会话及当前缓冲区内,将其视为正确拼写。
i- 将当前单词添加到个人词典文件中,此后即使重启 Emacs,该单词也会被识别为正确拼写。
m- 功能与
i类似,同时可指定词典补全信息。 u- 将当前单词的小写形式添加到个人词典文件中。
l word RET- 在词典中搜索与 “待查单词” 匹配的词汇,搜索结果将作为新的近似单词列表,可输入对应数字键选择替换。“待查单词” 中可使用 '
*' 作为通配符。 C-gX- 中断交互式拼写检查,将光标停留在正在检查的单词处。后续可通过
C-u M-$恢复检查。 x- 退出交互式拼写检查,并将光标返回至检查开始前的位置。
q- 退出交互式拼写检查,并终止拼写检查子进程。
C-r- 进入递归编辑模式(详见 “递归编辑层级” 章节)。按下
C-M-c退出递归编辑后,拼写检查会自动恢复。该模式可在不中断检查的前提下查看缓冲区文本,但禁止在递归编辑期间修改缓冲区内容,尤其不能改动疑似拼写错误的单词 —— 退出递归编辑时,所有修改都会被撤销。若需修改错误单词,应使用r或R指令,或按下X中断检查、编辑文本后,再用C-u M-$恢复。 - -
C-z - 挂起 Emacs 或最小化当前窗口。
- -
? - 显示所有操作指令的说明列表。
单词补全功能
使用 M-TAB (completion-at-point) 可补全光标所在位置的单词。输入单词前缀后按下 M-TAB ,即可从补全列表中选择所需词汇。若窗口管理器拦截了 M-TAB 快捷键,可改用 ESC TAB 或 C-M-i 。
拼写检查子进程管理
拼写检查子进程启动后会保持运行状态,等待后续操作,因此后续拼写检查命令的执行速度会更快。若需终止该进程,可执行 M-x ispell-kill-ispell 命令。通常无需手动终止,因为该进程仅在执行拼写纠错时占用系统资源,闲置时不会消耗处理器性能。
词典配置说明
拼写检查程序会从两类词典中查询拼写规则:标准词典与个人词典。
- 标准词典:由变量
ispell-local-dictionary指定;若该变量值为nil,则使用ispell-dictionary的值;若两个变量均为nil,则使用拼写程序的默认词典。执行M-x ispell-change-dictionary命令可设置当前缓冲区的标准词典,并重启子进程以应用新词典。 - 个人词典:由变量
ispell-personal-dictionary指定;若该变量值为空,拼写程序会在各程序的默认路径下查找个人词典。
拼写检查所用的词典通常对应特定语言,默认语言由系统环境与区域设置决定。若需检查其他语言文本的拼写,需同时修改标准词典与个人词典,可通过 ispell-change-dictionary 命令完成配置。
Hunspell 特殊功能:Hunspell 支持同时加载多本词典进行拼写检查。若需启用该功能,需在使用 Hunspell 检查混合语言文本前,执行 M-x ispell-hunspell-add-multi-dic 命令,按提示输入以逗号分隔的多语言词典名称列表(例如 'en_US' , 'de_DE' , 'ru_RU' )。配置完成后,检查混合上述语言的文本时无需频繁切换词典。
注意:若多种语言使用同一套书写系统,可能出现 “某单词在一种语言中拼写错误,但在另一语言词典中被判定为正确” 的情况,此时该拼写错误可能被遗漏。
单词补全词典
单词补全功能使用独立的词典,其文件名由变量 ispell-complete-word-dict 指定。补全词典需与拼写检查词典区分开,因为补全功能无法利用拼写检查所依赖的单词词根与词缀信息来识别单词变体。部分语言仅提供拼写检查词典,无对应的单词补全词典。
Flyspell Mode
Flyspell 模式是一种次要模式,可在输入文本时自动进行拼写检查。当检测到无法识别的单词时,会高亮标记该单词。执行 M-x flyspell-mode 可在当前缓冲区切换该模式的开关状态。若需在所有文本模式缓冲区中默认启用该模式,可将 flyspell-mode 添加至 text-mode-hook (详见 “钩子函数” 章节)。
注意:由于 Flyspell 模式需要检查光标经过的每个单词,可能会降低光标移动与滚动操作的速度。此外,该模式不会自动检查未输入或未经过的文本,需手动执行 flyspell-region 或 flyspell-buffer 命令进行检查。
默认情况下, Flyspell 模式会高亮标记所有输入、修改或光标经过的错误单词。若将变量 flyspell-check-changes 自定义为非空值,则仅检查输入或编辑过的单词。
当 Flyspell 模式高亮标记某个错误单词时,可通过以下方式纠错:
mouse-2鼠标中键点击该单词 (flyspell-correct-word) ,会弹出包含候选纠正词与操作选项的菜单;若需改为mouse-3鼠标右键弹出菜单,启用context-menu-mode即可。- 按下
C-.或ESC TAB(flyspell-auto-correct-word) ,会依次推荐多个候选纠正词。 - 按下
C-c $(flyspell-correct-word-before-point) ,会弹出候选纠正词菜单。当然,也可直接手动编辑单词进行纠错。
Flyspell Prog Mode
该模式的功能与普通 Flyspell 模式类似,但仅检查代码注释与字符串常量中的拼写,非常适合编辑程序代码。执行 M-x flyspell-prog-mode 可在当前缓冲区切换该模式的开关状态。若需在所有编程模式缓冲区中默认启用该模式,可将 flyspell-prog-mode 添加至 prog-mode-hook (详见 “钩子函数” 章节)。
19. 键盘宏(Keyboard Macros)
本章将介绍如何记录一系列编辑命令,以便后续便捷地重复执行。
keyboard macro 键盘宏是由 Emacs 用户自定义的命令,用于替代另一组按键序列。例如,若你需要连续四十次输入 C-n M-d C-d 这组操作,可自定义一个执行该操作的键盘宏,随后只需再调用此宏 39 次,即可大幅提升操作效率。
定义键盘宏的方式,是通过执行并记录构成该宏的一系列命令。换言之,在定义键盘宏的过程中,其对应的操作会被首次执行。通过这种方式,你能直观看到各命令的执行效果,无需在脑中推演操作结果。完成宏的定义后,该键盘宏即被创建,且实际上已执行过一次;后续只需调用此宏,就能重复执行整套操作。
键盘宏与 Emacs 普通命令的区别在于:键盘宏基于 Emacs 命令语言编写,而非 Lisp 语言。这让新手能更轻松地编写键盘宏,也让它作为临时快捷操作时更易用。但 Emacs 命令语言的编程能力有限,无法编写具备智能逻辑或通用型的功能,这类需求则需要使用 Lisp 语言实现。
19.1. 基本使用
F3- 开始定义键盘宏 (
kmacro-start-macro-or-insert-counter) 。 F4- 若正处于键盘宏定义状态,则结束定义;否则,执行最近定义的键盘宏 (
kmacro-end-or-call-macro) 。 C-u F3- 重新执行上一个键盘宏,随后将后续按键追加至该宏的定义中。
C-u C-u F3- 直接将后续按键追加至上一个键盘宏的定义,不重新执行该宏。
C-x C-k r- 在区域内所有行首执行最近定义的键盘宏 (
apply-macro-to-region-lines) 。 C-x (- 开始定义键盘宏(旧式快捷键,对应函数
kmacro-start-macro);带前缀参数时,将后续操作追加至上一个宏的定义。 C-x )- 结束键盘宏定义(旧式快捷键,对应函数
kmacro-end-macro);前缀参数作为该宏的执行重复次数。 C-x e- 执行最近定义的键盘宏 (
kmacro-end-and-call-macro) ;前缀参数作为执行重复次数。
定义键盘宏时,按下 F3 即可启动。此后你输入的所有按键,会在正常执行操作的同时,被记录为键盘宏的定义内容。此时模式行中会显示 'Def' 标识,提醒当前处于宏定义状态。定义完成后,按下 F4 (kmacro-end-or-call-macro) 即可终止宏定义。例如:
F3 M-f foo F4
该操作会定义一个键盘宏,功能为:向前移动一个单词,然后插入文本「foo」。注意, F3 和 F4 本身不会被纳入宏的定义内容。
宏定义完成后,按下 F4 即可调用该宏。对于上述示例,调用宏的效果与直接输入 M-f foo 完全一致。( 需 注意 F4 命令的双重作用 :若处于宏定义过程中,它是结束定义的快捷键;若未处于定义状态,则用于调用最近的键盘宏。)你也可以为 F4 指定数字前缀参数n,表示将该宏连续执行 n 次。若前缀参数为 0,宏会无限重复执行,直至触发错误或你按下 C-g 终止(在 MS-DOS 系统中为 C-Break )。
上述示例体现了键盘宏的一个实用技巧:若你需要在文本中按固定间隔重复某一操作,可将 移动类命令 纳入宏的定义。在该示例中,重复调用宏会在每一个后续单词后插入字符串「foo」,实现按间隔批量操作。
终止键盘宏定义后,按下 C-u F3 可将后续按键追加至该宏的定义末尾。该操作等效于重新按下 F3 启动定义,并手动重新输入宏的原有所有内容,因此会先重新执行一次该宏的原有定义。若将变量 kmacro-execute-before-append 的值设为 nil ,则追加定义前不会重新执行原有宏(该变量默认值为 t )。若想直接追加定义而不执行原有宏,可按下 C-u C-u F3 。
当宏定义中包含需要通过迷你缓冲区读取参数的命令时,你在迷你缓冲区中输入的内容,会与该命令一同被记录到宏定义中。因此回放该宏时,该命令会使用定义宏时输入的相同参数。例如:
F3 C-a C-k C-x b foo RET C-y C-x b RET F4
该操作定义的键盘宏,功能为:删除当前行,将其粘贴至缓冲区「foo」,随后返回原缓冲区。
绝大多数键盘命令在宏定义中均可正常使用,仅存在少量例外:
- 按下
C-g(keyboard-quit) 会直接终止当前的键盘宏定义; - 按下
C-M-c(exit-recursive-edit) 的行为不可靠:若退出的是宏定义过程中启动的递归编辑,其行为符合预期;但若退出的是调用键盘宏前就已启动的递归编辑,该操作会同时终止键盘宏的执行; - 鼠标事件同样存在不确定性:尽管宏定义中可以记录鼠标操作,但回放宏时,鼠标事件会使用 定义宏时的原始鼠标位置 ,而非回放时的鼠标位置,其执行效果难以预测。
命令 C-x C-k r (apply-macro-to-region-lines) 的作用是,在选中区域内 所有行的行首 执行最近定义的键盘宏。该命令会逐行执行:先将光标移至行首,再调用键盘宏。
除上述 F3 和 F4 的新式快捷键外,Emacs 还支持一套定义和执行键盘宏的 旧式快捷键 :
C-x ((kmacro-start-macro) 启动宏定义,与F3一致,带前缀参数时会将操作追加至上一个宏;C-x )(kmacro-end-macro) 结束宏定义;C-x e(kmacro-end-and-call-macro) 执行最近定义的宏。
若在宏定义过程中按下 C-x e ,会直接终止定义并立即执行该宏。在首次按下 C-x e 后,可连续按下 e 键,多次重复执行该宏;也可像 F4 一样,为 C-x e 指定前缀参数,作为宏的执行重复次数。
为 C-x ) 指定数字前缀参数时,表示定义完成后立即重复执行该宏。由于宏的定义过程本身就是首次执行,因此 C-u 4 C-x ) 表示在定义完成后,再额外执行该宏 3 次。
执行耗时较长的键盘宏时,有时需要手动触发屏幕重绘,以查看宏的执行进度,此时可使用命令 C-x C-k d 。举一个简单的示例: C-x ( M-f C-x C-k d C-x ) 定义的宏,在执行 C-u 42 C-x e 时,会在每次迭代中触发一次屏幕重绘。
19.2. 键盘宏环(Keyboard Macro Ring)
所有已定义的键盘宏都会记录在 键盘宏环 中。Emacs 中仅有一个键盘宏环,供所有缓冲区共享使用。
C-x C-k C-k- 执行宏环首位置的键盘宏 (
kmacro-end-or-call-macro-repeat) 。 C-x C-k C-n- 轮换键盘宏环至下一个宏(更早定义的宏)(
kmacro-cycle-ring-next) 。 C-x C-k C-p- 轮换键盘宏环至上一个宏(更晚定义的宏)(
kmacro-cycle-ring-previous) 。
所有对键盘宏环进行操作的命令,均使用统一的 C-x C-k 前缀。这类命令中的绝大多数,可连续执行和重复调用,无需再次输入 C-x C-k 前缀。例如:
C-x C-k C-p C-p C-k C-k C-k C-n C-n C-k C-p C-k C-d
该操作的执行逻辑为:将键盘宏环轮换至倒数第二个宏,执行当前宏环首位置的该宏三次,轮换回宏环原本的首位置宏并执行一次,再轮换至上一个宏并执行,最后将该宏从宏环中删除。
命令 C-x C-k C-k (kmacro-end-or-call-macro-repeat) 用于执行宏环首位置的键盘宏。执行后可直接按下 C-k 重复调用该宏,也可直接按下 C-n 或 C-p 对宏环进行轮换操作。
若正处于键盘宏定义状态, C-x C-k C-k 的功能与 F4 一致,区别在于执行该命令后,可直接使用本节的大部分快捷键,无需再次输入 C-x C-k 前缀。例如,直接按下 C-k 即可重新执行该宏。
命令 C-x C-k C-n (kmacro-cycle-ring-next) 和 C-x C-k C-p (kmacro-cycle-ring-previous) 用于轮换键盘宏环,将下一个 / 上一个键盘宏移至宏环的首位置,新的宏环首位置宏的定义内容会显示在回显区中。操作后可直接连续按下 C-n 或 C-p 继续轮换宏环,直至目标宏出现在宏环首位置;若要立即执行新的宏环首位置宏,直接按下 C-k 即可。
请注意,Emacs 将 宏环首位置的宏 视作最近定义的键盘宏。例如,按下 F4 会执行该宏,执行 C-x C-k n 可为该宏命名。
键盘宏环中可存储的宏的最大数量,由可自定义变量 kmacro-ring-max 决定。
19.3. 键盘宏计数器
每个键盘宏都配有一个关联的 计数器 ,启动宏定义时,该计数器会初始化为 0。借助这个当前计数器,你可以在缓冲区中插入一个数值,该数值会根据宏的调用次数动态变化。默认情况下,每当计数器的数值被插入缓冲区时,其值会自动递增。
除当前计数器外,键盘宏还会维护一个 历史计数器 ,用于记录当前计数器上一次被递增或设置时的数值。请注意,若将当前计数器的递增值设为 0(例如执行 C-u 0 C-x C-k C-i ),当前计数器的数值也会被记录为历史计数器的数值。
F3- 在键盘宏定义过程中,将键盘宏计数器的当前值插入缓冲区 (
kmacro-start-macro-or-insert-counter) 。 C-x C-k C-i- 将键盘宏计数器的当前值插入缓冲区 (
kmacro-insert-counter) 。 C-x C-k C-c- 设置键盘宏计数器的数值 (
kmacro-set-counter) 。 C-x C-k C-a- 将前缀参数的值累加至键盘宏计数器 (
kmacro-add-counter) 。 C-x C-k C-f- 指定键盘宏计数器的插入格式 (
kmacro-set-format) 。
在定义键盘宏时,执行命令 F3 (kmacro-start-macro-or-insert-counter) 会将该宏计数器的当前值插入缓冲区,且计数器值自动加 1。(若未处于宏定义状态, F3 的功能为启动宏定义,详见「基础使用」章节。)你可以通过指定数字前缀参数,设置非 1 的自定义递增值;若仅指定 C-u 作为前缀,该操作会插入 历史计数器 的数值,且不会修改当前计数器的数值。
以下举例说明如何使用键盘宏计数器制作带编号的列表,执行如下按键序列即可实现:
F3 C-a F3 . SPC F4
在该键盘宏的定义过程中,字符串 '0. ' 会被插入当前行首。若此时将光标移至缓冲区其他位置,按下 F4 调用该宏,目标行首会插入字符串 '1. ';后续每一次调用宏,会依次插入'2. '、'3. ',依此类推。
命令 C-x C-k C-i (kmacro-insert-counter) 的功能与宏定义中的 F3 完全一致,且可在 宏定义之外 的场景使用。当未定义或执行任何键盘宏时,该命令会插入 键盘宏环首位置 对应宏的计数器值,并完成计数器的递增。
命令 C-x C-k C-c (kmacro-set-counter) 可将当前宏计数器的数值设为前缀参数指定的数字。若在宏内部执行该命令,其设置会作用于宏的每一次重复执行;若在宏执行过程中仅指定 C-u 作为前缀,该操作会将计数器重置为 本次宏迭代开始 时的数值,撤销本次迭代中对计数器的所有递增操作。
命令 C-x C-k C-a (kmacro-add-counter) 会将前缀参数的数值累加至当前宏计数器。若仅指定 C-u 作为参数,该操作会将计数器重置为 任意键盘宏上一次插入的数值 (通常情况下,该数值为当前宏上一次插入的计数器值)。
命令 C-x C-k C-f (kmacro-set-format) 会通过迷你缓冲区提示你输入计数器的 插入格式字符串 ,默认格式为 '%d' ,表示以无补位的十进制形式插入数字。若在迷你缓冲区中直接回车,可将格式重置为该默认值。你可以输入 format 函数支持的任意格式字符串,且该字符串需适配 单个整数 作为额外参数的使用场景(详见《Emacs Lisp 参考手册》中的「格式化字符串」章节)。在迷你缓冲区中输入格式字符串时, 无需添加双引号 。
若在未定义或执行任何键盘宏时执行该命令,新设置的格式会作用于 后续所有新建的宏 ,已存在的宏仍会使用其定义时生效的格式;若在定义键盘宏的过程中设置格式,该设置仅对 当前正在定义的宏 从设置节点开始生效,不会影响其他宏。宏执行时,每一步的计数器插入都会使用 其定义时对应步骤生效的格式 ;在宏执行过程中修改计数器格式,与在宏定义过程中修改的效果一致,均不会影响其他宏。
通过 C-x C-k C-f 设置的格式, 不会影响 寄存器中存储数值的插入方式。
你也可以将寄存器用作计数器,在宏的每一次重复执行中实现递增,其效果与键盘宏计数器完全一致(详见「在寄存器中保存数字」章节)。但对于绝大多数使用场景,直接使用键盘宏计数器会更简便。
19.4. 带变量的宏执行(Executing Macros with Variations)
在键盘宏中,你可以实现类似 query-replace 查询替换的效果,让宏在每次执行时都向你确认是否执行修改操作。
C-x q- 宏执行至该位置时,弹出确认提示 (
kbd-macro-query) 。
定义宏时,在需要触发确认的位置按下 C-x q 即可。宏定义过程中,该按键不会产生任何效果;但后续执行该宏时,运行到该位置会弹出交互式确认,询问是否继续执行。
当 C-x q 触发确认时,可输入以下有效响应:
SPC(ory)- 继续执行该键盘宏。
DEL(orn)- 跳过本次宏迭代的剩余操作,直接开始下一次迭代。
RET(orq)- 跳过本次宏迭代的剩余操作,并取消后续所有宏迭代。
C-r- 进入递归编辑模式,可在该模式下执行非宏定义内的编辑操作。使用
C-M-c退出递归编辑后,会再次弹出宏执行的确认提示;此时按下SPC空格,将继续执行该宏的剩余定义操作。你需要自行保证退出递归编辑时,光标和文本的状态能让宏的后续操作达到预期效果。
带前缀参数的 C-u C-x q ,功能与普通的 C-x q 完全不同。无论是在 宏定义过程中 按下该组合键,还是在 宏执行过程中 触发该操作,都会进入递归编辑模式并从键盘读取输入。
- 宏定义阶段:在该递归编辑中执行的操作, 不会被记录到宏定义 中;
- 宏执行阶段:该递归编辑为每次宏迭代提供了执行 个性化编辑操作 的机会。详见「递归编辑层级」章节。
19.5. 键盘宏的命名与保存
C-x C-k n- 为最近定义的键盘宏指定命令名(有效期为当前 Emacs 会话) (
kmacro-name-last-macro) 。 C-x C-k b- 将最近定义的键盘宏绑定至某一按键序列(有效期为当前会话)(
kmacro-bind-to-key) 。 M-x insert-kbd-macro- 将键盘宏的定义以 Lisp 代码形式插入缓冲区。
若你希望保存键盘宏以供后续使用,可通过 C-x C-k n (kmacro-name-last-macro) 为其命名。该命令会通过迷你缓冲区读取一个名称作为参数,并将该名称定义为执行当前形式的最新键盘宏的指令(若后续你为该宏追加了新的定义内容,此命名对应的宏定义 不会 随之改变)。宏的名称为 Lisp 符号,通过此方式定义后,该名称将成为有效的命令名,可通过 M-x 调用,也可通过 keymap-global-set 为其绑定按键(详见「键盘映射」章节)。若你指定的名称已有非键盘宏类型的原有定义,系统会弹出错误提示,且不会对原有设置做任何修改。
你也可使用 C-x C-k b (kmacro-bind-to-key) 将最新的键盘宏(当前形式)绑定至指定按键序列,执行该命令后输入想要绑定的按键序列即可。该命令可将宏绑定至全局键盘映射中的任意按键序列,但由于多数按键序列已有其他绑定功能,你需要谨慎选择。若你尝试绑定的按键序列在任意键盘映射中已有绑定,该命令会在替换原有绑定前向你确认。
为避免因覆盖原有绑定引发问题, C-x C-k 0 至 C-x C-k 9 以及 C-x C-k A 至 C-x C-k Z 这些按键序列被预留出来,专供你绑定自定义键盘宏使用。实际上,绑定这类预留按键序列时,你只需输入对应的数字或字母,无需输入完整的按键序列。例如:
C-x C-k b 4
该操作会将最新的键盘宏绑定至按键序列 C-x C-k 4 。
当键盘宏拥有命令名后,你可将其定义保存至文件中,以便在其他编辑会话中使用。操作步骤如下:
- 打开你想要保存宏定义的文件;
- 执行命令:
M-x insert-kbd-macro RET macroname RET
该命令会在缓冲区中插入一段 Lisp 代码,这段代码在后续执行时,会定义出与当前宏完全一致的键盘宏(你无需理解 Lisp 代码,因为 insert-kbd-macro 会自动为你生成对应的代码)。之后保存该文件即可,后续可通过 load-file 命令加载此文件(详见「Emacs 的 Lisp 代码库」章节)。若你将宏定义保存至初始化文件 ~/.emacs 中(详见「Emacs 初始化文件」章节),则每次启动 Emacs 时,该宏都会被自动定义。
若为 insert-kbd-macro 指定前缀参数,该命令会额外生成一段 Lisp 代码,记录你为该宏名绑定的所有按键(若有),这样在你加载文件时,该宏会被重新分配至原有绑定的按键
19.6. 编辑键盘宏
C-x C-k C-e- 编辑最近定义的键盘宏 (
kmacro-edit-macro) 。 C-x C-k e 宏名 RET- 编辑已定义的指定名称的键盘宏 (
edit-kbd-macro) 。 C-x C-k l- 将最近的 300 次按键操作作为键盘宏进行编辑 (
kmacro-edit-lossage) 。
按下 C-x C-k C-e 或 C-x C-k RET (kmacro-edit-macro) ,即可编辑最近定义的键盘宏。该命令会将宏的定义格式化后展示在专属缓冲区中,并进入编辑宏的专用主模式。在该缓冲区中按下 C-h m ,可查看编辑宏的详细操作说明;编辑完成后,按下 C-c C-c 即可保存修改并退出编辑。
kmacro-edit-macro 所使用的 edmacro-mode (宏编辑主模式)提供了一系列便捷命令,用于编辑格式化后的宏定义:按下 C-c C-q (edmacro-insert-key) ,可将后续输入的按键序列按正确格式插入缓冲区,功能与 C-q (quoted-insert) 类似;按下 C-c C-r (edmacro-set-macro-to-region-lines) ,可将选中区域的文本替换为宏的定义内容。若选中的区域并非从行首开始或至行尾结束,该命令会自动扩展区域以包含完整行;若区域结束于某行的行首,则该最后一行不会被纳入替换范围。
若要编辑已命名的键盘宏,或绑定至按键的键盘宏,可按下 C-x C-k e (edit-kbd-macro) ,随后输入调用该宏的方式即可 —— 无论是 C-x e 、 M-x name ,还是其他绑定的按键序列均可。
按下 C-x C-k l (kmacro-edit-lossage) ,可将最近的 300 次按键操作提取出来,作为键盘宏进行编辑。默认情况下,最新的按键操作会显示在缓冲区的末尾;若将变量 edmacro-reverse-macro-lines 设为 t ,宏的按键序列会以倒序形式展示。
19.7. 逐步编辑键盘宏(Stepwise Editing a Keyboard Macro)
按下 C-x C-k SPC (kmacro-step-edit-macro) ,来交互式地逐步重放并编辑上一个键盘宏,每次处理一条命令。除非你按下 q 或 C-g 退出宏编辑,否则编辑后的宏将替换宏环中最新的那个宏。
该宏编辑功能会在迷你缓冲区中显示最新的宏定义,同时标注即将执行的第一条(或下一条)命令,并弹出提示让你选择执行操作。输入 '?' 可查看所有操作选项的说明,可用操作如下:
SPC、y- 执行当前命令,并跳至键盘宏中的下一条命令。
n、d、DEL- 跳过并删除当前命令。
f- 在本次宏执行中跳过当前命令,但不将其从宏定义中删除。
TAB- 执行当前命令,同时执行紧随其后的所有同类命令;例如,可使用
TAB执行一串字符的插入操作(对应连续的自插入命令)。 c- 继续执行宏(不再进行后续编辑),直至宏定义结束。若执行正常终止,编辑后的宏将替换原宏。
C-k- 跳过并删除键盘宏中剩余的所有命令,终止逐步编辑,并用编辑后的宏替换原宏。
q、C-g- 取消键盘宏的逐步编辑,丢弃对宏所做的所有修改。
i key.. C-j- 读取并执行一串按键序列(不包含最后的
C-j),将其插入到键盘宏中当前命令的前方,且不跳至下一条命令。 I key..- 读取并执行一个按键序列,将其插入到键盘宏中当前命令的前方,且不跳至下一条命令。
r key.. C-j- 读取并执行一串按键序列(不包含最后的
C-j),用其替换键盘宏中的当前命令,并跳至插入的按键序列之后。 R key..- 读取并执行一个按键序列,用其替换键盘宏中的当前命令,并跳至插入的按键序列之后。
a key.. C-j- 先执行当前命令,再读取并执行一串按键序列(不包含最后的
C-j),将其插入到键盘宏中当前命令的后方;随后跳至当前命令与插入序列之后的下一条命令。 A key.. C-j- 先执行键盘宏中剩余的所有命令,再读取并执行一串按键序列(不包含最后的
C-j),将其追加至键盘宏的末尾;随后终止逐步编辑,并用编辑后的宏替换原宏。
19.8. 列出与编辑键盘宏
执行命令 M-x list-keyboard-macros RET ,即可显示现有所有键盘宏的列表。该命令会在名为 *Keyboard Macro List* 的缓冲区中弹出 Kmacro Menu 宏操作菜单 ,列表中每一行对应一个宏,展示其位置编号、计数器值、计数器格式、格式化后的计数值以及宏的按键序列。以下是宏列表的示例:
Position Counter Format Formatted Keys 0 8 %02d 08 N : SPC <F3> RET 1 0 %d 0 l o n g SPC p h r a s e
宏列表的排序规则为:当前最新的宏排在顶部,位置编号为 0,其余旧宏按 键盘宏环 中的存储顺序依次排列(详见「键盘宏环」章节)。通过该宏操作菜单,你可调整宏的排序、修改宏的计数器值、计数器格式及按键序列。此菜单所在的缓冲区为只读模式,仅能通过本节介绍的专用命令进行修改。执行任意修改命令后,宏操作菜单会实时刷新,展示宏属性和宏环的最新状态。在该缓冲区中,既可使用 Emacs 常规的光标移动命令,也可使用菜单专属的导航命令;按下 C-h m 或 '?' (describe-mode) ,即可查看所有专用命令的说明。
你可使用以下命令修改宏的属性(操作时光标置于对应宏的行上即可):
#- 修改当前行对应宏在宏环中的位置编号(详见「键盘宏环」章节)。
C-x C-t- 将当前行的宏上移一行,功能与文本行交换命令
transpose-lines一致。 c- 修改当前行对应宏的计数器值(详见「键盘宏计数器」章节)。
f- 修改当前行对应宏的计数器格式。
e- 调用
edit-kbd-macro命令,编辑当前行对应宏的按键序列(详见「编辑键盘宏」章节)。 RET- 修改当前光标所在列对应的宏属性,自动调用上述对应属性的修改命令。
以下命令用于在列表中删除或复制宏:
d- d(宏操作菜单专用)
- 为当前行的宏标记删除标识,随后光标移至下一行 (
kmacro-menu-flag-for-deletion) 。行首出现字符D即表示标记成功,标记的宏仅在执行x命令后才会被真正删除(见下文)。若当前存在激活的选中区域,该命令会为区域内所有宏标记删除标识。 x- x (宏操作菜单专用)
- 删除列表中所有已标记删除标识的宏 (
kmacro-menu-do-flagged-delete) 。 m- m(宏操作菜单专用)
- 为当前行的宏添加标记,随后光标移至下一行 (
kmacro-menu-mark) 。行首出现字符 '*' 即表示标记成功,已标记的宏可被C和D命令批量操作(见下文)。若当前存在激活的选中区域,该命令会为区域内所有宏添加标记。 C- C(宏操作菜单专用)
- 复制宏,在宏当前的列表位置插入副本 (
kmacro-menu-do-copy) 。例如,对位置 0 的宏执行该命令,会在位置 1 插入其副本,原位置 1 及之后的宏均顺次下移。若存在激活的选中区域,批量复制区域内所有宏;若无选中区域但有已标记的宏,批量复制所有标记宏;若既无选中区域也无标记宏,仅复制当前行的宏。前两种批量复制的场景下,命令会先弹出确认提示,确认后再执行复制。 D- D(宏操作菜单专用)
删除宏并将其从宏环中移除 (
kmacro-menu-do-delete) 。例如,对位置 0 的宏执行该命令,会删除该宏,原位置 1 的宏将成为新的当前宏并移至位置 0,同时从宏环中弹出。若存在激活的选中区域,批量删除区域内所有宏;若无选中区域但有已标记的宏,批量删除所有标记宏;若既无选中区域也无标记宏,仅删除当前行的宏。所有场景下,命令都会先弹出确认提示,确认后再执行删除。
该命令是
d和x删除方式的替代方案。u- u(宏操作菜单专用)
- 取消当前行宏的标记和删除标识,随后光标下移至下一行 (
kmacro-menu-unmark) 。若存在激活的选中区域,取消区域内所有宏的标记和删除标识。 DEL- DEL (宏操作菜单专用)
- 功能与
u命令一致(见上文);若当前无激活的选中区域,操作后光标会上移至上一行 (kmacro-menu-unmark-backward) 。 U- U(宏操作菜单专用)
- 取消列表中所有宏的标记和删除标识 (
kmacro-menu-unmark-all) 。
20. 文件处理
操作系统将数据永久存储在命名 files文件 中,因此你使用 Emacs 编辑的大部分文本都来自文件,最终也会保存到文件中。
要编辑文件,你需要让 Emacs 读取该文件并创建一个包含文件文本副本的缓冲区,这一操作称为 visiting 访问 文件。编辑命令直接作用于缓冲区中的文本,即 Emacs 内部的这份副本;只有当你将缓冲区内容回存到文件时,所做的修改才会体现在文件本身中。
除了访问和保存文件,Emacs 还支持删除、复制、重命名、追加文件内容,保留文件的多个版本,以及对文件目录进行操作。
20.1. 文件名
Emacs 中许多对文件执行操作的命令,都需要你通过迷你缓冲区指定文件名(参见《文件名与迷你缓冲区》章节)。
在迷你缓冲区中,你可以使用常规的补全和历史记录命令(参见《迷你缓冲区》章节)。注意,文件名补全会忽略扩展名出现在变量 completion-ignored-extensions 中的文件(参见《补全选项》章节)。此外,大多数读取文件名的命令会采用 带确认的宽松补全 方式:你可以输入不存在的文件名,但如果在补全到一个不存在的文件名后直接按下 RET 回车键,Emacs 会显示 '[Confirm 确认]',你需要再次按下 RET 回车键完成确认。详细说明参见《补全的退出方式》章节。
迷你缓冲区的历史记录命令在读取文件名时提供了一些特殊功能,参见《迷你缓冲区历史记录》章节。
每个缓冲区都有一个 default directory默认目录 ,存储在缓冲区局部变量 default-directory 中。每当 Emacs 通过迷你缓冲区读取文件名时,通常会将默认目录作为初始内容插入到迷你缓冲区中。你可以将变量 insert-default-directory 设为nil,禁止该插入行为(参见《文件名与迷你缓冲区》章节)。无论是否插入默认目录,Emacs 始终将所有相对文件名解析为相对于默认目录的路径,例如,输入不带目录的文件名,即表示默认目录下的该文件。
当你访问一个文件时,Emacs 会将该访问缓冲区的 default-directory 设为该文件所在的目录。当你通过 C-x b 这类命令创建一个未访问任何文件的新缓冲区时,其默认目录通常会从创建时的当前缓冲区复制而来(参见《缓冲区的创建与选择》章节)。你可以使用命令 M-x pwd 查看当前缓冲区的 default-directory 值。命令 M-x cd 会提示你输入目录名,并将当前缓冲区的 default-directory 设为该目录(此操作不会改变缓冲区对应的文件名,若有)。
举个例子,当你访问文件 /u/rms/gnu/gnu.tasks 时,默认目录会被设为 /u/rms/gnu/ 。此时若调用一个读取文件名的命令,在迷你缓冲区中仅输入 'foo' (省略目录),表示文件 /u/rms/gnu/foo ;输入 '../.login' ,表示文件 /u/rms/.login ;输入 'new/foo' ,表示文件 /u/rms/gnu/new/foo 。
在迷你缓冲区中输入文件名时,你可以使用两个快捷方式: //双斜杠 会忽略该双斜杠中第二个斜杠之前的所有内容, '~/' 则代表你的 主目录 。参见《文件名与迷你缓冲区》章节。
字符 '$' 用于在文件名中 替换环境变量 。环境变量名由 '$' 之后的所有字母数字字符组成;你也可以将环境变量名用大括号包裹后跟在 '$' 之后。例如,若你通过 Shell 命令输入 export FOO=rms/hacks 设置了名为 FOO 的环境变量,那么 /u/$FOO/test.c 和 /u/${FOO}/test.c 均是 /u/rms/hacks/test.c 的简写形式。如果该环境变量未定义,则不会进行替换,字符 '$' 将按原义保留。注意,在 Emacs 外部设置的环境变量,只有在 Emacs 启动前生效,才会对 Emacs 产生影响。
若要访问的文件名中包含 '$' 字符,且并且你不希望它被当作环境变量展开,可输入 '$$' 。在对单个 '$' 执行变量替换的同时,这 2 个 '$' 会被转换为 1 个 '$' 。你也可以使用 '/:' 将整个文件名引起来(参见《引用文件名》章节)。以字面量 '~' 开头的文件名,同样需要用 '/:' 引用。
你可以在文件名中包含非 ASCII 字符,参见《文件名的编码系统》章节。
20.2. 打开文件(Visiting Files)
C-x C-f- 访问文件 (
find-file) - (no term)
C-x C-r::以只读方式访问文件,禁止修改 (find-file-read-only)C-x C-v- 替换访问另一个文件,替代上一次访问的文件 (
find-alternate-file) C-x 4 f- 在另一个窗口中访问文件 (
find-file-other-window) ,不改变当前选中窗口的显示内容 C-x 5 f- 在新框架中访问文件 (
find-file-other-frame) ,不改变当前选中框架的显示内容 M-x find-file-literally- 以无格式转换的方式访问文件,不处理文件内容的任何转换
访问文件指将文件内容读取到 Emacs 缓冲区中,以便进行编辑操作。Emacs 会为每个访问的文件创建一个新的缓冲区。
要访问文件,输入 C-x C-f (find-file) ,并通过迷你缓冲区输入目标文件名。在迷你缓冲区中,可输入 C-g 终止该命令。关于在迷你缓冲区中输入文件名的详细说明,参见《文件名》章节。
若指定的文件存在但系统禁止你读取,回显区会显示错误信息(在 GNU 和 Unix 系统中,你可通过 su 或 sudo 方式访问此类文件,参见《远程文件》章节)。若访问成功,屏幕会显示文件的新文本,模式行也会显示对应的缓冲区名称(参见《模式行》章节)。Emacs 通常会从文件名中提取缓冲区名,省略目录部分,例如访问文件 /usr/rms/emacs.tex 时,对应的缓冲区名为 emacs.tex 。若该名称的缓冲区已存在,Emacs 会生成一个唯一名称,默认方式是添加基于目录名的后缀(如 '<rms>' 、 '<tmp>' 等),你也可选择其他命名方式,参见《让缓冲区名唯一》章节。
创建新文件可直接使用相同的命令 C-x C-f ,只需输入新的文件名即可。此时回显区会显示 '(New file)' ,其余操作与访问一个已存在的空文件完全一致。
访问文件后,所有编辑命令产生的修改都仅作用于 Emacs 缓冲区,直到你保存缓冲区,修改才会同步到实际的文件中(参见《保存文件》章节)。若缓冲区包含未保存的修改,我们称该缓冲区已修改,此时若未保存就关闭缓冲区,修改将会丢失。模式行左侧的两个星号 '**' 是缓冲区已修改的标识。
若你访问的文件已在 Emacs 中打开, C-x C-f 不会创建新的缓冲区副本,而是直接切换到已存在的缓冲区。在此之前,Emacs 会检查该文件自上次访问或保存后是否被外部修改,若已修改,会提示你重新读取文件内容。
若你尝试访问的文件大小超过变量 large-file-warning-threshold 的取值(默认值为 10000000,约 10MB),Emacs 会先请求你的确认。输入 y 可继续正常访问文件,输入 l 则以无格式转换方式访问文件(详见下文)。以无格式转换方式访问大文件能提升导航和编辑速度,因为该方式会关闭各类可能占用大量资源的功能。请注意,Emacs 无法访问超过 最大缓冲区 大小的文件,该限制由 Emacs 可分配的内存空间和可表示的整数范围决定(参见《使用多个缓冲区》章节),若尝试访问,回显区会显示 “超出最大缓冲区大小” 的错误信息。
若你尝试访问的文件,其对应的主模式(参见《主模式》章节)会使用树分析解析库(tree-sitter),当文件字节大小超过变量 treesit-max-buffer-size 的取值时,Emacs 会发出警告。该变量默认值:64 位 Emacs 为 40MB,32 位 Emacs 为 15MB。此限制是为了避免 Emacs 内存耗尽,因为大缓冲区中基于 tree-sitter 的主模式会被禁用 —— 典型的 tree-sitter 解析器所需的内存约为其解析文本大小的 10 倍。
若你输入的文件名包含 Shell 风格的通配符,Emacs 会访问所有匹配该通配符的文件(在不区分大小写的文件系统中,通配符匹配会忽略字母大小写)。通配符包括 '?' 、 '*' 和 '[…]' 序列。若要在迷你缓冲区中输入作为文件名一部分的通配符 '?' ,需输入 C-q ? 进行转义。若文件名本身包含通配符,关于其访问方法参见《引用文件名》章节。你可通过自定义变量 find-file-wildcards 禁用通配符匹配功能。
若你尝试访问的文件已在某个缓冲区中打开,但该文件被外部程序修改,Emacs 通常会询问你是否从磁盘重新读取文件。若你将变量 query-about-changed-file 设为 nil ,Emacs 不会发出询问,而是继续显示缓冲区中修改前的内容,并在回显区提示你如何从文件恢复缓冲区内容。
若你因输错文件名意外访问了错误的文件,可输入 C-x C-v (find-alternate-file) 访问实际需要的文件。 C-x C-v 与 C-x C-f 功能类似,但会先关闭当前缓冲区(若缓冲区已修改,会先提示你保存)。当 C-x C-v 读取待访问的文件名时,会将完整的默认文件名插入迷你缓冲区,且光标定位在目录部分之后,若你仅输错了文件名的小部分,该方式会非常便捷。
若你尝试访问的文件实际是一个目录,Emacs 会调用目录编辑器 Dired(Emacs 目录浏览器),参见《目录编辑器 Dired》章节。你可将变量 find-file-run-dired 设为 nil 禁用该行为,此时尝试访问目录会被视为错误操作。
对于实际为文件集合的归档文件,Emacs 会以特殊模式打开,该模式会调用类 Dired 的操作环境,支持对归档内的成员文件进行操作,关于该功能的详细说明参见《文件归档》章节。
若你访问的文件被操作系统禁止修改,或被标记为只读,Emacs 会将对应的缓冲区也设为只读,避免你进行修改后无法保存。你可使用 C-x C-q (read-only-mode) 将只读缓冲区改为可写,参见《各类缓冲区操作》章节。
若你希望以只读方式访问文件,防止意外修改,可使用 C-x C-r (find-file-read-only) 替代=C-x C-f= 。
C-x 4 f (find-file-other-window) 与 C-x C-f 功能类似,区别在于该命令会在 另一个窗口 中选中目标文件的缓冲区,执行该命令前的当前窗口会保持原有缓冲区的显示。若执行该命令时仅存在一个窗口,Emacs 会将该窗口拆分为两个,一个窗口保持原有内容,另一个窗口显示新访问的文件,参见《多个窗口》章节。
C-x 5 f (find-file-other-frame) 与上述命令类似,区别在于该命令会在 新框架 中打开文件,或选中已显示该文件的现有框架,参见《框架与图形化显示》章节。
在图形化显示界面中,还有两种额外的文件访问方式:
- 若 Emacs 基于合适的 GUI 工具包编译,通过鼠标调用的命令(点击菜单栏或工具栏)会使用工具包的标准文件选择对话框,而非通过迷你缓冲区提示输入文件名。在 GNU/Linux 和 Unix 平台,基于 GTK+、LessTif 和 Motif 工具包编译的 Emacs 支持该功能;在 MS-Windows 和 Mac 系统,GUI 版本的 Emacs 默认支持该功能。关于该功能的自定义方法,参见《使用对话框》章节。
- Emacs 支持拖放操作 :将文件拖入普通的 Emacs 窗口,该窗口会直接访问该文件。例外情况:将文件拖入显示 Dired 缓冲区的窗口,会将该文件移动或复制到该窗口显示的目录中。详细说明参见《拖放操作》和《Dired 的其他功能》章节。
在文本模式终端中,或在未基于 GUI 工具包编译的 Emacs 图形化显示界面中,你可通过菜单栏的「文件(File)」菜单访问文件,该菜单包含「访问新文件(Visit New File)」和「打开文件(Open File)」选项。
每次访问文件时,Emacs 会自动扫描文件内容,检测其使用的字符编码和行尾格式,并在缓冲区中将其转换为 Emacs 内部的编码和行尾格式。当你保存缓冲区时,Emacs 会执行反向转换,将文件以原始的编码和行尾格式写入磁盘,参见《编码系统》章节。
若你希望将文件作为纯 ASCII 字符序列编辑,不进行任何特殊的编码或格式转换,可使用 M-x find-file-literally 命令。该命令与 C-x C-f 一样用于访问文件,但不会执行格式转换(参见《Emacs Lisp 参考手册》中的《格式转换》)、字符编码转换(参见《编码系统》)和自动解压缩(参见《访问压缩文件》),也不会因变量require-final-newline的设置为文件添加末尾换行符(参见《自定义文件保存方式》)。若你已以常规(非无格式转换)方式访问过同一文件,该命令会询问你是否改为以无格式转换方式访问。
某些文件之间会存在松散的关联关系,这类文件被称为 sibling files兄弟文件 。例如编辑 C 语言文件时,若存在文件 "foo.c" ,通常会对应一个头文件 "foo.h" ,该头文件即为其兄弟文件;同一文件的不同版本也可视为兄弟文件,例如 "src/emacs/emacs-27/lisp/allout.el" 和 "src/emacs/emacs-28/lisp/allout.el" 。Emacs 提供了 find-sibling-file 命令用于在兄弟文件之间跳转,但无法默认推测用户希望哪些文件互为兄弟文件,因此你可通过修改用户选项 find-sibling-rules 自由配置,该选项是一个由「匹配 / 扩展」规则组成的列表。
例如,要实现从 ".c" 文件到 ".h" 文件的映射,可进行如下配置:
(setq find-sibling-rules '(("\\([^/]+\\)\\.c\\'" "\\1.h")))
(ff-find-related-file 命令也提供类似功能,该命令专为 C 语言文件设计,参见《C 模式的其他命令》章节。)
又如,若你希望将 "src/emacs/DIR/file-name" 目录下的所有文件视为其他同层级目录下同名文件的兄弟文件,可配置:
(setq find-sibling-rules '(("src/emacs/[^/]+/\\(.*\\)\\'" "src/emacs/.*/\\1")))
如上所示,该选项的每一条规则均为 (MATCH EXPANSION...) 的形式。其中 match匹配规则 是匹配已访问文件名的正则表达式, expansion扩展规则 可通过 '\\1' 、 '\\2' 等引用匹配规则中的捕获组。Emacs 会将扩展后的字符串作为正则表达式,在文件系统中匹配符合条件的文件。
有两个特殊的钩子变量可扩展文件访问的操作逻辑:
- 访问不存在的文件时,Emacs 会执行
find-file-not-found-functions中的所有函数。该变量是一个函数列表,函数会被依次调用(无参数),直到某个函数返回非nil值。这并非普通钩子,变量名以 '-functions' 而非 '-hook' 结尾,正是为了区分这一特性。 - 成功访问任意文件(无论文件是否存在)后,Emacs 会无参数调用
find-file-hook中的所有函数,该变量是一个 普通钩子 。若访问的是不存在的文件,会先执行find-file-not-found-functions中的函数,再执行该钩子。关于钩子的详细说明参见《钩子》章节。
你可通过多种方式为文件自动指定编辑所用的主模式(参见《选择文件模式》),也可为文件指定专属的局部变量(参见《文件中的局部变量》)。
20.3. 保存文件
在 Emacs 中保存缓冲区,指将缓冲区的内容回写到其对应的源文件中。
20.3.1. 保存文件命令
以下是与文件的保存和写入相关的命令。
C-x C-s- 将当前缓冲区保存至对应文件 (
save-buffer) C-x s- 保存任意或全部已修改的缓冲区至各自对应文件 (
save-some-buffers) M-~- 清除当前缓冲区的已修改标记 (
not-modified);带前缀参数(C-u)时,标记当前缓冲区为已修改状态 C-x C-w- 将当前缓冲区以指定文件名保存 (
write-file),即另存为 M-x set-visited-file-name- 修改当前缓冲区后续保存时对应的文件名
M-x rename-visited-file- 功能与
M-x set-visited-file-name一致,同时会重命名缓冲区正在访问的原文件(若存在)
若你希望保存文件并让修改永久生效,输入 C-x C-s (save-buffer) 即可。保存完成后,该命令会在回显区显示如下提示信息:
Wrote /u/rms/gnu/gnu.tasks
若当前缓冲区未被修改(自缓冲区创建或上次保存后无任何更改),则不会实际执行保存操作 —— 因为此操作无任何实际效果,取而代之的是, C-x C-s 会在回显区显示:
(No changes need to be saved)
带前缀参数执行 C-u C-x C-s 时,Emacs 会标记该缓冲区,使其在 下一次保存时生成备份文件 ,相关说明参见《备份文件》章节。
C-x s (save-some-buffers) 命令会逐个询问是否保存已修改的缓冲区,你可对每个缓冲区选择对应的操作,可选响应与查询替换的操作方式类似:
ySPC- 保存当前缓冲区,继续询问其余缓冲区
nDEL- 不保存当前缓冲区,继续询问其余缓冲区
!- 保存当前缓冲区及所有剩余缓冲区,后续不再询问
qRET- 终止
save-some-buffers命令,不再保存任何缓冲区 .- 保存当前缓冲区,直接退出
save-some-buffers命令,不再询问其余缓冲区 C-r- 查看当前正在询问的缓冲区内容;退出查看模式后,会回到
save-some-buffers的询问界面,重新发起该缓冲区的保存询问 C-f- 退出
save-some-buffers命令,直接切换至当前正在询问的缓冲区 d- 对比当前缓冲区与对应源文件的差异,可直观查看即将保存的修改内容(该操作会调用
diff-buffer-with-file命令,参见《文件对比》章节) C-h- 显示上述操作选项的帮助信息
你可自定义变量 save-some-buffers-default-predicate 的取值,以此控制 Emacs 会对哪些缓冲区发起保存询问。
退出 Emacs 的快捷键 C-x C-c 会调用 save-some-buffers 命令,因此也会弹出相同的保存询问。
若你修改了缓冲区但并不希望保存这些更改,需执行相关操作避免误保存;否则每次使用 C-x s 或 C-x C-c 时,都有可能误保存该缓冲区。你可执行的操作之一是输入 M-~ (not-modified) ,该命令会清除缓冲区的已修改标识,此后所有保存命令都会判定该缓冲区无需保存(符号 '~' 在数学中常表示 “非”,因此 M-~ 可理解为 Meta键版的 “非” 操作)。此外,你也可通过重新从文件读取文本,撤销自访问或上次保存文件后做出的所有修改,该操作称为 恢复缓冲区 ,参见《恢复缓冲区》章节(你也可重复执行撤销命令 C-x u ,直至撤销所有修改,但恢复缓冲区的操作会更简便)。
M-x set-visited-file-name 命令用于修改当前缓冲区正在访问的文件名, 该命令会通过迷你缓冲区读取新的文件名 ,随后将缓冲区标记为访问该新文件,并相应修改缓冲区名称。该命令不会将缓冲区内容保存至新文件,仅会修改 Emacs 内部的记录,为后续的保存操作做准备;同时它会将缓冲区标记为已修改,确保你在该缓冲区执行 C-x C-s 时能触发保存。
若你希望将缓冲区标记为访问新文件并 立即保存 ,可使用 C-x C-w (write-file) 命令。该命令等效于先执行 set-visited-file-name ,再执行 C-x C-s ,区别在于:若指定的新文件已存在, C-x C-w 会先请求你的确认。若对一个未访问任何文件的缓冲区执行 C-x C-s ,其效果与 C-x C-w 一致 —— 会读取一个文件名,将缓冲区标记为访问该文件,并将内容保存至该文件。未访问任何文件的缓冲区,其默认文件名由 缓冲区名称 与 缓冲区默认目录 组合而成(参见《文件名》章节)。
在大多数情况下,若新文件名的后缀隐含了对应的主模式, C-x C-w 会自动将缓冲区切换至该主模式; set-visited-file-name 命令也具备此功能,相关说明参见《选择文件模式》章节。
若你希望将当前缓冲区内容保存至其他文件, 但不将缓冲区标记为访问该文件 ,可先执行 mark-whole-buffer ( C-x h )全选缓冲区内容,再执行 M-x write-region 命令(参见《各类文件操作》章节)。
当 Emacs 即将保存文件时,若检测到磁盘上该文件的最新修改时间,与 Emacs 上次读取或写入该文件的时间不一致,会立即向你发出提示。这一情况通常意味着文件被 同时编辑 并引发了问题,需要你及时处理,相关说明参见《同时编辑》章节。
20.3.2. 备份文件(Backup Files)
在大多数操作系统中,重写文件会直接清除该文件的原有内容记录。因此,从 Emacs 中保存文件本会覆盖文件的旧内容 —— 但实际不会,因为 Emacs 会在执行实际保存操作前,将文件旧内容妥善复制到另一个文件中,这个文件即为 backup file备份文件 。
Emacs 仅在从访问文件的缓冲区 首次保存该文件 时,为其创建备份文件。后续无论你对该文件执行多少次保存操作,其备份文件的内容都不会改变。但如果关闭该缓冲区后再次访问此文件,Emacs 会为其生成一个新的备份文件。
对于绝大多数文件,是否创建备份文件由变量 make-backup-files 决定。在多数操作系统中,该变量的默认值为 t ,即 Emacs 会自动生成备份文件。
对于由 版本控制系统 管理的文件(参见《版本控制》章节),是否创建备份文件由变量 vc-make-backup-files 决定。该变量默认值为 nil ,因为当所有历史版本都已存储在版本控制系统中时,备份文件属于冗余文件(参见《通用选项》章节)。
你可根据需要设置 Emacs,为每个文件仅保留 单个备份文件 ,或为编辑的每个文件生成一系列 带编号的备份文件 (参见《单备份与编号备份》小节)。
变量 backup-enable-predicate 的默认配置,会禁止为 临时文件目录 中的文件创建备份文件,临时文件目录由变量 temporary-file-directory 或 small-temporary-file-directory 指定。
即便缓冲区此前已执行过保存操作,你也可明确让 Emacs 为该缓冲区重新生成一个备份文件:
- 若通过
C-u C-x C-s保存缓冲区,当你再次保存该缓冲区时,此次保存的版本会被生成为新的备份文件; C-u C-u C-x C-s会先将文件原有内容生成为新的备份文件,再执行缓冲区的保存操作;C-u C-u C-u C-x C-s则会同时完成两项操作:将文件原有内容生成备份文件,且设置为 再次保存时 ,将本次新保存的内容也生成新的备份文件。
你可自定义变量 backup-directory-alist ,指定匹配特定模式的文件,在指定目录中创建备份文件。一种常用配置是向该变量添加元素 ("." . dir) ,让所有文件的备份都生成在绝对路径为 dir 的目录中。Emacs 会自动修改备份文件的名称,避免不同目录下同名文件的备份发生命名冲突。另一种配置是添加 ("." . ".~") ,将备份文件生成在原文件所在目录的隐藏子目录 '.~' 中,若该目录不存在,Emacs 会自动创建以完成备份。
20.3.2.1. 单一备份或编号备份
Emacs 创建备份文件时,默认的命名方式是在待编辑文件的文件名后追加符号 '~' ;例如,文件 eval.c 对应的备份文件为 eval.c~ 。
若因访问权限限制,Emacs 无法以常规名称创建备份文件,会将备份文件写入 ~/.emacs.d/%backup%~ 路径。该路径下仅能存在一个此类备份文件,因此仅可获取最近一次生成的该类备份。
Emacs 也支持 创建编号备份文件 ,其命名规则为在原文件名后添加 '.~' 、数字序号和另一个 '~' 。例如,文件 eval.c 的编号备份文件依次为 eval.c.~1~ 、 eval.c.~2~ ,序号可延续至 eval.c.~259~ 乃至更大的数字。
变量 version-control 用于控制 Emacs 生成单备份文件还是多个编号备份文件,其可选取值及对应规则如下:
nil- 若文件已有编号备份,则继续生成编号备份;否则生成单备份文件(默认取值)
t- 始终生成编号备份文件
never- 从不生成编号备份文件,始终生成单备份文件
该变量的常规配置方式为通过初始化文件或自定义缓冲区进行 全局设置 ;同时也可在单个缓冲区中进行局部设置,以控制该缓冲区对应文件的备份生成规则(参见《局部变量》章节)。部分模式(如 Rmail 模式)会自动设置该变量,也可在访问指定文件时,让 Emacs 自动为其设置该变量的局部取值(参见《文件中的局部变量》章节)。
若你设置了环境变量 VERSION_CONTROL (用于指定各类 GNU 工具的备份文件生成规则),Emacs 在启动时也会遵循该环境变量的配置,自动对应设置 Lisp 变量 version-control :
- 当环境变量值为
t或numbered时,Emacs 中version-control设为t - 当环境变量值为
nil或existing时,Emacs 中version-control设为nil - 当环境变量值为
never或simple时,Emacs 中version-control设为never - 若将变量
make-backup-file-name-function设为合适的 Lisp 函数,可覆盖 Emacs 默认的备份文件命名规则。
20.3.2.2. 备份文件的自动删除
为避免过度占用磁盘空间,Emacs 可自动删除编号备份文件的旧版本。通常情况下,Emacs 会保留编号最靠前的若干个备份和最新的若干个备份,将中间的所有备份文件删除。该清理操作会在 每次生成新备份文件时 执行。
备份文件的自动清理规则由两个变量控制: kept-old-versions 和 kept-new-versions 。二者的取值分别对应 每次生成新备份时 ,需要保留的最旧(编号最小)备份文件数量,以及需要保留的最新(编号最大)备份文件数量。处于两者之间的备份文件(即排除上述保留的最旧和最新备份后,剩余的中间备份)均为冗余的中间版本,会被自动删除。这两个变量的取值仅在新备份生成后、清理冗余版本时生效,且刚生成的新备份会被计入 kept-new-versions 的保留数量中。两个变量的默认值均为 2 。
若变量 delete-old-versions 的取值为 t ,Emacs 会在后台静默删除冗余的备份文件,不弹出任何提示;若取值为 nil (默认值),Emacs 会先询问你是否确认删除这些冗余备份版本,再执行后续操作;若为其他任意值,Emacs 则不会自动删除任何备份文件。
你也可使用 Dired 中的句点( . )命令手动删除备份旧版本,相关操作参见《批量标记文件》章节。
20.3.2.3. 复制备份与重命名备份
创建备份文件的方式分为 复制原文件 和 重命名原文件 两种。当原文件存在多个文件名(硬链接)时,两种方式的效果会截然不同:若将原文件重命名为备份文件,那么原文件的其他关联文件名会成为该备份文件的名称;若选择复制原文件生成备份,原文件的其他关联文件名仍指向你正在编辑的文件,通过这些文件名访问到的内容也会是文件的新内容。
备份方式的选择也会影响文件的属主和所属用户组:采用复制方式时,文件的属主和所属组不会发生变化;采用重命名方式时,你会成为文件的新属主,文件的所属组则会变为系统默认组(不同操作系统的默认组规则存在差异)。
Emacs 选择复制或重命名方式的判断逻辑如下:
- 若变量
backup-by-copying为非nil值(默认值为nil),采用复制方式。 - 若上述变量为
nil,但变量backup-by-copying-when-linked为非nil值(默认值为nil)且原文件存在多个硬链接文件名,采用复制方式。 若上述两个变量均为
nil,但变量backup-by-copying-when-mismatch为非nil值(默认值为t)且重命名会导致文件属主或所属组发生变化,采用复制方式。若将
backup-by-copying-when-mismatch设为nil,Emacs 会检查文件属主的用户ID和所属组ID:若其中任意一个 ID 的数值不大于变量backup-by-copying-when-privileged-mismatch的取值,Emacs 仍会按照backup-by-copying-when-mismatch为非nil的规则执行,即采用复制方式。- 若以上条件均不满足,默认采用重命名方式。
当文件由版本控制系统管理时(参见《版本控制》章节),Emacs 通常不会以常规方式为该文件创建备份。但向版本控制系统提交(也称作 checking in,参见《版本控制的基本概念》章节)文件的新版本,在某些方面与创建备份类似,其中一个弊端是:这类操作通常会破坏文件的硬链接,导致你所访问的文件名与该文件的其他关联文件名失去关联。该问题与 Emacs 无关,是由版本控制系统本身的操作导致的。
部分文件存储服务支持 文件版本管理功能 :会记录文件的历史版本,并允许恢复至任意历史版本。若你希望在 Emacs 中编辑这类服务托管的文件时,仍能使用该功能,可将变量 backup-by-copying 自定义为非nil值。
编辑重要文件时,采用复制原文件的方式创建备份也十分实用:这能确保即便在创建备份后、保存编辑内容前的过程中发生异常,原文件仍会保留其原始名称。此外,你也可将变量 file-precious-flag 设为非nil值,该设置会默认采用复制方式创建备份,同时还能在保存编辑内容时,防止出现 I/O 错误。
20.3.3. 文件保存定制
若变量 require-final-newline 的取值为 t ,在保存或写入文件时,若文件末尾无换行符,Emacs 会自动为其添加,且不弹出任何提示。若取值为 visit ,Emacs 仅在 访问文件后 ,为末尾无换行符的文件添加换行符(此操作会标记缓冲区为已修改状态,你可撤销该操作)。若取值为 visit-save ,则 Emacs 会在 访问文件和保存文件时 ,均执行上述末尾换行符的添加操作。若取值为 nil ,Emacs 不会修改文件末尾的内容;若为其他非nil值,Emacs 会先询问你是否添加换行符,再执行后续操作。该变量的默认值为 nil 。
部分主模式专为特定类型的文件设计,而这类文件通常要求末尾必须有换行符。此类主模式会将 require-final-newline 的取值设为变量 mode-require-final-newline 的取值,该变量默认值为 t 。你可通过修改 mode-require-final-newline ,控制这些主模式对文件末尾换行符的处理方式。
若该选项为非nil值,且你通过 符号链接 访问文件,当变量 file-precious-flag 也为非nil值时,Emacs 在保存缓冲区时会 断开该符号链接 ,并将缓冲区内容写入与该符号链接同名的实际文件中(关于 file-precious-flag 的更多说明,参见《Emacs Lisp 参考手册》)。若你希望此类场景下,Emacs 将缓冲区内容保存至符号链接 指向的原文件 (从而保留该符号链接),可将变量 file-preserve-symlinks-on-save 自定义为 t 。
通常情况下,程序写入文件时,操作系统会先将文件数据临时缓存至主内存,再将数据提交至二级存储设备。该机制虽能大幅提升性能,但存在数据丢失风险:若系统在缓存数据提交前断电,缓存中的数据会丢失;且在部分平台中,其他进程可能无法立即感知到文件的修改。
为降低该风险,Emacs 可在保存文件后调用 fsync 系统调用,强制将缓存数据写入二级存储。但使用 fsync 并不能完全消除数据丢失或修改通知延迟的问题,原因有二:一是许多系统并未对 fsync 提供完善支持;二是 Emacs 的文件保存流程通常还依赖于目录更新操作,即便 fsync 执行正常,这类目录更新也可能在系统崩溃时丢失。
变量 write-region-inhibit-fsync 用于控制 Emacs 是否在保存文件后调用 fsync ,该变量默认值为 t (即不调用)。
Emacs 在写入 自动保存文件 时,绝不会调用 fsync —— 因为这类文件本身就存在数据丢失的可能性。
20.3.4. 防止同时编辑冲突
同时编辑 指两名用户访问同一文件,双方均对文件做出修改并执行保存操作的情况。若未及时向用户告知该情况,先完成保存的一方,后续会发现其修改内容被覆盖丢失。
在部分系统中,当第二位用户开始修改文件时,Emacs 会立即检测到并发出警告;而在所有系统中,Emacs 都会在你执行保存操作时进行检查,若检测到你即将覆盖其他用户的修改,会及时弹出警告。此时你可执行相应的修正操作,而非直接保存文件,避免覆盖丢失其他用户的修改成果。
当你在访问某文件的 Emacs 缓冲区中做出 首次修改 时,Emacs 会记录该文件被你 锁定 (锁定的实现方式为:在该文件所在目录中创建一个命名特殊、内容特殊的符号链接 7,更多细节参见《Emacs Lisp 参考手册》中的文件锁定相关章节)。当你保存修改后,Emacs 会自动解除该文件的锁定。该机制的核心逻辑是: 当访问某文件的缓冲区存在未保存修改时,该文件会被锁定 。
你可将变量 create-lockfiles 设为 nil ,禁止 Emacs 创建锁定文件。注意:此操作会让你失去该功能带来的保护。你也可通过变量 lock-file-name-transforms ,控制锁定文件的存储位置。
若你尝试修改的文件,已被其他用户锁定,此时就会发生 collision锁定冲突 。Emacs 检测到冲突后,会调用 Lisp 函数 ask-user-about-lock ,向你询问处理方式;你也可重新定义该函数,实现自定义的冲突处理逻辑。该函数的标准定义会向你提出问题,并接受以下三种响应:
s- 抢占锁定。原持有该文件锁定的用户会失去锁定权限,锁定权限转移至你。
p- 继续编辑。无视其他用户的锁定,继续编辑该文件。
q- 退出操作。触发文件被锁定的错误(
file-locked),缓冲区内容保持不变 —— 你本次尝试做出的修改不会实际生效。
若 Emacs 程序或操作系统发生崩溃,可能会遗留一些 失效的锁定文件 ,导致你偶尔收到虚假的锁定冲突警告。当你确认该冲突为虚假冲突时,只需输入 p ,告知 Emacs 继续执行编辑操作即可。
请注意,文件锁定机制 基于文件名实现 :若一个文件拥有多个名称(如硬链接、符号链接),Emacs 无法阻止两名用户通过不同名称同时编辑该文件。
在某些情况下,Emacs 无法创建锁定文件,例如:Emacs 缺少对应的系统权限,或因其他原因无法生成锁定文件。即便如此,Emacs 仍能在你尝试保存文件时检测到冲突,检测方式为 检查文件的最后修改时间 :若该文件自 Emacs 上次访问或保存后,被其他方式修改过,此时执行保存会覆盖丢失这些修改。Emacs 会立即显示警告信息,并在保存前向你请求确认;输入 'yes' 则执行保存,输入 'no' 或按下 C-g 则取消保存操作。
若你收到通知,得知该文件已发生同时编辑,可使用 M-x diff-buffer-with-file 命令对比缓冲区内容与文件的实际内容,查看差异(参见《文件对比》章节)。
你可将变量 remote-file-name-inhibit-locks 设为 t ,禁止 Emacs 创建远程文件的锁定文件。
次要模式 lock-file-mode 可通过交互方式调用,用于切换当前缓冲区中 create-lockfiles 变量的局部取值。
20.3.5. 文件影子(Shadowing Files)
你可将指定文件的完全相同的 shadow copies影子副本 保存在多个位置,这些位置甚至可以在不同的计算机上。要实现该功能,首先你需要创建一个 shadow file group影子文件组 ,即一组在多个站点间共享、且文件名完全相同的文件构成的集合。该文件组为永久配置,不仅在当前 Emacs 会话中生效,在后续的 Emacs 会话中也同样有效。影子文件组创建完成后,每次退出 Emacs 时,程序都会将你编辑过的该文件,同步复制到其所属影子文件组中的其他文件位置。你也可以不退出 Emacs,直接输入 M-x shadow-copy-files 执行该同步复制操作。
shadow cluster影子集群 是一组共享目录的主机,因此向集群中的任一主机执行文件的复制操作,即可完成集群内所有主机上该文件的更新。每个影子集群都有专属名称,同时需要指定集群中 主主机 的网络地址(即文件的同步目标主机),以及一个能匹配集群中所有其他主机名的正则表达式。你可通过 M-x shadow-define-cluster 命令定义影子集群。
M-x shadow-initialize- 启用文件影子功能
M-x shadow-define-literal-group- 声明单个文件在多个站点间共享
M-x shadow-define-regexp-group- 将匹配指定正则表达式的所有文件,设为在多主机间共享的文件
M-x shadow-define-cluster RET 集群名 RET- 定义一个名为「集群名」的影子文件集群
M-x shadow-copy-files- 同步复制所有待处理的影子文件
M-x shadow-cancel- 取消部分文件的遮蔽同步指令
创建影子文件组可使用 M-x shadow-define-literal-group 或 M-x shadow-define-regexp-group 命令,更多使用细节可查阅这两个命令的文档字符串。
在将文件同步复制到其各影子副本位置前,Emacs 会向你请求确认。你可选择 "no" ,跳过本次该文件的同步复制操作。若你希望永久取消某个文件的影子同步功能,可使用 M-x shadow-cancel 命令,删除或修改该文件所属的影子文件组配置。
20.3.6. 自动更新时间戳
你可设置让文件中的 时间戳 在每次保存文件时自动更新(时间戳也可被称作日期戳或最后修改时间)。在文件文本中嵌入时间戳,能确保即便文件因被复制或转换而丢失文件系统层面的修改时间,文件的实际写入时间也能被留存。
设置自动时间戳功能需分两步操作:首先,需在文件的 前八行内 的任意位置添加一个时间戳模板,模板格式可写为:
Time-stamp: <>
也可按你的需求写成:
Time-stamp: " "
添加好该模板后,你可立即使用 M-x time-stamp 命令,一次性更新当前缓冲区的时间戳。Emacs 会自动检测文件中的模板,若找到模板,就会将当前的日期、时间、作者及其他信息填充到尖括号或双引号之间(若缓冲区中无此模板, time-stamp 命令将不执行任何操作)。生成首个时间戳后,该模板所在行可能会显示为:
Time-stamp: <1993-07-06 11:05:14 terryg>
其次,将 time-stamp 函数添加至 before-save-hook 钩子中,配置 Emacs 在每次保存文件时自动运行该函数(参见《钩子》章节)。你既可以使用 M-x customize-option 命令自定义 before-save-hook 选项(参见《自定义特定项》章节),也可以编辑你的初始化文件,添加如下配置行:
(add-hook 'before-save-hook 'time-stamp)
20.3.6.1. 时间戳定制
若要为特定文件自定义时间戳格式,可在该文件的 局部变量列表 中设置变量 time-stamp-pattern (参见《指定文件变量》章节)。通过该变量,你可以修改 time-stamp 命令匹配时间戳模板的规则,同时也能指定命令在文件中的模板查找范围;具体用法可查阅该变量的内置文档(使用 C-h v 命令,参见《通过命令或变量名获取帮助》章节)。
举一个简单的例子,若某文件的开头位置有如下内容:
publishing_year_and_city = "Published nnnn in Boston, Mass.";
那么在该文件末尾添加以下注释,即可告知 time-stamp 命令如何识别并更新这个自定义模板:
// Local Variables:
// time-stamp-pattern: "Published %Y in Boston"
// End:
该匹配规则表示,时间戳的前缀文本为 "Published" ,后缀文本为 "in Boston" 。如果 time-stamp 命令在文件 前八行 中找到同时包含这两段文本的内容,就会按照 %Y 的格式要求,将两段文本之间的内容替换为当前年份。
对文件局部变量完成任何修改后,需输入 M-x normal-mode 命令重新读取这些变量配置。
再举一个示例,将时间戳插入 HTML 文档的最后一个段落中。由于该模板位于文档末尾,而非文件前八行,因此在 time-stamp-pattern 的开头添加 -10/ ,告知 time-stamp 命令在文件 最后 10 行 中查找模板;其中的 %% 表示使用默认的时间戳格式(由变量 time-stamp-format 指定)。
文档内容示例:
…
<p>Last modified: </p>
</body>
</html>
<!--
Local Variables:
time-stamp-pattern: "-10/Last modified: %%</p>$"
End:
-->
Emacs 会默认根据你的 区域设置 (参见《环境变量》章节)和 时区 (参见《Emacs Lisp 参考手册》中的《时间与日期》章节)格式化时间戳。你可以设置变量 time-stamp-time-zone ,覆盖默认使用的时区。关于时间戳的具体格式化规则,以及其他影响格式化的相关变量,可查阅变量 time-stamp-format 的内置文档。
20.3.6.2. 强制单个文件的时间戳更新
若你正在编辑一个由多位作者协作的文件,且无法确定其他作者是否已在其 Emacs 初始化文件中 全局启用 时间戳功能,可在该文件的 局部变量列表 中,将 time-stamp 函数添加至缓冲区的 before-save-hook 钩子,以此为该特定文件强制启用时间戳功能。以下是基于前文示例的扩展配置:
// Local Variables: // eval: (add-hook 'before-save-hook 'time-stamp nil t) // time-stamp-pattern: "Published %Y in Boston" // End:
本示例中同时配置了上述两项内容,若你希望使用默认的时间戳匹配规则,也可仅使用 eval 配置项,而不设置 time-stamp-pattern 。
20.4. 恢复缓冲区(Reverting a Buffer)
若你对访问文件的缓冲区做出了大量修改,之后又想放弃这些修改,可通过恢复操作还原至文件的已保存版本。执行该操作只需按下 C-x x g 即可。由于误执行恢复操作可能会丢失大量工作成果,因此若缓冲区存在未保存修改,Emacs 会先向你请求确认,再执行恢复。
revert-buffer 命令会尽量智能定位光标位置:若文件仅做了少量修改,光标会停留在与修改前大致相同的文本位置;但如果文件做了大幅修改,光标最终可能会出现在完全不同的位置。
执行恢复操作后,缓冲区的 已修改标记会被清除 。但该操作会将本次恢复的所有修改内容,作为单次修改记录添加到缓冲区的撤销历史中(参见《撤销》章节)。因此,即便执行了恢复,若你后续改变主意,仍可按下 C-/ 或其等效快捷键,恢复此前被撤销的修改内容。
若想以更保守的方式恢复缓冲区,可使用 revert-buffer-with-fine-grain 命令。该命令的基础功能与 revert-buffer 一致,但会尽可能做到 无破坏性恢复 ,尽力保留缓冲区中的所有标记、文本属性和覆盖层。当你对文件做出了大量修改时,这种恢复方式的执行速度可能会很慢,你可以修改变量 revert-buffer-with-fine-grain-max-seconds ,指定该方式替换缓冲区内容的最长耗时(以秒为单位)。请注意,该设置并不能保证 revert-buffer-with-fine-grain 命令的整体执行时间不超过该限值。
部分与文件无关联的缓冲区也可执行恢复操作,例如 Dired 缓冲区,对这类缓冲区而言,恢复意味着重新计算并刷新其内容。而通过 C-x b 显式创建的空白缓冲区无法执行恢复操作,若尝试对其执行 revert-buffer ,命令会直接抛出错误。
当你编辑的文件会 自动且频繁地发生变化 (例如,某个持续运行的进程生成的输出日志文件),让 Emacs 无需询问直接恢复该文件会非常实用。若要启用该功能,需将变量 revert-without-query 设为一个正则表达式列表。当文件名匹配列表中的任意一个正则表达式时,若文件在磁盘上发生了变化,且对应的缓冲区本身无未保存修改, find-file 和 revert-buffer 命令会自动恢复该文件(若你已对缓冲区文本做了修改,自动恢复会丢弃这些修改,因此该情况下不会执行)。
快捷键 C-x x g 绑定的是 revert-buffer-quick 命令,该命令与 revert-buffer 功能一致,但 弹出的提示更少 。与 revert-buffer 不同,若当前缓冲区关联了文件且无未保存修改,该命令不会弹出任何确认提示。同时,该命令会遵循用户选项 revert-buffer-quick-short-answers 的配置:若该选项为非nil值,会使用简短的 'y/n' 确认提示,而非冗长的 'yes/no' 提示。
你也可以设置 Emacs,让缓冲区在其关联的文件在磁盘上发生变化时 自动执行恢复 ,相关配置参见《自动恢复:让缓冲区自动保持最新》章节。
请注意,恢复缓冲区时,Emacs 会为该缓冲区关联的文件启用对应的主模式(具体规则参见《选择文件模式》章节)。因此,恢复操作最终启用的主模式会受模式重映射配置的影响:若你在恢复前自定义了 major-mode-remap-alist ,恢复后启用的主模式可能与原模式不同。
20.5. 自动恢复:保持缓冲区自动更新(Auto Revert)
当缓冲区关联的磁盘文件被其他程序修改时,缓冲区内容会与文件不同步。若要让缓冲区始终保持最新,可输入 M-x auto-revert-mode 启用 自动恢复模式 ,该模式会在磁盘文件发生修改时,自动恢复缓冲区内容。若要为所有文件缓冲区启用该功能,可输入 M-x global-auto-revert-mode 开启 全局自动恢复模式 。
当缓冲区存在未保存修改,或其对应的磁盘文件被删除、重命名时,自动恢复功能不会对该缓冲区执行恢复操作。
自动恢复模式的一个常用场景是 跟踪 系统日志这类文件,让其他程序对该文件的修改能实时显示在 Emacs 中。只需将光标移至缓冲区末尾,后续文件内容更新时,光标会始终停留在末尾位置。但如果你确定该文件只会在末尾追加内容,建议改用 自动恢复尾部模式 (auto-revert-tail-mode),该模式针对此场景的执行效率更高,且对远程文件同样适用。
缓冲区被自动恢复时,Emacs 会弹出提示信息,将变量 auto-revert-verbose 设为 nil= 可关闭该提示。
自动恢复模式默认不会检查或恢复远程文件,因该操作通常耗时过久,将变量 auto-revert-remote-files 设为非nil值可修改此行为。
自动恢复模式默认通过 file notifications文件通知机制 工作,由操作系统将文件系统的修改情况通知给 Emacs。将变量 auto-revert-use-notify 设为 nil 可禁用该机制,此时 Emacs 会通过 轮询 方式检查文件修改,默认轮询间隔为 5 秒,可通过变量 auto-revert-interval 修改轮询时间。
并非所有系统都支持文件通知机制,在不支持该机制的系统中, auto-revert-use-notify 会默认设为 nil 。
即便启用了文件通知机制,自动恢复模式默认仍会定期轮询文件是否修改。多数场景下轮询并无必要,仅依靠通知机制可减少资源消耗,将变量 auto-revert-avoid-polling 设为非nil值即可关闭轮询。但需注意,部分文件系统的通知机制失效,尤其是类 Unix 系统中的网络文件系统(这类文件可被其他机器修改),此时轮询操作是必要的。若 auto-revert-avoid-polling 为非nil但需对部分文件强制轮询,可设置变量 auto-revert-notify-exclude-dir-regexp ,让匹配该正则表达式的文件排除在通知机制之外,转而使用轮询。
在 Dired 缓冲区中(参见《目录编辑器 Dired》章节),当缓冲区对应目录中有文件被创建或删除时,自动恢复模式会刷新该缓冲区的内容。
若要恢复版本控制系统管理下文件的早期版本,可参考相关命令说明(参见《撤销版本控制操作》章节)。关于访问版本控制系统管理的文件时,自动恢复模式的特殊行为说明,参见《版本控制与模式行》章节。
20.5.1. 非文件缓冲区的自动恢复
全局自动恢复模式默认仅对 文件缓冲区 执行自动恢复操作。要为特定非文件缓冲区启用自动恢复,有两种方式:一是在目标缓冲区中启用自动恢复模式(执行 M-x auto-revert-mode 命令);二是将变量 global-auto-revert-non-file-buffers 设为非nil值,后者会为所有已实现该功能的非文件缓冲区(如下方列表所示)全局启用自动恢复。
与文件缓冲区相同,非文件缓冲区在你编辑操作期间,或缓冲区中包含恢复后可能丢失的信息时,默认不会执行自动恢复。因此, 已修改的非文件缓冲区不会触发自动恢复 。这一规则的实际应用存在一定复杂性,因为判断非文件缓冲区何时应标记为已修改,通常比文件缓冲区的判断难度更高。
另一处需要注意的细节是,出于效率考量,自动恢复功能通常不会尝试检测缓冲区中所有可能的变更,仅会识别 主要变更 或 易于检测的变更 。因此,为非文件缓冲区启用自动恢复,并不总能保证缓冲区中的所有信息都是最新的,手动执行恢复操作依然有其必要性。
与之相反的是,部分非文件缓冲区会按照 auto-revert-interval 变量设定的秒数 定时自动恢复 (目前该规则仅适用于缓冲区菜单)。此类场景下,即便变量 auto-revert-verbose 设为非nil,自动恢复操作也不会打印任何提示信息。
部分非文件缓冲区可通过其 默认目录 的文件通知机制实现可靠的自动更新,Dired 缓冲区就是典型示例。对应的主模式可通过在缓冲区中将变量 buffer-auto-revert-by-notification 设为非nil值来标识这一特性,让自动恢复功能无需再执行定期轮询。需注意,该方式的文件通知仅针对目录本身的变更, 不包含目录内文件的变更 。
非文件缓冲区自动恢复的具体规则因缓冲区类型而异,相关细节会在对应章节中说明。
20.5.1.1. 缓冲区菜单的自动恢复
若已启用非文件缓冲区的自动恢复功能, 缓冲区菜单 (参见《对多个缓冲区执行操作》章节)会按照 auto-revert-interval 变量设定的秒数定时自动恢复,无论是否存在实际的变更需要同步(因为检查是否需要恢复的耗时,可能反而比直接执行恢复操作更长)。
若缓冲区菜单被错误标记为已修改状态,只需按下 g 手动恢复,自动恢复功能便会恢复正常。但需注意,若你已为部分缓冲区标记了删除或显示操作,执行恢复时需格外小心 —— 因为恢复操作会 清除所有标记 。而添加标记的操作会为缓冲区设置已修改标识,这一机制恰好能防止自动恢复功能误删标记
20.5.1.2. Dired 缓冲区的自动恢复
Dired 缓冲区仅在其主目录的文件列表发生变化时(如新增或删除文件)触发自动恢复;若仅为单个文件的信息变更(如文件大小修改),或插入的子目录内容发生变化,不会触发自动恢复。即便已为 Dired 缓冲区启用自动恢复功能,若要确保列表中所有信息均为最新,仍需按下 g 键手动执行恢复操作。
有时你会发现,修改或保存主目录列表中的文件后,缓冲区似乎也触发了自动恢复,这是因为对文件的修改或保存操作,往往会间接导致目录本身发生变化(例如生成备份文件或自动保存文件),但这种情况并非必然发生。
若 Dired 缓冲区被标记为 “已修改”,且其中无需要保留的修改内容,多数情况下按下 g 键手动恢复后,即可恢复自动恢复功能,仅存在一种例外情况:若你为文件添加了标记或标记符,仍可安全执行缓冲区恢复操作,该操作不会清除已添加的标记或标记符(除非被标记的文件已被删除);但恢复后,缓冲区仍会保持 “已修改” 状态,自动恢复功能也无法恢复。这一设计的原因是,当你为文件添加标记或标记符时,通常表明正针对该缓冲区进行操作,大概率不希望缓冲区在无提示的情况下发生变更。
若希望在保留文件标记 / 标记符的同时恢复自动恢复功能,可按下 M-~ 将缓冲区标记为 “未修改”;但后续若再次添加、删除或修改标记 / 标记符,缓冲区会重新被标记为 “已修改”。
注意:远程 Dired 缓冲区目前不支持自动恢复;通过 Shell 通配符或文件参数筛选出部分文件生成的 Dired 缓冲区,同样不支持自动恢复。 *Find* 和 *Locate* 缓冲区也无自动恢复功能。
此外,在部分系统中,Dired 缓冲区的自动恢复功能可能无法达到预期效果。
20.6. 自动保存:防止数据丢失(Auto-Saving)
Emacs 会定期将每个已打开的文件,保存至一个独立的文件中,且不会改动你实际编辑使用的原文件,这一功能称为 自动保存 。若系统发生崩溃,该功能能避免你丢失过多的编辑成果。
当 Emacs 判定达到自动保存时机时,会对每个缓冲区进行检查:若该缓冲区启用了自动保存功能,且自上次自动保存后有内容修改,便会对其执行自动保存操作。当变量 auto-save-no-message 设为 nil (默认值)时,若此次有文件实际执行了自动保存,回显区会显示提示信息「正在自动保存…」;若要关闭该提示,可将此变量自定义设置为非nil值。自动保存过程中若发生错误,Emacs 会捕获错误信息,避免其干扰你正在输入执行的命令。
20.6.1. 自动保存文件
自动保存操作通常不会将内容保存至你所打开的原文件中,因为贸然保存并非你想要永久保留的修改,会造成不必要的麻烦。反之,自动保存会将内容写入一个独立的文件,即 自动保存文件 ;只有当你显式执行保存操作时(如按下快捷键 C-x C-s ),修改内容才会写入原文件。
默认情况下,自动保存文件的命名规则为:在原文件名称的首尾各添加一个井号 '#' 。例如,打开文件 'foo.c' 对应的缓冲区,其自动保存文件为 '#foo.c#' 。对于大多数未关联实际文件的缓冲区,仅当你显式发起请求时才会执行自动保存;这类缓冲区的自动保存文件命名,会先在缓冲区名称首尾添加 '#' ,再在末尾拼接数字和字母以保证唯一性。比如,用于撰写待发送邮件的 *mail* 缓冲区,其自动保存文件可能命名为 #*mail*#704juu 。除非你重新编写 Emacs 相关功能代码(涉及 make-auto-save-file-name 和 auto-save-file-name-p 函数),否则自动保存文件都会遵循此命名规则。缓冲区的自动保存文件名,会在该缓冲区开启自动保存功能时完成计算。
变量 auto-save-file-name-transforms 允许你对自动保存文件名进行一定程度的自定义,你可通过该变量指定一系列正则表达式及替换规则,实现对自动保存文件名的转换。该变量的默认值会将远程文件(参见「远程文件」相关内容)的自动保存文件,存放至本地机器的临时文件目录中。
当你在一个大缓冲区中删除大量文本内容时,该缓冲区的自动保存功能会暂时关闭。此设计的原因是:若你并非有意删除这些文本,保留了被删内容的自动保存文件,会对你恢复数据更有帮助。若要在该情况下重新启用自动保存功能,可按下 C-x C-s 保存缓冲区,或执行命令 C-u 1 M-x auto-save-mode 。
若你希望自动保存操作直接写入原文件,而非独立的自动保存文件,可启用全局次要模式 auto-save-visited-mode 。开启该模式后,自动保存的效果将与显式保存完全一致。请注意,该模式与前文所述的自动保存模式相互独立,你可同时启用两种模式。但如果某一缓冲区已激活自动保存模式,且废弃变量 auto-save-visited-file-name 被设为非nil值,那么该缓冲区将不受 auto-save-visited-mode 模式的影响。
你可通过变量 auto-save-visited-interval ,自定义 auto-save-visited-mode 模式下自动保存的时间间隔,其默认值为 5 秒。而变量 auto-save-interval 和 auto-save-timeout 对 auto-save-visited-mode 模式不产生作用,关于这些变量的详细说明,参见「控制自动保存」章节。
当你将缓冲区的内容保存至原文件时,该缓冲区对应的自动保存文件会被自动删除(若将变量 delete-auto-save-files 设为 nil ,可禁止此删除操作)。若通过 C-x C-w 或 set-visited-file-name 命令修改缓冲区关联的原文件名,对应的自动保存文件也会同步重命名,与新的原文件名匹配。
默认情况下,关闭缓冲区不会删除其对应的自动保存文件。若将变量 kill-buffer-delete-auto-save-files 设为非nil值,当你关闭一个存在自动保存文件的缓冲区时,Emacs 会向你发起确认提示,询问是否删除该自动保存文件(若 delete-auto-save-files 设为 nil ,则不会出现此提示)。
20.6.2. 自动保存控制
当你打开任意文件时,若变量 auto-save-default 设为非nil值,该文件对应的缓冲区会开启自动保存功能(批处理模式下除外,参见「初始选项」相关内容)。该变量的默认值为 t ,因此文件关联缓冲区默认都会启用自动保存。若要切换当前缓冲区的自动保存状态,可执行命令 M-x auto-save-mode 。自动保存模式是一个 缓冲区局部次要模式 (参见「次要模式」章节)。
Emacs 会根据你自上次自动保存后输入的字符数,定期执行自动保存操作。变量 auto-save-interval 用于指定两次自动保存之间的字符输入阈值,默认值为 300 。该变量不支持设置过小的数值:若你将其自定义为小于 20 的数,Emacs 会自动按 20 的阈值执行。
当你停止输入一段时间后,Emacs 也会触发自动保存。默认情况下,闲置 30 秒后会执行该操作(此时 Emacs 可能同时进行垃圾回收,参见《Emacs Lisp 参考手册》中的「垃圾回收」章节)。你可通过自定义变量 auto-save-timeout 修改这一闲置阈值。若当前缓冲区内容较长,实际触发自动保存的闲置时间会相应延长;这是一项启发式设计,目的是在你编辑大缓冲区时减少干扰 —— 因为大缓冲区的自动保存会消耗可观的时间。闲置时的自动保存能实现两个目的:一是若你离开终端一段时间,确保所有编辑内容都已保存;二是能在你实际输入的过程中,减少自动保存的触发次数。
当 auto-save-visited-mode 模式启用时,文件关联缓冲区会在闲置 5 秒后触发自动保存,你可通过自定义变量 auto-save-visited-interval 修改该闲置阈值。
当 Emacs 遭遇致命错误时,也会执行自动保存操作。这类情况包括通过 'kill %emacs' 等 Shell 命令终止 Emacs 进程,或是电话线路、网络连接断开等场景。
你也可通过执行命令 M-x do-auto-save ,显式触发一次自动保存。
20.6.3. 从自动保存文件恢复数据
你可以使用命令 M-x recover-file RET 文件名 RET ,借助自动保存文件的内容恢复丢失的数据。该命令会先打开指定文件,经你确认后,从其对应的自动保存文件 #file# 中恢复内容,之后你可按下 C-x C-s ,将恢复的文本保存至原文件中。例如,要从自动保存文件 '#foo.c#' 恢复文件 'foo.c' ,操作步骤如下:
M-x recover-file RET foo.c RET yes RET C-x C-s
在请求确认前, M-x recover-file 会显示目录列表,展示指定文件与对应自动保存文件的相关信息,你可借此对比两者的大小和修改时间;若自动保存文件的修改时间更早,该命令将不会提供读取此文件的选项。
当 M-x recover-file 请求确认时,若你输入 diff 或 = 作为回应,命令会展示原文件与自动保存文件 '#file#' 之间的内容差异,随后再次向你请求恢复确认。
若 Emacs 程序或计算机发生崩溃,你可使用命令 M-x recover-session ,从自动保存文件中恢复所有此前正在编辑的文件。该命令会先为你展示已记录的所有中断会话列表,将光标移至你选择的会话处,按下 C-c C-c 即可进入后续步骤。
接着, recover-session 会针对该会话中曾编辑的每一个文件逐一确认,询问是否恢复对应文件;若你回答 'y' ,命令会调用 recover-file 并按其常规逻辑执行,展示原文件与自动保存文件的修改时间,且会再次确认是否恢复该文件。
recover-session 执行完成后,你选择恢复的所有文件都会出现在 Emacs 的缓冲区中, 此时需手动保存这些缓冲区 ,只有执行保存操作,才能将恢复的内容更新至原文件本身。
Emacs 会将中断会话的相关信息,记录在 '/.emacs.d/auto-save-list/' 目录下、命名格式为 '.saves-进程号-主机名' 的文件中,该存储目录由变量 auto-save-list-file-prefix 指定;若将此变量设为 nil ,Emacs 将不再记录会话信息,也就无法进行会话恢复操作。
20.7. 文件名别名(File Name Aliases)
符号链接与硬链接均可实现多个文件名指向同一个文件。 硬链接 是直接指向文件的替代名称,所有名称的有效性完全相同,不存在优先级之分。与之不同的是, 符号链接 是一种显式定义的别名:若 'foo' 是指向 'bar' 的符号链接,你可通过任一名称访问该文件,但 'bar' 为实际的原名称,而 'foo' 仅为别名。当符号链接指向目录时,会出现更为复杂的情况。
默认情况下,若你打开的文件,Emacs 已通过其他名称打开过,Emacs 会在回显区显示提示信息,并直接使用已打开该文件的现有缓冲区。这种情况会出现在多种场景:支持硬链接或符号链接的系统、会截断长文件名的系统中使用长文件名、或是在不区分大小写的文件系统中操作。你可将变量 find-file-suppress-same-file-warnings 设为非nil值,关闭该提示信息;若将变量 find-file-existing-other-name 设为 nil ,则会完全禁用此功能 —— 此时若通过两个不同名称打开同一个文件,Emacs 会为每个文件名分别创建独立的缓冲区。
若变量 find-file-visit-truename 设为非nil值,缓冲区中记录的文件名会是文件的 真实名称 (将所有符号链接替换为其指向的目标名称后得到的名称),而非你输入的原始名称。设置该变量的同时,也会等效启用 find-file-existing-other-name 变量的功能。
有时,某个目录通常通过符号链接进行访问,而你希望 Emacs 优先显示其链接名称,此时可自定义变量 directory-abbrev-alist 实现该需求。该列表中的每个元素均为 (from源匹配串 . to目标替换串) 的形式,表示当目录名中出现源匹配串时,将其替换为目标替换串。其中 源匹配串为正则表达式 (参见《正则表达式的语法》章节),会从目录名的第一个字符开始匹配,且需以 '\`' 作为起始(以兼容包含换行符的目录名,避免 '^' 匹配符失效); 目标替换串 需为指向同一目录的普通绝对目录名,且不可在其中使用 '~' 代表主目录(Emacs 会单独处理此类路径替换)。以下是一个示例,适用于 '/home/fsf' 目录通常通过符号链接 '/fsf' 访问的系统:
(("\\`/home/fsf" . "/fsf"))
20.8. 文件目录(File Directories)
文件系统会将文件归类至不同目录中, directory listing目录列表 即某一目录下的所有文件清单。Emacs 提供了创建、删除目录的命令,也可生成 简洁格式 (仅显示文件名)和 详细格式 (包含大小、日期及其他属性)的目录列表。Emacs 还内置了名为 Dired 的目录浏览功能,可通过快捷键 C-x d 调用,相关用法参见《目录编辑器 Dired》章节。
C-x C-d 目录/匹配模式 RET- 显示简洁格式的目录列表 (
list-directory) 。 C-u C-x C-d 目录/匹配模式 RET- 显示详细格式的目录列表。
M-x make-directory RET 目录名 RET- 创建指定名称的新目录。
M-x delete-directory RET 目录名 RET- 删除指定名称的目录;若目录非空,会询问是否递归删除该目录。
用于显示目录列表的核心命令为 C-x C-d (list-directory) ,该命令会通过迷你缓冲区读取一个文件名 —— 此文件名可以是待列出的目录,也可以是包含通配符、用于匹配目标文件的模式。例如:
C-x C-d /u2/emacs/etc RET
会列出 /u2/emacs/etc 目录下的所有文件。以下是指定文件名称匹配模式的示例:
C-x C-d /u2/emacs/src/*.c RET
默认情况下, C-x C-d 显示的简洁目录列表仅包含文件名;若执行命令时带上数字参数(无论参数具体值是多少),则会生成详细目录列表,包含文件大小、修改日期、所有者等信息(效果类似系统命令 ls -l )。
目录列表的内容,主要通过在子进程中执行 ls 命令获取。有两个 Emacs 变量用于控制传递给 ls 命令的参数: list-directory-brief-switches 为简洁列表的参数字符串(默认值为 "-CF"), list-directory-verbose-switches 为详细列表的参数字符串(默认值为 "-l")。
在详细格式的目录列表中,Emacs 还会额外显示该目录所在磁盘的剩余存储空间信息。
M-x delete-directory 命令会通过迷你缓冲区提示输入待删除的目录名,若目录为空则直接删除;若目录非空,会询问是否递归删除。在支持「Trash回收站」(或 "Recycle Bin废纸篓")功能的系统中,若将变量 delete-by-moving-to-trash 设为 t ,该命令会将指定目录移至回收站,而非直接永久删除。关于回收站的更多使用方法,参见《杂项文件操作》章节。
20.9. 文件比较
命令 M-x diff 会通过迷你缓冲区提示输入两个文件名,随后在名为 *diff* 的缓冲区中显示这两个文件的内容差异。该命令的实现依赖于调用系统的 diff 程序,执行时会使用变量 diff-switches 中配置的参数。此变量的值为字符串类型,默认值是 "-u" ,表示生成 统一上下文格式 的差异对比结果。关于 diff 程序的更多用法,参见《文件的对比与合并》中的「差异对比」章节。
diff 命令的输出结果会在 差异模式 (Diff mode)下展示,该模式为一种主模式,相关用法参见「差异模式」章节。
另一种功能更完善的替代方案是命令 M-x ediff ,相关用法参见《Ediff 手册》中的「Ediff」章节。
命令 M-x diff-backup 用于对比指定文件与其最新的备份文件;若你输入的是备份文件的名称,该命令则会对比此备份文件与其对应的源文件。除上述逻辑外,该命令的其他行为均与 M-x diff 一致。
命令 M-x diff-buffer-with-file 用于对比指定缓冲区与其对应的本地文件,通过该命令可查看:若保存此缓冲区,会对原文件做出哪些修改。
命令 M-x diff-buffers 用于对比两个指定缓冲区的内容。
命令 M-x compare-windows 用于对比当前窗口与 上一个选中的窗口 中的文本(关于 Emacs 的窗口相关知识,参见「多窗口」章节)。对比操作会从两个窗口的光标位置开始,且执行前会将两个缓冲区的初始光标位置分别压入各自的标记环(参见「标记环」章节);随后光标会在两个窗口中同步逐字符向后移动,直至找到不匹配的字符,命令随即退出。
若命令执行时,两个窗口的光标位置后紧跟的就是不匹配的文本, M-x compare-windows 会通过启发式算法,尝试在两个窗口中向后定位至匹配的文本位置,之后便退出。因此,若你重复执行该命令(参见「重复执行命令」章节),每次执行要么会跳过一段匹配的文本区域,要么会找到下一段匹配区域的起始位置。
若执行该命令时带上数字参数,对比过程会忽略空白字符的变化;若变量 compare-ignore-case 设为非nil值,对比还会忽略大小写的差异。若变量 compare-ignore-whitespace 设为非nil值, compare-windows 默认会忽略空白字符的变化,而带上前缀参数时,本次命令执行会临时关闭该忽略规则。
你可执行 M-x smerge-mode 开启 合并模式 (Smerge mode),这是一款用于编辑 diff3 程序输出结果的次要模式。 diff3 的输出通常出现在以下场景:在版本控制系统外执行更新操作时,因文件存在冲突的修改导致合并失败。合并模式提供了专用命令,可通过选择特定的修改内容来解决文件合并冲突。
关于文件合并的高级工具 Emerge ,可参见《使用 Emerge 合并文件》章节,该工具为文件合并提供了功能强大的操作界面。
20.10. 差异模式
差异模式(Diff mode)是一种主模式,专用于展示 M-x diff 及其他同类命令的输出结果。这类输出内容被称为 patch补丁文件 ,因为可将其传入系统的 patch 命令,实现指定修改的自动应用。若要手动启用差异模式,执行命令 M-x diff-mode 即可。
补丁文件中定义的修改会被划分为多个 修改块 (hunk),每个修改块是包含一行或多行变更内容的连续文本段,通常还会附带未修改的文本,为变更提供上下文参考。每个修改块前都会有 hunk header修改块头 ,用于指定该块修改在原文件和新文件中对应的行号。差异模式会对所有修改块头进行高亮,使其与修改块的实际内容区分开。
补丁文件中的第一个修改块前会有 文件头 ,展示文件新旧版本的名称及其时间戳。若一个补丁文件包含对多个文件的修改,每个文件的第一个修改块前都会配有对应的文件头。
你可像编辑普通缓冲区一样编辑差异模式的缓冲区(若缓冲区为只读状态,需先将其设为可写,参见《缓冲区的杂项操作》)。每当你编辑某个修改块时,差异模式会自动校正该块头中的行号,确保补丁文件始终有效,仍可被 patch 命令正常应用。若要关闭行号自动校正功能,将变量 diff-update-on-the-fly 设为 nil 即可。
差异模式会将修改块识别为编译器错误信息,让 M-g M-n 及其他处理错误信息的命令可对其生效(参见《编译模式》)。因此,你可使用编译模式的相关命令,跳转到修改对应的源码位置。
此外,差异模式还提供了以下命令,用于补丁文件的导航、操作与修改应用:
补丁导航命令
M-n跳转到下一个修改块的起始位置 (
diff-hunk-next) 。带上数字参数n时,向前跳至第n个修改块。默认情况下,Emacs 展示补丁时会自动细化所有修改块,以更精细的粒度高亮变更内容。若将变量
diff-refine设为navigation,则差异模式仅会对通过本命令或diff-hunk-prev跳转至的修改块进行细化处理。M-p- 跳转到上一个修改块的起始位置 (
diff-hunk-prev) 。带上数字参数n时,向后跳至第n个修改块。与M-n相同,若diff-refine设为navigation,本命令会对跳转至的修改块做细化处理。 M-}- 在多文件补丁中,跳转到下一个文件的起始位置 (
diff-file-next) 。带上数字参数n时,向前跳至第n个文件的起始位置。 M-{- 在多文件补丁中,跳转到上一个文件的起始位置 (
diff-file-prev) 。带上数字参数n时,向后跳至第n个文件的起始位置。
补丁内容删除命令
M-k- 删除光标所在位置的修改块 (
diff-hunk-kill) 。 M-K- 在多文件补丁中,删除当前文件对应的所有补丁内容 (
diff-file-kill) 。
补丁应用命令
C-c C-a- 将当前修改块应用至其目标文件 (
diff-apply-hunk) 。带上前缀参数C-u时,撤销该修改块的变更,即执行反向应用,将文件的 "new" 还原为 "old" 版本 。若变量diff-jump-to-old-file设为非nil,则该命令会将修改块应用至文件的「旧版本」而非新版本。 C-c RET a- 将缓冲区中所有修改块应用至对应文件 (
diff-apply-buffer) 。若所有差异均应用成功,会自动保存被修改的缓冲区。
补丁细化与查看命令
C-c C-b以更精细的粒度高亮光标所在修改块的变更内容 (
diff-refine-hunk) ,可清晰查看变更行中具体哪些字符发生了修改。由于差异模式默认会自动细化所有修改块,该命令主要在你将
diff-refine设为非默认值时使用。C-c C-c- 跳转到当前修改块对应的源码文件及行号 (
diff-goto-source) 。默认跳转到文件的「新版本」(文件头中首个展示的版本),带上前缀参数时则跳转到「旧版本」。若diff-jump-to-old-file设为非nil,命令默认跳转到「旧版本」,前缀参数的作用则会反转。若前缀参数为大于 8 的数字(如执行C-u C-u C-c C-c),该命令还会为下一次调用设置diff-jump-to-old-file的取值。若源码文件受版本控制系统管理(参见《版本控制》),命令默认跳转到工作区文件;带上前缀参数时,若光标位于旧版本的行号处,会跳转到文件的「旧版本修订版」(参见《查看与对比旧修订版》),否则跳转到「新版本修订版」。 C-c C-n- 将视图限定为当前修改块 (
diff-restrict-view,参见《内容窄化》)。带上前缀参数时,在多文件补丁中将视图限定为当前文件的补丁内容。执行C-x n w(widen) 可恢复完整视图。
补丁编辑与转换命令
C-c C-e- 基于当前补丁启动 Ediff 会话 (
diff-ediff-patch,参见《Ediff 手册》中的 Ediff 章节)。 C-c C-r- 反转整个缓冲区的对比方向 (
diff-reverse-direction) 。带上前缀参数时,仅反转当前区域内的对比方向(参见《标记与区域》)。对比方向反转,指修改块和文件头会被重新调整,生成可将文件「新版本」还原为「旧版本」的补丁。 C-c C-s- 将光标所在的修改块拆分为两个独立的修改块 (
diff-split-hunk) ,该命令会插入新的修改块头并修改原块头的信息。本命令适用于手动编辑补丁,且仅对diff程序通过-u或--unified选项生成的统一格式差异文件生效。若需拆分diff程序通过-c或--context选项生成的上下文格式差异文件,需先执行C-c C-u将缓冲区转换为统一格式。 C-c C-d- 将整个缓冲区转换为 上下文格式差异文件 (
diff-unified->context) 。带上前缀参数时,仅转换区域内的修改块。 C-c C-u- 将整个缓冲区转换为 统一格式差异文件 (
diff-context->unified) ;带上前缀参数时,将统一格式转换为上下文格式。若标记处于激活状态,仅转换区域内的修改块。 C-c C-l- 重新生成当前修改块 (
diff-refresh-hunk) 。 C-c C-w- 重新生成当前修改块,忽略空白字符的变更;带上非nil的前缀参数时,重新生成所有修改块 (
diff-ignore-whitespace-hunk) 。该命令会通过diff-ignore-whitespace-switches调用diff-command,该变量默认值为 '-b' ,即仅忽略空白字符的变更。
其他实用命令
C-x 4 A- 为每个修改块生成一份 ChangeLog 日志条目 (
diff-add-change-log-entries-other-window) ,效果类似C-x 4 a(参见《变更日志》),会创建一份变更日志的骨架,你可后续补充具体的变更描述。在差异模式中,C-x 4 a本身会针对当前修改块对应的文件生成日志,且从补丁文件中提取函数名,适用于为被补丁删除的函数创建日志条目。
补丁中的空白字符处理
补丁文件有时会在变更行中包含尾随空白字符,这属于无意且不必要的变更,可通过两种方式处理:
- 在差异缓冲区中启用空白字符模式(Whitespace mode)(参见《无用的空白字符》),模式会自动高亮变更行中的尾随空白字符;
- 执行命令
M-x diff-delete-trailing-whitespace,该命令会搜索补丁中所有变更行的尾随空白字符,并同时删除补丁文件和被补丁修改的源码文件中的这些空白字符。该命令不会自动保存所做的修改,你可自行决定是否保存(被修改的文件列表会在回显区显示);带上前缀参数时,命令会尝试修改原始的「旧版本」源码文件,而非被补丁修改后的「新版本」源码文件。
若变量 diff-font-lock-syntax 设为非nil,修改块中的源码片段会根据对应的主模式进行语法高亮。
20.11. 文件的复制、命名与重命名
Emacs 提供了多条用于文件复制、命名和重命名的命令。这类命令均会通过迷你缓冲区读取两个文件名 —— old 原文件名(或目标文件名)与 new 新文件名,再据此执行文件复制或文件名调整操作; 此类命令均不支持带通配符的文件名 。
在所有这类命令中,若传入的 new 参数仅为一个目录名(参见《Emacs Lisp 参考手册》中的「目录名」章节),则实际的 new新文件名会是该目录下、与 old原文件拥有相同非目录部分的名称。例如,执行命令 M-x rename-file RET ~/foo RET /tmp/ RET 会将 '~/foo' 重命名为 '/tmp/foo' 。在 GNU 及其他类 POSIX 系统中,目录名均以 '/' 结尾。
当新文件名已存在时,所有这类命令都会先请求用户确认,再执行后续操作。
M-x copy-file :将原文件的内容复制到新文件中。
M-x copy-directory :复制目录,功能与 Shell 命令 cp -r 类似。若 new 为目录名,该命令会创建 old 原目录的副本,并将其放入该目录中;若 new 非目录名,则会把 old 原目录的所有内容复制到一个以 new 新参数命名的新目录中。若变量 copy-directory-create-symlink 设为非 nil 且原目录为符号链接,该命令会直接复制此符号链接;若设为 nil (默认值),则会跟随符号链接,复制链接指向的实际内容。
M-x rename-file :将 old 原文件重命名为 new 新文件名。若 new 新文件名已存在,你必须输入 yes 确认,否则重命名操作不会执行;这是因为重命名会导致 new 新文件名原本对应的文件关联被覆盖。若原文件和新文件所在的文件系统不同,该命令会先将原文件复制到新位置,再删除原文件。
若文件受版本控制系统管理(参见《版本控制》章节),应使用 M-x vc-rename-file 而非 M-x rename-file 执行重命名操作,具体参见《删除和重命名受版本控制的文件》章节。
M-x add-name-to-file :为已有文件添加一个额外的文件名,且保留原文件名不变。该命令会通过为现有文件创建 硬链接 的方式生成新名称,新文件名必须与原文件位于 同一文件系统 中。在微软视窗系统中,该命令仅在文件存储于 NTFS 文件系统时生效;在 MS-DOS 系统及部分远程系统中,该命令会通过 复制文件 的方式实现多文件名关联。
M-x make-symbolic-link :创建一个名为新文件名的 符号链接 ,该链接指向指定的目标文件 / 目录。创建后,后续尝试打开该符号链接时,会访问其指向的目标文件 / 目录;若此时目标不存在,则会触发错误。该命令 不会展开 目标参数的路径,因此你可以指定相对路径作为链接的目标;但该命令会展开目标参数中开头的 '' (方便你指定主目录),并剔除开头的 '=/:=' (方便你指定以字面量 '' 或 '/:' 开头的相对路径),具体参见《带引用的文件名》章节。在微软视窗系统中,该命令仅在 Vista 及更高版本中生效;若符号链接的新文件名指向远程位置,命令是否生效取决于对应的远程系统类型。
20.12. 各类文件操作
Emacs 提供了执行各类其他文件操作的命令,这类命令均仅对单个文件生效, 不支持带通配符的文件名 。
M-x delete-file :会提示输入文件名并将其删除。若需删除同一目录下的多个文件,使用 Dired 目录编辑器会比该命令更便捷,参见《使用 Dired 删除文件》章节。
M-x move-file-to-trash :将文件移至系统 Trash回收站(或 Recycle Bin废纸篓)。该功能在多数操作系统中均支持,移至回收站的文件若后续反悔,可进行恢复(回收站文件的恢复方式因系统而异)。
默认情况下,Emacs 的删除类命令不会使用回收站功能。若希望常用删除命令在回收站可用时优先使用该功能,可将变量 delete-by-moving-to-trash 设为 t 。该设置会对 M-x delete-file 、 M-x delete-directory (参见《文件目录》章节),以及 Dired 中的所有删除命令(参见《使用 Dired 删除文件》章节)生效。为 M-x delete-file 或 M-x delete-directory 添加前缀参数时,无论 delete-by-moving-to-trash 如何设置,都会直接永久删除文件,而非移至回收站。
若你已开启 delete-by-moving-to-trash ,且希望在 Emacs 中手动删除回收站目录中的文件,使用 D (dired-do-delete) 这类命令的效果会很差(该操作仅会为文件重命名,无法实现实际删除)。若需要实现该需求,可在回收站目录中创建一个 .dir-locals.el 文件,并在其中写入以下内容:
((dired-mode . ((delete-by-moving-to-trash . nil))))
但需注意,若使用系统的「清空回收站」命令,该 .dir-locals.el 文件也可能被一并删除,因此该方法仅适用于手动删除回收站文件的场景。
若变量 remote-file-name-inhibit-delete-by-moving-to-trash 设为非nil值,远程文件将永远不会被移至回收站,而是直接被删除。
若文件受版本控制系统管理(参见《版本控制》章节),应使用 M-x vc-delete-file 而非 M-x delete-file 执行删除操作,参见《删除和重命名受版本控制的文件》章节。
M-x insert-file (快捷键亦为 C-x i ):将指定文件的内容副本插入到当前缓冲区的光标位置,光标会保留在插入内容的前方不变。插入内容的末尾位置会被添加到标记环中,且不会激活标记(参见《标记环》章节)。
M-x insert-file-literally :功能与 M-x insert-file 类似,区别在于该命令会 以字面形式插入文件内容 —— 将文件视为纯 ASCII 字符序列,不进行任何特殊的编码转换,与 M-x find-file-literally 命令的处理方式一致(参见《访问文件》章节)。
M-x write-region :是 M-x insert-file 的反向操作,会将缓冲区中选定区域的内容复制到指定文件中。 M-x append-to-file :将选定区域的文本追加到指定文件的末尾,参见《文本累积》章节。变量 write-region-inhibit-fsync 对这两个命令及文件保存操作均生效,参见《自定义文件保存方式》章节。
M-x set-file-modes :会先提示输入文件名,再提示输入文件权限模式,并将该模式应用到指定文件上。文件模式也被称为文件权限,用于决定文件的读、写、执行权限归属。该命令读取的文件模式,支持 chmod 系统命令的符号型或八进制型格式,例如 'u+x' 表示为文件的所有者添加执行权限。该命令在不支持文件模式的操作系统中不产生任何效果。 chmod 是该函数的便捷别名,可直接使用
20.13. 访问压缩文件
你在打开压缩文件时,Emacs 会自动对其进行解压缩;若你修改并保存该类文件,Emacs 会自动将其重新压缩。Emacs 通过 文件名 识别压缩文件,以 '.gz' 结尾的文件表示由 gzip 工具压缩的文件,其他后缀则对应其他压缩程序。
自动解压缩与重新压缩功能,适用于 Emacs 中所有涉及读取文件内容的操作,包括打开文件、保存文件、将文件内容插入缓冲区、加载文件以及字节编译文件。
若要关闭该功能,可执行命令 M-x auto-compression-mode ;若需永久禁用,可对变量 auto-compression-mode 进行自定义设置。
20.14. 文件归档包
文件名以 '.tar' 结尾的文件,通常是由 tar 程序创建的归档文件。Emacs 会以一种特殊的 Tar 模式 打开这类文件,该模式会以类 Dired 的形式展示归档内的内容(参见《目录编辑器 Dired》章节)。你可以像在 Dired 中一样浏览该列表,也能打开归档中包含的子文件,但并非所有 Dired 命令都能在 Tar 模式中使用。
若自动压缩模式处于启用状态(参见《访问压缩文件》章节),Tar 模式也会适用于压缩归档文件 —— 即扩展名是=.tgz= 、 .tar.Z 和 .tar.gz 的文件。
按下 e 、 f 键或 RET 回车键,均可将归档中的单个子文件提取并在独立缓冲区中打开。你可在该缓冲区中编辑文件,若保存此缓冲区,修改后的版本会替换 Tar 模式缓冲区中对应的原文件。用鼠标点击 Tar 模式缓冲区中的文件名,也能实现相同的提取编辑操作。按下 v 键会将文件提取到 视图模式 的缓冲区中打开(参见《视图模式》章节);按下 o 键会提取文件并在另一个窗口中展示,方便你同时编辑子文件和操作归档文件。
按下 I 键可向归档中添加一个新的普通文件,该文件初始状态为空,你可通过上述命令对其进行编辑。该命令会将新文件插入到当前光标所在文件的前方:在 Tar 模式缓冲区的首行执行此命令,新文件会成为归档中的第一个文件;在缓冲区末尾执行此命令,新文件则会成为归档的最后一个文件。
与 Dired 中相同,按下 d 键可为文件标记删除标识,后续按下 x 键即可执行删除;按下 u 键可取消文件的标记。按下 C 键可将归档中的文件复制到本地磁盘;按下 R 键可重命名归档内的文件。按下 g 键可根据磁盘上的原归档文件,恢复 Tar 模式缓冲区的内容。按下 M 、 G 、 O 键,可分别修改归档内文件的权限位、所属用户组和文件所有者。
保存 Tar 模式缓冲区时,Emacs 会根据你对归档内子文件所做的修改,在磁盘上生成一份新的归档文件。
使用 Tar 模式无需依赖 tar 程序 ——Emacs 会直接读取归档文件,但访问压缩归档文件时,仍需要对应的解压缩程序支持。
Emacs 还提供了一个独立但功能相近的 归档模式 (Archive mode),适用于 arc 、 jar 、 lzh 、 zip 、 rar 、 7z 、 zoo 格式的归档文件,同时也支持自解压可执行文件(exe 格式)。
归档模式的按键绑定与 Tar 模式基本一致,额外增加了 m 键(为文件标记标识,以便执行后续批量操作)和 M-DEL 键(取消所有已标记文件的标识)。此外,对于部分无法在单行内完整展示详情的归档格式,按下 a 键可切换是否显示文件的详细信息。需要注意的是,重命名子文件、修改文件权限或所有者这类操作,仅对部分归档格式提供支持。
与 Tar 模式不同,归档模式会调用对应的归档程序来完成归档的解包和重新打包操作。不过仅查看归档的目录内容时,无需依赖这些程序,只有提取或操作归档内的子文件时才会用到。相关程序的名称及其执行参数,可在 'Archive' 自定义组中进行设置(参见《自定义组》章节)。
20.15. 远程文件
你可通过一种特殊的文件名语法,引用其他机器上的文件,语法格式如下:
/method:host:filename /method:user@host:filename /method:user@host#port:filename
为执行远程文件访问请求,Emacs 会调用 ssh 等远程登录程序。在文件名中,你必须明确指定使用的访问方式 —— 例如 /ssh:user@host:filename 表示使用 ssh 方式访问。若在文件名中指定伪访问方式用 '-',Emacs 会按以下规则自动选择访问方式:
- 若主机名以 'ftp.' (带句点)开头,使用
FTP方式; - 若用户名设为 'ftp' 或 'anonymous' ,使用
FTP方式; - 若变量
tramp-default-method设为ftp,使用FTP方式; - 若
ssh-agent进程正在运行,使用scp方式; - 其他情况,默认使用
ssh方式。
执行命令 M-x inhibit-remote-files 可彻底关闭远程文件名功能;也可在文件名前添加 '/:' 进行引用(参见《带引用的文件名》),单独禁用某一次的远程文件访问。
通过 FTP 方式的远程文件访问,由 Ange-FTP 包处理,相关用法见下文说明;其他访问方式的远程文件操作,均由 Tramp 包处理,该包有独立的使用手册,参见《Tramp 手册》。
使用 Ange-FTP 包访问远程文件时,若远程文件名中指定了用户名 user ,Emacs 会使用该用户名通过 FTP 登录;若未指定用户名,默认使用本地系统的用户名登录。若将变量 ange-ftp-default-user 设为某个字符串,Emacs 会使用该字符串作为默认登录用户名。登录过程中,Emacs 可能会提示你输入密码。
出于性能考虑,Emacs 默认不会为通过 FTP 访问的远程文件创建备份文件。若需要开启该功能,将变量 ange-ftp-make-backup-files 设为非nil值即可。
远程文件的自动保存文件,默认会创建在本地机器的临时文件目录中,具体由变量 auto-save-file-name-transforms 指定,参见《自动保存文件》章节。
访问支持匿名 FTP 的远程文件时,需使用专用用户名 anonymous 或 ftp ,这类用户名的密码会做特殊处理,具体由变量 ange-ftp-generate-anonymous-password 控制:
- 若该变量值为一个字符串,直接使用该字符串作为密码;
- 若该变量值为非nil(默认值),使用
user-mail-address变量的值作为密码; - 若该变量值为
nil,Emacs 会像常规操作一样,提示你手动输入密码(参见《输入密码》)。
有时因中间的防火墙出于安全考虑拦截了连接,你无法直接访问远程机器上的文件。若你能 登录某台网关机器 ,且该机器可访问目标文件、其 FTP 服务器支持网关功能,仍可正常使用远程文件名访问 —— 只需将变量 ange-ftp-gateway-host 设为该网关机器的名称,并将 ange-ftp-smart-gateway 设为 t 即可。若上述条件不满足,也可通过其他复杂步骤实现远程文件访问,执行命令 M-x finder-commentary RET ange-ftp RET 可查看详细操作说明。
20.16. 带引用的文件名
你可以对绝对文件名进行 quote引用处理 ,避免其中的特殊字符和语法触发相应的特殊效果,具体方法是在文件名开头添加 '/:' 。
例如,若某个本地文件名的格式看似远程文件路径,可通过引用将其标记为本地文件,防止 Emacs 将其当作远程文件名处理。比如你有一个名为 /foo: 的目录,其中包含文件 'bar' ,在 Emacs 中可通过 '/:/foo:/bar' 引用该文件。
若仅需对远程文件名的本地路径部分中的特殊字符进行引用,可仅为该部分添加引用标识。例如 /ssh:baz:/:/foo:/bar ,表示访问主机 baz 上 /foo: 目录中的 bar 文件。
'/:' 也能阻止 '~' 被解析为用户主目录的特殊标识。例如 /:/tmp/~hack ,指向的是 /tmp 目录下一个名为 ~hack 的文件。
在迷你缓冲区中输入包含 '$' 的文件名时,也可通过 '/:' 进行引用,但需 注意 '/:' 必须置于迷你缓冲区输入内容的开头(也可将每个 '$' 重复输入一次来实现相同效果,参见《含 $ 的文件名》章节)。
访问文件时,还能通过 '/:' 对通配符进行引用。例如输入 /:/tmp/foo*bar ,会直接访问 /tmp 目录下的 foo*bar 文件(而非将 '*' 当作通配符匹配)。
实现上述效果还有另一种方法:输入 /tmp/foo[*]bar ,这种通配符写法仅会匹配 /tmp/foo*bar 这一个文件。不过在很多情况下,无需对通配符进行引用,因为即便不引用,也能得到预期结果。例如,若 /tmp 目录中唯一以 foo 开头、以 bar 结尾的文件就是 foo*bar ,那么直接输入 /tmp/foo*bar ,Emacs 也会仅访问该文件。
20.17. 文件名缓存
你可以使用 file name cache文件名缓存 功能,轻松通过文件名定位文件,而无需准确记住文件的存放位置。在迷你缓冲区中输入文件名时,按下 C-TAB (file-cache-minibuffer-complete) 可通过文件名缓存完成补全。重复按下 C-TAB ,会循环展示你初始输入内容的所有可能补全结果。(请注意,在大多数文本终端中无法输入 C-TAB 组合键。)
文件名缓存不会自动填充内容,需通过以下命令将文件名手动加载至缓存中:
M-x file-cache-add-directory RET 目录名 RET- 将指定目录下的所有文件名添加至文件名缓存。
M-x file-cache-add-directory-using-find RET 目录名 RET- 将指定目录及其所有嵌套子目录下的所有文件名添加至文件名缓存。
M-x file-cache-add-directory-using-locate RET 目录名 RET- 通过
locate命令查找指定目录及其所有嵌套子目录下的所有文件,并将这些文件名添加至文件名缓存。 M-x file-cache-add-directory-list RET 变量名 RET- 将指定变量中列出的所有目录下的文件名,全部添加至文件名缓存。该变量需为 Lisp 变量,且其值为目录列表,类似
load-path变量的格式。 M-x file-cache-clear-cache RET- 清空缓存,即移除缓存中的所有文件名。
文件名缓存不具备持久性:其内容仅在当前 Emacs 会话期间保留和维护。你可通过 file-cache-display 命令查看缓存中的内容。
20.18. 查找文件的便捷功能
本节将介绍一些实用工具,可用于查找近期打开的文件、从缓冲区中读取文件名。
执行 M-x recentf-mode 启用 最近文件模式 后,Emacs 会自动维护一份近期打开的文件列表。要从该列表中打开文件,可使用 M-x recentf-open 命令。开启此模式后,'File' 菜单中会新增一个子菜单,你可通过该子菜单快速访问列表中的文件。 M-x recentf-save-list 命令可将当前的最近文件列表(recentf-list) 保存至文件中, M-x recentf-edit-list 命令则可对该列表进行编辑。
若你使用远程文件,可自定义变量 remote-file-name-access-timeout ,该变量用于设置超时秒数 —— 超过此时间后,Emacs 会停止检查是否将该远程文件加入最近文件列表,以此避免程序出现阻塞。
M-x ffap 命令是 find-file 命令的增强版,配备了更智能的启发式默认规则(参见《访问光标位置处的文件和网址》),其匹配逻辑通常基于光标所在位置的文本内容。 部分补全模式 提供了其他扩展 find-file 的功能,可与 ffap 命令配合使用,相关说明参见《补全选项》。
20.19. 查看图像文件
打开图像文件时,Emacs 会自动启用 Image mode图像模式 。在该主模式下,按下 C-c C-c (image-toggle-display) 可在两种显示状态间切换:一是在 Emacs 缓冲区中以图像形式展示文件,二是展示文件的底层文本(或原始字节)格式。此外,按下 C-c C-x (image-toggle-hex-display) ,可在图像显示与十六进制格式显示间切换。 仅当 Emacs 编译时启用了对应图像的显示支持 ,才能以图像形式展示文件。
若显示的图像宽或高超过所在窗口尺寸,使用常规的光标移动按键( C-f 、 C-p 等)可切换显示图像的不同区域。不过 Emacs 默认会自动调整图像大小以适配窗口,因此仅当你通过 image-auto-resize 和 image-auto-resize-on-window-resize 选项自定义了默认行为后,才需要手动移动查看。
你可通过以下命令手动调整图像尺寸:
- 按下
s w执行image-transform-fit-to-window,将图像同时适配窗口的高度和宽度; - 按下
s p执行image-transform-set-percent,按原始尺寸的百分比缩放图像; - 按下
s s执行image-transform-set-scale,指定缩放系数调整图像大小; - 按下
s 0执行image-transform-reset-to-initial,或按下s o执行image-transform-reset-to-original,将所有图像变换恢复至初始状态。
按下 n (image-next-file) 和 p (image-previous-file) ,可分别打开同一目录中的下一个和上一个图像文件。这两个命令会通过 父级 Dired 缓冲区 确定对应的图像文件,在从归档文件(如 zip 、 tar 文件)中打开图像时也能生效,此时会读取归档模式缓冲区的信息;若未找到归档或 Dired 父级缓冲区,Emacs 会自动打开一个 Dired 缓冲区。
浏览图像时,有时需要标记文件以便后续处理(例如选择一组图像复制到其他位置):按下 m (image-mode-mark-file) ,会在所有显示该文件所在目录的 Dired 缓冲区中标记当前文件;若未打开相关 Dired 缓冲区,会在新缓冲区中打开该目录并完成标记。按下 u (image-mode-unmark-file) 可取消文件标记。按下 w (image-mode-copy-file-name-as-kill) ,可将当前缓冲区对应的文件名复制到杀环中。
若图像支持动画效果,按下 RET (image-toggle-animation) 可启动或停止动画;默认情况下动画仅播放一次,若将 image-animate-loop 设为非nil值则会循环播放。按下 f (image-next-frame) 和 b (image-previous-frame) 可逐帧浏览动画,为命令添加数字前缀可一次跳过多帧;按下 F (image-goto-frame) 可跳转到指定帧(帧的索引从 1 开始)。按下 + (image-increase-speed) 加快动画播放速度,按下 - (image-decrease-speed) 减慢速度,按下 r (image-reverse-speed) 反转播放方向,按下 a 0 (image-reset-speed) 将速度恢复为默认值。
除上述图像模式专属的按键绑定外,当光标位于 Emacs 任意缓冲区中的图像上或图像内部时,还可使用以下专用按键:
i +- 将图像放大 20% (
image-increase-size) ,数字前缀可自定义放大比例 —— 前缀为n时,图像尺寸会乘以1 + n/10,例如C-u 5 i +表示将图像放大 50%。 i -- 将图像缩小 20% (
image-decrease-size) ,数字前缀可自定义缩小比例 —— 前缀为n时,图像尺寸会乘以1 - n/10,例如C-u 3 i -表示将图像缩小 30%。 i r- 将图像顺时针旋转 90 度 (
image-rotate) ,添加前缀参数则为逆时针旋转 90 度(该命令对分片图像无效)。 i h- 将图像水平翻转 (
image-flip-horizontally) ,效果等同于通过垂直镜面反射图像(该命令对分片图像无效)。 i v- 将图像垂直翻转 (
image-flip-vertically) ,效果等同于通过水平镜面反射图像(该命令对分片图像无效)。 i o- 将图像保存至文件 (
image-save) ,命令会提示输入保存的文件名。 i c- 裁剪图像 (
image-crop) , 仅当系统安装了可用于图像裁剪的外部程序 时该命令才可用,image-crop-crop-command变量用于指定裁剪程序,默认使用ImageMagick的convert程序。执行该命令后,图像上会叠加一个矩形裁剪框,可通过鼠标移动和调整裁剪框大小;按下m可将鼠标操作从调整尺寸切换为移动裁剪框,按下s可将裁剪框锁定为正方形;调整满意后按下RET回车键完成裁剪,按下q则退出不执行裁剪,裁剪后的图像可通过i o或M-x image-save保存。 i x- 从图像中裁剪出矩形区域并删除 (
image-cut) ,该命令的使用条件与image-crop一致(需通过image-crop-cut-command指定外部程序),与裁剪不同的是,该命令会删除裁剪框内的图像区域,并将该区域填充为image-cut-color指定的颜色;添加前缀参数时,命令会提示自定义填充颜色。
上述图像尺寸调整和旋转命令支持 连续操作 ,即首次按下 i 前缀后,后续可直接按 + 、 - 、 r 等键继续调整,无需重复输入 i 。
若 Emacs 编译时启用了 ImageMagick 库 支持,可通过该库渲染多种格式的图像。 imagemagick-enabled-types 变量列出了 Emacs 可使用 ImageMagick 渲染的图像类型,列表中的每个元素为 ImageMagick 内部的图像类型名(可为符号或对应字符串,例如 BMP 对应 .bmp 格式);将该变量设为 t ,可让 Emacs 对所有支持的图像类型均使用 ImageMagick 渲染。 imagemagick-types-inhibit 变量列出了 禁止 使用 ImageMagick 渲染的图像类型(不受 imagemagick-enabled-types 取值影响),默认列表包含 C、HTML 等类型 —— 这类类型虽能被 ImageMagick 渲染为图像,但 Emacs 不应做此处理;将该变量设为 t ,可彻底禁用 ImageMagick 的图像渲染功能。
若 Emacs 本身不支持某类图像格式,且 image-use-external-converter 设为非nil值,Emacs 会尝试查找外部工具,将该格式图像转换为 PNG 格式后再进行显示,目前支持的转换工具包括 GraphicsMagick、ImageMagick 和 ffmpeg。
此外,你可为特定图像格式添加自定义处理程序,通过 image-converter-add-handler 函数即可实现。例如,要将 Krita 文件以普通图像形式查看,可执行以下代码:
(image-converter-add-handler "kra" (lambda (file data-p) (if data-p (error "Can't decode non-files") (call-process "unzip" nil t nil "-qq" "-c" "-x" file "mergedimage.png"))))
该函数接收两个参数:第一个为文件后缀名,第二个为执行转换的处理函数。处理函数同样接收两个参数:第一个为文件名或图像数据字符串,第二个为布尔值(标识第一个参数是数据还是文件名),处理函数需在当前缓冲区中输出 image-convert-to-format 格式的图像数据。
你还可使用Image-Dired 包以缩略图形式查看图像,详见《在 Dired 中查看图像缩略图》章节。
20.20. 文件集(Filesets)
若你需要定期编辑某一组特定文件,可将其定义为一个 fileset文件集 ,通过文件集可一次性对所有文件执行打开、查询替换、执行 Shell 命令等操作。要使用文件集功能,需先在初始化文件中添加表达式 (filesets-init) (参见《Emacs 初始化文件》章节),该操作会在菜单栏的 'File' 菜单下添加一个 'Filesets' 子菜单。
定义文件集最简便的方式是逐个向其中添加文件:打开目标文件后,执行 M-x filesets-add-buffer RET 文件名 RET ,即可将当前文件添加至指定名称的文件集;若该名称的文件集尚未存在,会自动创建一个新文件集,且初始仅包含当前文件。执行 M-x filesets-remove-buffer 命令,可将当前文件从对应文件集中移除。
你也可通过 M-x filesets-edit 命令(或从「Filesets」菜单中选择「Edit Filesets」选项)直接编辑文件集列表,编辑操作会在自定义缓冲区中完成(参见《简易自定义界面》章节)。默认情况下,文件集是一个简单的文件列表,你也可将文件集定义为 匹配文件名的正则表达式 ,自定义缓冲区中会展示这类复杂文件集的示例。若希望在后续的 Emacs 会话中继续使用这些文件集,记得选择「Save for future sessions保存供后续会话使用」。
执行 M-x filesets-open 命令可打开某个文件集中的所有文件, M-x filesets-close 命令可关闭文件集中的所有文件;执行 M-x filesets-run-cmd 命令,可对某个文件集中的所有文件执行指定的 Shell 命令。这些命令也可通过「Filesets」菜单调用,菜单中会为每个已存在的文件集单独创建一个子菜单。
另有一种不同概念的文件集可参见《版本控制》章节,这类文件集是为执行版本控制操作而组合的文件组, 无命名且不会在 Emacs 会话间持久保存 。
21. 多缓冲区的使用
你在 Emacs 中编辑的文本,会存储在一个名为 buffer缓冲区 的对象中。每次打开文件时,Emacs 都会创建一个缓冲区来存放该文件的文本;每次调用 Dired 目录编辑器时,会生成一个缓冲区来展示目录列表;使用 C-x m 发送消息时,消息文本也会由一个缓冲区承载;查询命令的帮助文档时,文档内容会显示在名为 *Help* 的缓冲区中。
缓冲区会在使用期间一直存在,当不再需要时,会由用户(参见《删除缓冲区》)或 Emacs 自身删除(即「销毁」,例如退出 Emacs 时,参见《退出 Emacs》)。
每个缓冲区都有一个 唯一的名称 ,名称可包含任意字符且无长度限制。当缓冲区在窗口中显示时,其名称会出现在模式行中(参见《模式行》)。缓冲区名称区分大小写,大部分缓冲区由打开文件创建,名称也派生自对应文件名;你也可以创建一个自定义名称的空缓冲区。刚启动的 Emacs 会自带多个缓冲区,其中包含一个名为 *scratch* 的临时缓冲区,可用于执行 Lisp 表达式,该缓冲区不关联任何文件(参见《Lisp 交互缓冲区》)。
在任意时刻,Emacs 中 有且仅有一个缓冲区处于选中状态 ,该缓冲区被称为 current buffer当前缓冲区 。我们常说某条命令「作用于缓冲区」,实际指该命令作用于当前缓冲区。当 Emacs 中只有一个窗口时,该窗口显示的缓冲区即为当前缓冲区;当存在多个窗口时, select window选中窗口 中显示的缓冲区为当前缓冲区(参见《多窗口》)。
缓冲区的内容由一串字符组成,每个字符可选择性地附带一组 文本属性 (参见《文本属性》),用于记录该字符的额外信息。
除文本内容外,每个缓冲区还会记录多项相关信息,包括其关联的文件(若有)、是否被修改、当前启用的 major mode主模式 和 minor mode次要模式 (参见《主模式与次要模式》)等。这些信息都存储在 缓冲区局部变量 中 —— 这类变量可在不同缓冲区中拥有不同的值(参见《局部变量》)。
缓冲区的大小存在上限,该上限由 Emacs 整数类型所能表示的最大缓冲区位置决定,因为 Emacs 会通过该数据类型跟踪缓冲区位置。对于常见的 64 位系统,缓冲区的最大容量为 2^{61} - 2 字节,约 2 艾字节(EiB);对于常见的 32 位系统,最大容量通常为 2^{29} - 2 字节,约 512 兆字节(MiB)。此外,缓冲区的实际大小还会受系统内存容量的限制。
21.1. 创建与选择缓冲区
C-x b buffer RET- 选中或创建指定名称的缓冲区 (
switch-to-buffer) 。 C-x 4 b buffer RET- 功能同上,在另一个窗口中选中该缓冲区 (
switch-to-buffer-other-window) 。 C-x 5 b buffer RET- 功能同上,在独立的框架中选中该缓冲区 (
switch-to-buffer-other-frame) 。 C-x LEFT- 选中缓冲区列表中的上一个缓冲区 (
previous-buffer) 。 C-x RIGHT- 选中缓冲区列表中的下一个缓冲区 (
next-buffer) 。 C-u M-g M-gC-u M-g g- 读取数字
n,在另一个窗口中,将光标移至 除当前缓冲区外最近选中的缓冲区 的第n行。
C-x b (switch-to-buffer) 命令会通过迷你缓冲区读取缓冲区名称,随后将该缓冲区设为当前缓冲区,并在当前选中的窗口中展示。若输入为空,则会选中 当前未在任何窗口中显示、且最近一次被设为当前缓冲区 的那个缓冲区。
输入缓冲区名称时,可使用常规的补全和历史记录命令(参见《迷你缓冲区》)。注意, C-x b 及相关命令在迷你缓冲区补全时,采用 permissive completion with confirmation 带确认的宽松补全 规则:若按下 RET 回车时,迷你缓冲区中的文本对应的是不存在的缓冲区,Emacs 会打印 '[Confirm]',你需要再次按下 RET 回车,确认创建该名称的缓冲区。详细规则参见《补全的退出方式》,其他补全选项与功能参见《补全选项》。
若指定的缓冲区不存在, C-x b 会创建一个 未关联任何文件的新空缓冲区 ,并将其选中供编辑使用。新缓冲区的主模式由变量 major-mode 的默认值决定,默认为主基础模式(Fundamental mode)(参见《主模式》)。创建新缓冲区的常见用途之一,是记录临时笔记。若你尝试保存该缓冲区,Emacs 会提示输入文件名,且会根据该文件名重新确定缓冲区的主模式(参见《文件模式的选择》)。
若需要在少数几个缓冲区之间快速切换,可使用 C-x LEFT 和 C-x RIGHT 命令。 C-x 左方向键 (previous-buffer) 会选中 上一个缓冲区 (按当前框架中最近的选中顺序), C-x 右方向键 (next-buffer) 则按相反顺序切换缓冲区。两个命令均支持数字前缀参数,用于指定切换的次数。
若要在 非当前窗口 中选中缓冲区(参见《多窗口》),可输入 C-x 4 b (switch-to-buffer-other-window) 。该命令会通过迷你缓冲区提示输入缓冲区名称,在另一个窗口中展示该缓冲区,并将该窗口设为选中状态。
类似地, C-x 5 b (switch-to-buffer-other-frame) 会提示输入缓冲区名称,在另一个框架中展示该缓冲区(参见《框架与图形化显示》),并选中该框架。若该缓冲区已在其他框架的某个窗口中显示,Emacs 会直接选中该窗口和框架,而非创建新框架。
关于 C-x 4 b 和 C-x 5 b 命令如何选择展示缓冲区的窗口和 / 或框架,参见《在窗口中展示缓冲区》。
此外, C-x C-f 及其他所有打开文件的命令,也可用于切换至已存在的、关联该文件的缓冲区(参见《访问文件》)。
C-u M-g M-g (即带普通前缀参数的 goto-line 命令),会通过迷你缓冲区读取数字 n ,在另一个窗口中选中 除当前缓冲区外最近选中的缓冲区 ,并将光标移至该缓冲区的第 n 行开头。该命令主要适用于 某一缓冲区中引用了另一缓冲区行号 的场景:若光标位于某个数字上,或紧邻数字后方, goto-line 会将该数字作为 n 的默认值。注意,非单纯 C-u 的前缀参数,执行效果会不同:例如 C-u 4 M-g M-g ,会直接将光标移至 当前缓冲区 的第 4 行,而不会从迷你缓冲区读取数字。(注意,无前缀参数的 M-g M-g ,会读取数字 n 并将光标移至当前缓冲区的第 n 行,参见《移动光标位置》。)
Emacs 会将 以空格开头 的缓冲区名用于内部操作,这类缓冲区会被做一些细微的特殊处理 —— 例如,默认不会记录撤销信息。建议你避免使用此类名称命名自己的缓冲区。
21.2. 列出已有缓冲区
C-x C-b- 列出所有已存在的缓冲区 (
list-buffers) 。
键入 C-x C-b 可展示所有已存在的缓冲区列表,该操作会在名为 *Buffer List* 的缓冲区中弹出一个缓冲区菜单。列表中的每一行对应一个缓冲区,展示其缓冲区名、大小、主模式以及关联的文件。缓冲区按 最近成为当前缓冲区的顺序 排列,最近使用的缓冲区会显示在最前方。本节介绍缓冲区列表的展示形式及列表中各类标识的含义; *Buffer List* 缓冲区的专用模式及可使用的相关命令,详见《对多个缓冲区执行操作》章节。
列表每行第一个字段中的 '.' 表示该缓冲区为 当前缓冲区 , '%' 表示该缓冲区为 只读缓冲区 , '*' 表示该缓冲区 已被修改 。若有多个缓冲区标记为已修改,便是时候使用 C-x s 命令保存部分缓冲区了(参见《文件保存相关命令》)。以下是缓冲区列表的示例:
CRM Buffer Size Mode File
. * .emacs 3294 ELisp/l ~/.emacs
% *Help* 101 Help
search.c 86055 C ~/cvs/emacs/src/search.c
% src 20959 Dired by name ~/cvs/emacs/src/
* *mail* 42 Mail
% HELLO 1607 Fundamental ~/cvs/emacs/etc/HELLO
% NEWS 481184 Outline ~/cvs/emacs/etc/NEWS
*scratch* 191 Lisp Interaction
* *Messages* 1554 Messages
*Help* 缓冲区由帮助查询操作创建(参见《帮助功能》),该缓冲区未关联任何文件; src 缓冲区是对目录 ~/cvs/emacs/src/ 执行 Dired 目录浏览操作后生成的。为该命令添加前缀参数(如执行 C-u C-x C-b ),可仅列出 关联了文件 的缓冲区。
默认情况下, list-buffers 命令会 忽略名称以空格开头 的缓冲区(关联了文件的除外),这类缓冲区为 Emacs 的内部使用缓冲区(可通过 I 命令取消该限制,详见《对多个缓冲区执行操作》章节)。
21.3. 缓冲区的各类杂项操作
C-x C-q- 切换缓冲区的只读状态 (
read-only-mode) 。 C-x x r RET 新缓冲区名 RET- 修改当前缓冲区的名称 (
rename-buffer) 。 C-x x u- 为当前缓冲区重命名,在原名称后添加数字后缀以保证唯一性 (
rename-uniquely) 。 M-x view-buffer RET buffer RET- 滚动浏览指定缓冲区的内容(参见「视图模式」章节)。
缓冲区可设置为 read-only只读状态 ,处于该状态时,无法执行插入或删除文本的相关命令。(但部分其他命令如 C-x RET f ,仍可将其标记为已修改,参见「为文件文本指定编码系统」章节。)模式行的左侧边缘会显示 '%%' 或 '%*' 标识,以此表示该缓冲区为只读缓冲区(参见「模式行」章节)。只读缓冲区通常由 Dired、Rmail 这类子系统创建,这类子系统会提供专门的命令对缓冲区文本进行操作;若打开的文件在系统权限中被设置为不可写,对应的缓冲区也会被设为只读。
执行 C-x C-q (read-only-mode) ,可将只读缓冲区切换为可写状态,也可将可写缓冲区设为只读状态。该命令的实现原理是修改 buffer-read-only 变量 —— 该变量为缓冲区局部变量,若其值为非nil,则对应缓冲区为只读。若将 view-read-only 选项设为非nil,通过 C-x C-q 将缓冲区设为只读时,会同时为该缓冲区启用视图模式(参见「视图模式」章节)。
执行 C-x x r (rename-buffer) 命令可修改当前缓冲区的名称,需在迷你缓冲区中输入新名称,该命令无默认名称可选;若指定的新名称已被其他缓冲区使用,会触发错误且重命名操作失败。
执行 C-x x u (rename-uniquely) 命令会为当前缓冲区生成一个相似的唯一名称,具体方式是在原名称后添加数字后缀,该命令无需传入参数。此命令适用于创建多个 Shell 缓冲区的场景:若先为 *shell* 缓冲区重命名,再执行 M-x shell 命令,Emacs 会创建一个新的 *shell* 缓冲区,而原 Shell 缓冲区会以新名称继续存在。该方法也适用于邮件缓冲区、编译缓冲区,以及 Emacs 中大多数会创建特定名称专用缓冲区的功能。(对于部分此类功能,如 M-x compile 、 M-x grep ,再次执行命令前需先切换至其他缓冲区,否则即便原缓冲区已重命名,该功能仍会复用当前缓冲区。)
执行 M-x append-to-buffer 和 C-x x i (insert-buffer) 命令,也可实现将文本从一个缓冲区复制至另一个缓冲区的操作(参见「文本累积」章节)。
21.4. 关闭缓冲区
若 Emacs 会话持续运行一段时间,可能会累积大量缓冲区,此时删除不再需要的缓冲区会让操作更便捷(部分其他编辑器将此操作称为 “close”,会提及 “closing the buffer” 或 “closing the file”)。在大多数操作系统中,删除缓冲区会将 Emacs 为该缓冲区占用的内存释放给系统,供其他程序使用。以下是用于删除缓冲区的相关命令:
C-x k buffer RET- 删除指定缓冲区 (
kill-buffer) 。 M-x kill-some-buffers- 逐个确认并删除缓冲区。
M-x kill-matching-buffers- 确认并删除所有名称匹配指定正则表达式的缓冲区。
M-x kill-matching-buffers-no-ask- 功能与
kill-matching-buffers类似,无需确认直接删除。
C-x k (kill-buffer) 命令用于删除单个缓冲区,需在迷你缓冲区中指定缓冲区名称;若直接在迷你缓冲区中按 RET 回车,默认删除 当前缓冲区 。若删除的是当前缓冲区,Emacs 会将另一个缓冲区设为当前缓冲区 —— 该缓冲区为近期曾作为当前缓冲区、且当前未在任何窗口中显示的缓冲区。若要删除的是关联了文件且已被修改的缓冲区,必须输入 yes 确认后,删除操作才会执行。
M-x kill-some-buffers 命令会逐个对所有缓冲区进行删除确认,输入 yes 即表示删除该缓冲区,效果与 kill-buffer 命令一致。该命令会忽略 Emacs 内部使用的、名称以空格开头的缓冲区。
M-x kill-matching-buffers 命令会先提示输入一个正则表达式,随后删除所有名称匹配该表达式的缓冲区(参见《正则表达式的语法》)。与 kill-some-buffers 命令相同,该命令在删除每个缓冲区前都会要求确认,且默认忽略 Emacs 内部使用的、名称以空格开头的缓冲区;若为该命令添加前缀参数,则会一并删除内部缓冲区。 M-x kill-matching-buffers-no-ask 命令的功能与 kill-matching-buffers 一致,区别是删除匹配的缓冲区时 无需逐次确认 。
使用缓冲区菜单功能也能便捷地删除多个缓冲区,详见《对多个缓冲区执行操作》章节。
若希望在每次删除缓冲区时执行自定义操作,可向 kill-buffer-hook 钩子中添加钩子函数(参见《钩子》章节)。
许多用户会让 Emacs 会话连续运行数日,此时会话中会堆积数天前使用过的缓冲区, M-x clean-buffer-list 命令是清理这类缓冲区的便捷方式 —— 该命令会删除所有长期未使用且未被修改的缓冲区。默认情况下,若某个普通缓冲区已 3 天未被显示,就会被该命令删除;你也可以指定某些缓冲区为 禁止自动删除 ,同时将另一些缓冲区的自动删除阈值设为仅一小时未使用。该命令的这些默认规则及其他行为,均可通过自定义 clean-buffer-list 文档字符串中描述的相关选项来调整。
你也可以启用 Midnight mode 午夜模式 ,让系统每日自动执行缓冲区清理操作。午夜模式会在每日午夜触发,执行 clean-buffer-list 命令,或你添加到 midnight-hook 普通钩子中的其他自定义函数(参见《钩子》章节)。启用该模式的方法是,在自定义缓冲区中将变量 midnight-mode 设为 t (参见《简易自定义界面》章节)。
21.5. 对多个缓冲区执行批量操作
M-x buffer-menu- 打开缓冲区菜单,可编辑 Emacs 所有缓冲区的列表。
M-x buffer-menu-other-window- 功能同上,在另一个窗口中打开缓冲区菜单。
通过 C-x C-b 打开的缓冲区菜单(参见《列出已有缓冲区》)并非仅用于罗列缓冲区,还可通过类 Dired 的操作界面(参见《目录编辑器 Dired》),对缓冲区执行保存、删除、显示等各类操作。
使用缓冲区菜单的操作方法:按下 C-x C-b 后,切换至显示 *Buffer List* 缓冲区的窗口即可;也可直接输入 M-x buffer-menu ,在当前选中的窗口中打开缓冲区菜单;此外, M-x buffer-menu-other-window 命令会在另一个窗口中打开缓冲区菜单并自动选中该窗口。
缓冲区菜单为只读缓冲区,仅可通过本节介绍的专用命令进行操作,常规的光标移动命令在该缓冲区中均适用。以下命令均作用于光标所在行对应的缓冲区:
d- 为缓冲区标记删除(killing)标识,随后将光标移至下一行 (
Buffer-menu-delete) 。标记后,该行缓冲区名称前会显示字符 'D' 作为删除标识,实际删除操作仅在按下x命令后执行(见下文)。 C-d- 功能与
d命令一致,区别是标记后将光标向上移动 (Buffer-menu-delete-backwards) 。 s- 为缓冲区标记保存标识 (
Buffer-menu-save) 。标记后,该行缓冲区名称前会显示字符S作为保存标识,实际保存操作仅在按下x命令后执行。可对同一个缓冲区同时标记保存和删除标识。 x- 执行所有已标记的删除和保存操作 (
Buffer-menu-execute) 。 u- 清除光标所在行的所有标识,随后将光标向下移动 (
Buffer-menu-unmark) 。若添加数字前缀参数,清除标识后光标会向上移动。 DEL- 将光标移至上一行,并清除该行的所有标识 (
Buffer-menu-backup-unmark) 。 M-DEL- 清除所有行中指定类型的标识 (
Buffer-menu-unmark-all-buffers) 。按下该命令后会提示输入一个字符,随后清除所有以该字符为标识的标记;直接按RET回车键则清除所有标识。 U- 清除所有行的所有标识 (
Buffer-menu-unmark-all) 。
上述的标识清除命令、 d 命令和 C-d 命令,均支持数字前缀参数作为重复执行的次数。
以下命令会立即对光标所在行对应的缓冲区执行操作,且均支持数字前缀参数作为重复执行的次数:
~- 将缓冲区标记为未修改状态 (
Buffer-menu-not-modified) ,参见《文件保存相关命令》。 %- 切换缓冲区的只读状态 (
Buffer-menu-toggle-read-only) ,参见《缓冲区的杂项操作》。 t- 将该缓冲区作为标签表打开 (
Buffer-menu-visit-tags-table) ,参见《选择标签表》。
以下命令用于选中单个或多个其他缓冲区:
q- 退出缓冲区菜单 (
quit-window) ,原窗口会显示最近一次可见的缓冲区。 RETf- 选中光标所在行的缓冲区,替换当前窗口中的
*Buffer List*缓冲区 (Buffer-menu-this-window) 。 o- 在另一个窗口中选中光标所在行的缓冲区,效果等同于执行
C-x 4 b命令,保留*Buffer List*缓冲区可见 (Buffer-menu-other-window) 。 C-o- 在另一个窗口中显示光标所在行的缓冲区,不选中该窗口 (
Buffer-menu-switch-other-window) 。 1- 在占满整个框架的窗口中选中光标所在行的缓冲区 (
Buffer-menu-1-window) 。 2- 在当前框架中拆分出两个窗口,一个窗口选中光标所在行的缓冲区,另一个窗口显示此前的当前缓冲区(
*Buffer List*除外) (Buffer-menu-2-window) 。 b- 将光标所在行的缓冲区置为未激活状态 (
Buffer-menu-bury) ,即移至缓冲区列表的末尾。 m- 为缓冲区标记显示标识,若按下
v命令退出菜单,该缓冲区会在另一个窗口中显示 (Buffer-menu-mark) 。标记后,该行开头会显示字符 '>' 作为显示标识(一个缓冲区不可同时标记删除和显示标识)。 v- 选中光标所在行的缓冲区,同时在其他窗口中显示所有带
m标记的缓冲区 (Buffer-menu-select) 。若未标记任何带显示标识的缓冲区,该命令的效果与1命令一致。
以下命令作用于整个缓冲区列表:
S- 根据光标所在列的属性对缓冲区菜单的条目进行排序 (
tabulated-list-sort) 。若添加数字前缀参数n,则根据第n列的属性进行排序。 }- 将当前列的宽度增加
n个字符(n为数字前缀参数)。 {- 将当前列的宽度减少
n个字符(n为数字前缀参数)。 T- 隐藏或重新显示非文件类缓冲区对应的行 (
Buffer-menu-toggle-files-only) ,该命令可切换缓冲区列表中是否包含此类缓冲区。 I- 切换是否显示内部缓冲区(名称以空格开头的缓冲区)。
默认情况下,当创建或删除缓冲区时, *Buffer List* 缓冲区不会自动更新,其内容仅为静态文本。若执行了缓冲区的创建、删除或重命名操作,按下 g 键 (revert-buffer) 即可更新 *Buffer List* 的内容,展示最新的缓冲区状态。若该缓冲区未被标记为已修改,在其中启用自动恢复模式后,缓冲区会按照 auto-revert-interval 变量设定的秒数定期自动更新。全局自动恢复模式仅在 global-auto-revert-non-file-buffers 变量值为非 nil 时,才对 *Buffer List* 缓冲区生效,具体细节参见 global-auto-revert-non-file-buffers 变量的说明。
21.6. 间接缓冲区
indirect buffer间接缓冲区 共享另一缓冲区的文本内容,该缓冲区被称为此间接缓冲区的 base buffer基缓冲区 。在某种程度上,它相当于文件系统中符号链接在缓冲区上的对应实现。
相关命令
M-x make-indirect-buffer RET base-buffer RET indirect-name RET- 创建以指定基缓冲区为文本源、并命名为指定名称的间接缓冲区。
M-x clone-indirect-buffer 回车- 创建当前缓冲区的副本间接缓冲区(与原缓冲区完全联动)。
C-x 4 c- 创建当前缓冲区的副本间接缓冲区,并在新窗口中选中该间接缓冲区 (
clone-indirect-buffer-other-window) 。
核心特性
间接缓冲区的文本始终与基缓冲区 完全一致 :对任意一方的编辑修改,都会立即在另一方中显示。此处的 "Text" 包含字符本身及其所有 文本属性 。
但在其他所有方面,间接缓冲区与基缓冲区是 完全独立 的,二者可拥有:不同的缓冲区名称、不同的光标位置、不同的内容窄化范围、不同的标记、不同的叠加层、不同的主模式,以及不同的局部变量。
文件操作与缓冲区生命周期
- 间接缓冲区 无法直接访问文件 ,但其基缓冲区可以;若尝试保存间接缓冲区,实际会执行基缓冲区的保存操作。
- 删除基缓冲区会 连带失效 其所有间接缓冲区;而删除间接缓冲区,对其基缓冲区无任何影响。
典型用法
间接缓冲区的常用场景之一是为大纲文档创建 多视图展示 ,具体可参考《在多视图中查看单个大纲》章节。
快速创建方式
使用快捷键 C-x 4 c 是创建间接缓冲区最快捷的方式,该命令会以当前缓冲区为基缓冲区,直接生成副本间接缓冲区并在新窗口打开。若带数字参数执行该命令,会提示用户输入间接缓冲区的自定义名称;无参数时,默认以原缓冲区名称加后缀 '<n>' (n 为数字)命名。
通用创建方式
使用命令 M-x make-indirect-buffer 可创建自定义的间接缓冲区,该命令会通过迷你缓冲区依次提示用户输入 基缓冲区名 和 间接缓冲区名 ,灵活性更高。
相关钩子函数
创建间接缓冲区的所有函数,都会在缓冲区创建完成后执行钩子函数 clone-indirect-buffer-hook 。该钩子执行时,新创建的间接缓冲区会成为当前缓冲区。
注意事项
对缓冲区文本进行修改时, 修改钩子仅会在基缓冲区中执行 —— 原因是这些钩子上的大部分函数并未适配间接缓冲区的运行环境,无法在其中正常工作。因此,若需要在间接缓冲区中使用修改钩子函数,需手动将该函数添加到 基缓冲区 的对应钩子中,并让函数在目标间接缓冲区中执行相关操作。
21.7. 缓冲区操作的便捷功能与相关定制
本节介绍多款可提升缓冲区切换效率的模式与功能。
21.7.1. 让缓冲区名称唯一化
当多个缓冲区访问文件名相同的文件时,Emacs 必须为这些缓冲区分配互不重复的名称。默认命名方式会 根据文件所在的目录名称添加后缀 ,以此区分。例如,若同时访问文件 /foo/bar/mumble/name 和 /baz/quux/mumble/name ,对应的缓冲区会分别命名为 'name<bar/mumble>' 和 'name<quux/mumble>' 。Emacs 会自动添加足够多的目录层级,确保缓冲区名称唯一。
你可以通过自定义选项 uniquify-buffer-name-style ,选择多种不同的 缓冲区唯一名称构建规则 。
'forward' 正向命名法 会将文件目录的部分名称加在缓冲区名称 开头 :例如访问 /u/rms/tmp/Makefile 和 /usr/projects/zaphod/Makefile 时,缓冲区会被命名为 'tmp/Makefile' 和 'zaphod/Makefile' 。
与之相对, 'post-forward' 后置正向命名法 会将目录名加在缓冲区名称后方,格式为 '文件名|目录名' ,上述两个文件对应的缓冲区会被命名为 'Makefile|tmp' 和 'Makefile|zaphod' 。默认使用的 post-forward-angle-brackets 后置正向尖括号命名法 与后置正向命名法逻辑一致,仅将唯一路径部分用尖括号包裹,也是前文示例中使用的命名方式。
reverse 反向命名法 会将目录名加在缓冲区名称后方,格式为 '文件名\目录名' ,上述示例会被命名为 'Makefile\tmp' 和 'Makefile\zaphod' 。后置正向命名法与反向命名法的核心区别体现在 单个目录名不足以区分文件 的场景:此时反向命名法会将目录层级 逆序拼接 ,例如文件 /top/middle/file 会被命名为 'file\middle\top' ;而后置正向命名法会将目录层级 正序拼接 在文件名后,格式为 'file|top/middle' 。
若将 uniquify-buffer-name-style 设为 nil ,Emacs 会采用最简命名规则,仅在缓冲区名称后依次追加 '<2>' 、 '<3>' 等数字后缀以保证唯一。
uniquify-buffer-name-style 的取值也可以是 自定义函数 ,该函数需接收两个参数: base (字符串类型,为缓冲区基础名称)和 extra-strings (字符串列表类型,为用于区分的目录片段)。例如,后置正向尖括号命名法的默认实现可自定义为如下函数:
(defun my-post-forward-angle-brackets (base extra-string) (concat base \"<\" (mapconcat #'identity extra-string \"/\") \">\"))
如果在输入缓冲区名称前,你会先查看所有缓冲区的命名再选择,那么采用哪种目录名拼接规则其实影响不大。但对于熟练的 Emacs 用户而言,若熟知所使用的命名规则,无需查看即可直接输入缓冲区名称,此时你会发现某一种规则会更便于记忆和快速使用。
21.7.2. 迷你缓冲区快速选择(方式)
补全预览模式(Icomplete mode)为在迷你缓冲区中从候选补全项里快速选择内容提供了便捷方式。启用该模式后,在迷你缓冲区中输入内容时,会 实时显示 所有与已输入字符串匹配的候选补全项列表。
在输入过程中的任意时刻,可按下 C-j 选中列表中的 首个补全项 。因此,选中特定补全项的核心思路,是将其调整为列表中的首个选项,具体有两种实现方式:
- 继续输入补全项的更多字符, 缩小候选范围 ,将目标项上方的无关补全项过滤掉;
- 使用快捷键
C-.和C-,轮换候选列表 ,直至目标缓冲区 / 补全项出现在列表首位。
按下 M-TAB 同样会选中列表中的首个补全项,与 C-j 的区别是 不会退出迷你缓冲区 ,可对选中的补全项继续编辑。该快捷键在输入文件名时尤为常用,多次按下可逐级匹配目录层级,快速定位目标路径。
若要为迷你缓冲区启用补全预览模式,可执行命令 M-x icomplete-mode ,或将配置变量 icomplete-mode 自定义设为 t (参见简易自定义界面)。
此外,还可通过将配置变量 icomplete-in-buffer 设为 t ,为快捷键 C-M-i (completion-at-point ,即点处补全)额外启用补全预览模式。针对缓冲区内的补全操作,配置变量 completion-auto-help 用于控制补全预览模式的 候选补全项显示时机 ,其默认值 t 表示首次按下 C-M-i 时,即显示候选补全项列表。
默认情况下,按下 C-M-i 时,补全预览模式的缓冲区内置候选补全项显示,与 *Completions* 补全缓冲区会 同时出现 。若启用了缓冲区内置的补全预览功能( icomplete-in-buffer ),可隐藏自动弹出的 *Completions* 缓冲区,只需在 Emacs 初始化文件中添加以下配置(参见 Emacs 初始化文件相关说明):
(advice-add 'completion-at-point :after #'minibuffer-hide-completions)
补全预览模式的替代方案是 Fido 补全模式(Fido mode),该模式与补全预览模式功能高度相似,同时保留了热门扩展 Ido 模式的部分核心功能(其名称正是由 “Fake Ido” 衍生而来)。除基础补全功能外, Fido 补全模式还有以下特性:
- 可使用
C-s和C-r快捷键轮换候选补全项列表; - 可通过
C-k在候选列表中直接删除文件、关闭缓冲区; - 默认采用 flex柔性匹配 作为补全样式(参见补全候选项的选择规则)。
若要修改该模式的默认补全样式,可在初始化文件中添加以下配置:
(defun my-icomplete-styles () (setq-local completion-styles '(initials flex))) (add-hook 'icomplete-minibuffer-setup-hook 'my-icomplete-styles)
启用 Fido 补全模式的方式为:执行命令 M-x fido-mode ,或将配置变量 fido-mode 自定义设为 t (参见简易自定义界面)。
补全预览模式与 Fido 补全模式,默认会在与提示语同一行显示候选补全项。若要在提示语下方 垂直展示 所有补全候选项,可执行命令 M-x icomplete-vertical-mode ,或将配置变量 icomplete-vertical-mode 自定义设为 t (参见简易自定义界面)。
21.7.3. 定制缓冲区菜单
M-x bs-show- 生成缓冲区列表,功能与
M-x list-buffers类似,且支持自定义配置。 M-x ibuffer- 生成缓冲区列表,并可通过类 Dired 的操作方式对缓冲区进行管理。
M-x bs-show 会弹出一个缓冲区列表,与 C-x C-b 默认显示的列表功能一致,但 支持更灵活的自定义显示规则 。例如,你可以指定要展示的缓冲区属性项、缓冲区名称列的最小和最大宽度、用于匹配 永不显示 的缓冲区名称正则表达式,以及 始终显示 的缓冲区名称正则表达式等。若你更偏好该缓冲区列表,可将此命令绑定到 C-x C-b 快捷键上。如需自定义该缓冲区列表,可使用 bs 自定义组(参见简易自定义界面),或直接调用 bs-customize 命令进行配置。
MSB 全局次要模式(MSB 为 "mouse select buffer" 鼠标选择缓冲区的英文缩写)提供了一套风格不同且支持自定义的鼠标缓冲区菜单,你可根据喜好启用。该模式会用自身的命令,替换原本绑定在 C-Down-mouse-1 和 C-F10 上的 mouse-buffer-menu 相关命令,同时也会修改菜单栏中的缓冲区菜单。你可在msb自定义组中对该菜单进行个性化配置。
IBuffer 是一款专门用于查看缓冲区列表的 主模式 ,它支持以类 Dired 的方式(参见《目录编辑器 Dired》章节)对缓冲区进行操作,包括缓冲区过滤、标记、多种方式排序,以及对标记的缓冲区执行批量操作等。
22. 多窗口
Emacs 可将一个框架拆分为两个或多个窗口。多个窗口既可以显示不同缓冲区的内容,也可显示同一缓冲区的不同部分。多框架必然对应多窗口,因为每个框架都有其独立的窗口集,且每个窗口仅归属于一个框架。
22.1. Emacs 窗口的概念
每个 Emacs 窗口在任一时刻仅显示一个 Emacs 缓冲区。单个缓冲区可同时显示在 多个窗口 中:若缓冲区内容发生修改,所有显示该缓冲区的窗口都会实时同步更新修改内容。但这些窗口可展示缓冲区的不同部分,因为 每个窗口都有独立的光标位置 。
任一时刻,仅有一个 Emacs 窗口为 选中窗口 ,该窗口当前显示的缓冲区即为 当前缓冲区 。在图形化显示界面中,选中窗口的光标为 实心闪烁光标 ,未选中窗口的光标为空心方框;在文本终端中,光标仅会显示在选中窗口内。相关细节参见《光标显示》章节。
光标移动类命令 仅会改变选中窗口 的光标位置,不会影响其他 Emacs 窗口的光标位置 —— 即便这些窗口显示的是同一个缓冲区。缓冲区切换类命令(如 C-x b )的行为同理,完全不会对其他窗口产生影响。不过存在部分特殊命令(如 C-x 4 b ),可选中其他窗口并在其中切换缓冲区。此外,所有在窗口中展示信息的命令(例如 C-h f (descibe-function) 、 C-x C-b (list-buffers) ),通常都会在 未选中窗口 中展示对应缓冲区内容,且不会改变当前的选中窗口。
当多个窗口显示同一个缓冲区时,各窗口可拥有 不同的选区 ,原因是各窗口的光标位置相互独立;但所有窗口共享同一个 标记位置 ,因为每个缓冲区仅存在一个标记位。
每个窗口都配有独立的 模式行 ,用于显示该窗口当前所展示缓冲区的名称、修改状态,以及该缓冲区的主模式和次要模式。选中窗口的模式行会以 不同颜色 显示,相关细节参见《模式行》章节。
22.2. 拆分窗口
C-x 2- 将选中的窗口拆分为两个上下排列的窗口 (
split-window-below) 。 C-x 3- 将选中的窗口拆分为两个左右并排的窗口 (
split-window-right) 。 C-mouse-2- 在某一窗口的模式行上点击,拆分该窗口。
C-x 2 (split-window-below) 会将选中窗口拆分为两个上下排布的窗口,拆分后原窗口为上方的选中窗口,新拆分出的窗口位于下方。两个窗口会保留拆分前的光标位置,且显示缓冲区的同一部分内容(或尽可能接近的区域);若有需要,窗口会自动滚动以保证光标处于可视区域。默认情况下,拆分后的两个窗口各占原窗口高度的一半。带正数字参数执行该命令,可指定上方窗口的行数;带负数字参数,则指定下方窗口的行数。
若将变量 split-window-keep-point 设为 nil ,执行 C-x 2 时,Emacs 会调整两个窗口显示的缓冲区内容范围,同时修改各窗口的光标位置,尽可能保持屏幕上的文本与拆分前一致;此外,若拆分前光标位于原窗口的下半区域,拆分后会选中下方的窗口,而非上方窗口。
C-x 3 (split-window-right) 会将选中窗口拆分为两个左右并排的窗口,左侧为选中窗口,右侧窗口显示同一缓冲区的同一部分内容,且光标位置与原窗口一致。带正数字参数执行该命令,可指定左侧窗口的列数;带负数字参数,则指定右侧窗口的列数。
使用 C-x 3 拆分窗口后,每个窗口的宽度都会小于框架的完整宽度。若窗口过窄,且文本启用了折行显示,缓冲区内容会难以阅读(参见折行显示章节)。因此,当窗口宽度小于 50 列时,Emacs 会自动切换为行截断模式。该自动截断行为不受变量 truncate-lines 控制(参见行截断章节),而是由变量 truncate-partial-width-windows 管理:若该变量值为正整数(默认值为 50),则表示非全宽窗口的最小宽度阈值,低于此值即触发自动行截断;若值为 nil ,则禁用自动行截断;若为其他非nil值,则所有非全宽窗口无论宽度多少,均会启用行截断。窗口的总宽度以 window-total-width 函数返回的列数为单位(参见《Emacs Lisp 参考手册》的窗口大小章节),包含边缘区域、折行与截断符号、边距和滚动条的宽度。
在文本终端中,左右并排的窗口之间会显示一个垂直分隔线,该分隔线使用 vertical-border 面属性绘制。
在某一窗口的模式行上点击 C-mouse-2 ,会拆分该窗口,且在点击位置生成垂直分隔线。根据 Emacs 的编译版本,也可在滚动条上点击 C-mouse-2 2拆分窗口,此时会在点击位置生成水平分隔线(该功能在 Emacs 使用 GTK + 滚动条时无效)。
默认情况下,拆分窗口时,Emacs 会为拆分后的每个窗口分配 框架默认字体大小整数倍 的尺寸,这可能导致屏幕空间在各窗口间分配不均。若将变量 window-resize-pixelwise 设为非nil值,Emacs 会为每个窗口分配相同的像素数(若初始尺寸为奇数像素,可能会相差 1 个像素)。注意,若框架的像素尺寸并非字符尺寸的整数倍,即便该选项设为 nil ,至少有一个窗口也会按像素单位调整大小
22.3. 使用其他窗口
C-x o- 选中另一窗口 (
other-window) 。 C-M-v- 向上滚动下一个窗口的内容 (
scroll-other-window) 。 C-M-S-v- 向下滚动下一个窗口的内容 (
scroll-other-window-down) 。 C-M-S-l- 重定下个窗口的内容居中显示 (
recenter-other-window) 。 mouse-1- 在窗口的文本区域点击鼠标左键,会选中该窗口并将光标移动至点击位置;在模式行上点击则仅选中窗口,不会改变其中的光标位置。
使用键盘可通过输入 C-x o (other-window) 来切换窗口,此处为字母 o (代表 “other”,即其他),并非数字 0。当窗口数量多于两个时,该命令会按 循环顺序 遍历所有窗口,一般遵循从上到下、从左到右的次序;在选中最右侧、最下方的窗口后,会重新回到左上角的第一个窗口。带 数字参数 执行该命令,可按循环顺序连续切换指定次数的窗口;带 负参数 则按相反的循环方向切换。当迷你缓冲区处于激活状态时,迷你缓冲区窗口会作为循环中的最后一个窗口;你可从迷你缓冲区窗口切换至其他任意窗口,后续可再次切回并继续输入迷你缓冲区所需的参数。详见《在迷你缓冲区中编辑》章节。
other-window 命令默认仅在 当前框架 内切换至下一个窗口(除非另行配置)。若你在多框架环境下工作,希望将所有框架中的窗口都纳入循环切换范围,可将 C-x o 重新绑定至 next-window-any-frame 命令(关于如何重新绑定命令,详见《交互式修改按键绑定》章节)。
常规的滚动命令(详见《控制显示效果》章节)仅对 选中窗口 生效,Emacs 也提供了专门用于滚动下一个窗口的命令。 C-M-v (scroll-other-window) 会滚动 C-x o 即将选中的那个窗口,该命令的其他行为与 C-v 一致:二者均会让缓冲区文本相对窗口向上滚动,且均可接收正、负数字参数。(在迷你缓冲区中, C-M-v 不会滚动标准循环顺序中的下一个窗口,而是滚动与迷你缓冲区关联的帮助窗口(若存在),详见《在迷你缓冲区中编辑》章节。) C-M-S-v (scroll-other-window-down) 以类似方式实现下一个窗口的向下滚动;同理, C-M-S-l (recenter-other-window) 的作用,等同于在次窗口中执行 C-l (recenter-top-bottom) 命令。
若将变量 mouse-autoselect-window 设为非nil值,将鼠标移至其他窗口上方时,会自动选中该窗口,该功能默认处于关闭状态。
22.4. 在另一窗口中显示内容
C-x 4 是一组命令的前缀键,这类命令会在 另一窗口 中切换至指定缓冲区 —— 该窗口可以是已存在的其他窗口,也可以是通过拆分当前选中窗口新建的窗口。Emacs 如何选择或创建目标窗口的规则,详见《display-buffer 函数的工作机制》章节。
C-x 4 b bufname RET- 在另一窗口中选中指定缓冲区 (
switch-to-buffer-other-window) ,详见《创建与选择缓冲区》章节。 C-x 4 C-o bufname RET- 在某一窗口中显示指定缓冲区, 不尝试选中 该窗口 (
display-buffer) 。窗口的选择规则细节,详见《在窗口中显示缓冲区》章节。 C-x 4 f finename RET- 访问指定文件,并在另一窗口中选中其对应的缓冲区 (
find-file-other-window) ,详见《访问文件》章节。 C-x 4 d directory RET- 在另一窗口中为指定目录选中 Dired 缓冲区 (
dired-other-window) ,详见《目录编辑器 Dired》章节。 C-x 4 m- 开始撰写邮件,功能与
C-x m一致(详见《发送邮件》章节),区别是在另一窗口中执行 (compose-mail-other-window) 。 C-x 4 .- 查找标识符的定义,功能与
M-.一致(详见《查找标识符引用》章节),区别是在另一窗口中执行 (xref-find-definitions-other-window) 。 C-x 4 r filename RET- 以只读方式访问指定文件,并在另一窗口中选中其对应的缓冲区 (
find-file-read-only-other-window) ,详见《访问文件》章节。 C-x 4 4- 一个更通用的前缀命令,会影响紧随其后执行的命令所显示的缓冲区 (
other-window-prefix) ,该前缀会要求后续命令将其要显示的缓冲区展示在另一窗口中。 C-x 4 1- 该通用前缀命令则要求后续执行的命令,将其对应的缓冲区 显示在当前同一窗口中 。
22.5. 删除与调整窗口大小
C-x 0- 删除选中的窗口 (
delete-window) 。 C-x 1- 删除选中框架中除选中窗口外的所有窗口 (
delete-other-windows) 。 C-x 4 0- 删除选中的窗口并
kill关闭其在缓冲区显示 (kill-buffer-and-window,该快捷键最后一个字符为数字 0) 。 C-x w 0 RET buffer RET- 删除所有显示指定缓冲区的窗口。
C-x ^- 增大选中窗口的高度 (
enlarge-window) 。 C-x }- 增大选中窗口的宽度 (
enlarge-window-horizontally) 。 C-x {- 缩小选中窗口的宽度 (
shrink-window-horizontally) 。 C-x -- 若缓冲区无需当前行数,缩小该窗口尺寸 (
shrink-window-if-larger-than-buffer) 。 C-x +- 平衡选中框架中所有窗口的尺寸 (
balance-windows) 。
删除选中窗口可按下 C-x 0 (注意是数字 0)。窗口被删除后,其占用的空间会分配给相邻的窗口(迷你缓冲区窗口除外,即便其处于激活状态也不会分配)。删除窗口不会对其原本显示的缓冲区产生任何影响,该缓冲区会继续存在,你仍可通过 C-x b 切换至该缓冲区。配置项 delete-window-choose-selected 用于控制选择哪个窗口作为新的选中窗口(详见《Emacs Lisp 参考手册》的 “删除窗口” 章节)。
C-x 4 0 是比 C-x 0 功能更强的命令,它会先 kill关闭 当前缓冲区,再删除选中的窗口。
C-x 1 会删除选中框架中除选中窗口外的所有窗口,选中窗口会自动扩展至占据整个框架的空间(该命令无法在迷你缓冲区窗口激活时使用,强行使用会触发错误)。
执行 M-x delete-windows-on 可删除所有显示指定缓冲区的窗口,该命令会提示输入目标缓冲区,默认值为当前缓冲区。若带上数字 0 前缀参数( C-u 0 ),该命令仅会删除当前显示器所属框架中显示该缓冲区的窗口。
C-x ^ 命令会将选中窗口的高度增加一行,空间从垂直方向的相邻窗口中获取,且不会改变框架的整体高度。带上正数字参数时,窗口高度会按该数值增加;带上负数字参数时,窗口高度会按该数值减少。若当前窗口无垂直方向的相邻窗口(即窗口已占满框架全部高度),执行该命令会触发错误;若尝试将任意窗口的高度缩小至低于配置项 window-min-height 指定的最小行数(默认值为 4 行),同样会触发错误。
同理, C-x } 会增大选中窗口的宽度, C-x { 会缩小选中窗口的宽度。若尝试将任意窗口的宽度缩小至低于配置项 window-min-width 指定的最小列数(默认值为 10 列),执行这两个命令会触发错误。
在模式行(参见《模式行的鼠标命令》)或窗口分隔线(参见《窗口分隔线》)上点击鼠标,也可实现窗口高度调整、窗口拆分或删除操作。
C-x - 命令会检测选中窗口的高度,若其超出显示对应缓冲区全部文本所需的行数,会自动缩小窗口高度,并将多余的行空间分配给框架中的其他窗口。
你也可使用 C-x + 平衡选中框架中所有窗口的尺寸(迷你缓冲区窗口除外,参见《迷你缓冲区》章节)。该命令会让所有水平相邻的窗口高度一致,所有垂直相邻的窗口宽度一致。
22.6. 在窗口中显示缓冲区
响应用户命令来显示或调出某个缓冲区,是 Emacs 的常规操作。命令实现该功能的方式有多种。
许多命令(如 C-x C-f (find-file) )默认会 占用当前选中的窗口 来显示缓冲区,这是因为这类命令预期用户的注意力会转移至该缓冲区。
部分命令会采用更智能的显示方式,尽量不占用选中的窗口 —— 例如,拆分出一个新窗口并在其中显示目标缓冲区。这类命令包括各类帮助命令(参见帮助相关章节),其内部均通过调用 display-buffer 函数实现该功能,具体细节参见《display-buffer 的工作机制》小节。
另有一些命令的行为与 display-buffer 一致,且会额外选中用于显示的窗口,方便用户直接开始编辑该缓冲区。命令 M-g M-n (next-error) 就是典型示例(参见编译模式章节),这类命令内部通过调用 pop-to-buffer 函数实现功能,具体可参见《Emacs Lisp 参考手册》中的《在窗口中切换至缓冲区》章节。
名称以 -other-window 结尾的命令,行为与 display-buffer 类似, 唯一区别 是绝不会在选中的窗口中显示缓冲区。这类命令中有多个被绑定在 C-x 4 前缀键下(参见《在另一窗口中显示内容》章节)。
名称以 -other-frame 结尾的命令,同样以 display-buffer 的行为为基础,同时满足两个规则:① 绝不会在选中的窗口中显示缓冲区;② 优先创建新框架,或使用其他框架中的窗口来显示目标缓冲区。这类命令中有多个被绑定在 C-x 5 前缀键下。
有时,某个窗口会被 dedicated专用于 其当前显示的缓冲区(详见《Emacs Lisp 参考手册》中的《专用窗口》章节)。 display-buffer 函数在绝大多数情况下,都会避免复用专用窗口。窗口的专用属性会在模式行中以字符 'd' 标识(参见模式行相关章节);此外,窗口还可设置为 强专用模式 ,该模式下窗口显示的缓冲区无法被任何方式替换,其模式行中会以字符 'D' 标识。
专用窗口通常用于显示特定用途的缓冲区,不过该属性在交互式操作中也能发挥作用。例如,使用 M-g M-n (next-error) 查看错误信息时,新显示的源代码缓冲区可能会覆盖你需要参考的某个缓冲区。若将该窗口设置为对应缓冲区的专用窗口,上述命令(通过 display-buffer 函数)会自动选择其他窗口来显示新内容。
你可使用命令 C-x w d (toggle-window-dedicated) ,来切换选中窗口是否专用于当前缓冲区。若带上前缀参数执行该命令,会将窗口设置为强专用模式。
22.6.1. display-buffer 函数的工作原理
display-buffer 命令(以及所有内部调用该函数的命令)会按照下述步骤选择用于显示缓冲区的窗口。若需修改该步骤执行顺序,详见《Emacs Lisp 参考手册》中的《为显示缓冲区选择窗口》章节。
若无论其他条件如何,该缓冲区都需在选中窗口中显示,则复用当前选中的窗口。此步骤默认会被跳过,若要取消跳过,需将 匹配该缓冲区名称的正则表达式 ,与
display-buffer-same-window动作函数的引用一起,添加至配置项display-buffer-alist中(动作函数相关说明详见《Emacs Lisp 参考手册》中的《缓冲区显示的动作函数》章节,配置项相关说明详见《Emacs Lisp 参考手册》中的《为显示缓冲区选择窗口》章节)。例如,要让*scratch*缓冲区优先在选中窗口中显示,可写入以下配置:(setopt display-buffer-alist '(("\\*scratch\\*" (display-buffer-same-window))))
display-buffer-alist的默认值为nil。- 若该缓冲区已在某个现有窗口中显示,则复用该窗口。默认情况下,仅会检索当前选中框架中的窗口;若在动作关联列表中配置了对应的
reusable-frames项(详见《Emacs Lisp 参考手册》中的《缓冲区显示的动作关联列表》章节),其他框架中的窗口也可被复用。具体配置方式可参考下一步的示例。 可选创建一个新框架,并在其中显示该缓冲区。此步骤默认被跳过。若要启用该功能,需按如下方式修改配置项
display-buffer-base-action的值(详见《Emacs Lisp 参考手册》中的《为显示缓冲区选择窗口》章节):(setopt display-buffer-base-action '((display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . 0)))该自定义配置同时会让上一步的检索范围,扩展至所有可见或最小化的框架中的可复用窗口。
尝试在当前选中的框架中拆分某个窗口,创建新窗口并在其中显示该缓冲区。
拆分方式可为垂直或水平,具体由变量
split-height-threshold和split-width-threshold控制,这两个变量均需设置为整数值。若split-height-threshold小于目标窗口的高度,新窗口会被拆分为下方窗口;若该条件不满足,但split-width-threshold小于目标窗口的宽度,新窗口会被拆分为右侧窗口;若两个条件均不满足,Emacs 会尝试将新窗口拆分为下方窗口 —— 但该行为仅在目标窗口未被拆分过的情况下生效(避免过度拆分)。- 在之前显示过该缓冲区的窗口中重新显示。默认情况下,仅会检索当前选中框架中的窗口;若配置了合适的
reusable-frames动作关联列表项(见上文),也可使用其他框架中的对应窗口。 - 在当前选中框架的某个现有窗口中显示该缓冲区。
- 若因任何原因,上述所有方式均失败,则创建一个新框架,并在其中显示该缓冲区。
22.6.2. 显示不可编辑缓冲区
部分缓冲区在窗口中展示仅作查阅之用,而非用于编辑。帮助类命令(参见帮助章节)通常会借助名为 *Help* 的缓冲区实现此功能,迷你缓冲区补全(参见补全章节)会用到名为 *Completions* 的缓冲区,诸如此类的缓冲区通常仅临时显示一小段时间。
默认情况下,Emacs 会通过 display-buffer 函数为这类临时展示的缓冲区选择显示窗口,具体规则见上一小节。但 *Completions* 缓冲区是例外,它通常会固定显示在 选中框架底部 的窗口中,不受该框架当前已打开的窗口数量影响。
若你希望 Emacs 以其他方式显示临时缓冲区,可对配置项 display-buffer-alist 进行相应的自定义配置(详见《Emacs Lisp 参考手册》中的《为显示缓冲区选择窗口》章节)。例如,要让 *Completions* 缓冲区始终显示在选中窗口的下方,可在初始化文件中添加以下配置(参见《Emacs 初始化文件》章节):
(setopt display-buffer-alist '(("\\*Completions\\*" display-buffer-below-selected)))
*Completions* 缓冲区还有一个特殊之处:Emacs 通常会自动调整其窗口大小,使其 恰好能完整显示所有内容 。若要让其他临时展示的缓冲区(如 *Help* 缓冲区)的窗口也实现自动调整大小,可启用次要模式 temp-buffer-resize-mode (参见次要模式章节,该模式详情见《Emacs Lisp 参考手册》中的《临时展示》章节)。
由 temp-buffer-resize-mode 模式调整大小的窗口,其最大尺寸可通过配置项 temp-buffer-max-height 和 temp-buffer-max-width 自定义控制(详见《Emacs Lisp 参考手册》中的《临时展示》章节),且窗口最大尺寸不会超过所属框架的大小。
用于展示警告信息的缓冲区(如字节编译警告,详见《Emacs Lisp 参考手册》中的《字节编译函数》章节),默认也会显示在选中框架底部的窗口中。你可通过变量 warning-display-at-bottom 控制该行为:若将其设为 nil ,Emacs 会改用 display-buffer 函数的默认逻辑为其选择窗口(参见 display-buffer 函数的工作机制),你也可通过 display-buffer-alist 对该逻辑进行自定义。
22.7. 窗口操作的便捷功能
窗口配置恢复模式(Winner mode)是一款全局次要模式,它会记录 窗口配置的变更记录 (即框架拆分为多个窗口的布局方式),让你可以撤销这些变更。可通过 M-x winner-mode 切换该模式的开启与关闭,也可通过自定义变量 winner-mode 完成设置。启用该模式后,按下 C-c LEFT (winner-undo) 可撤销上一次的窗口配置变更;若在撤销操作后改变想法,可使用 C-c right (M-x winner-redo) 重做已撤销的配置变更。若不想让窗口配置恢复模式绑定 C-c left 和 C-c right ,可将变量 winner-dont-bind-my-keys 设为非nil值。默认情况下,该模式为每个框架最多存储 200 条窗口配置记录,你可通过修改变量 winner-ring-size 调整这一上限。若存在部分缓冲区,你不希望该模式恢复其对应的窗口布局,可将这些缓冲区的名称添加至列表变量 winner-boring-buffers ,或匹配至正则表达式变量 winner-boring-buffers-regexp 中。
跟随模式( M-x follow-mode )可让显示同一缓冲区的多个窗口实现同步,使它们始终展示该缓冲区中 相邻的内容区域 。详见「跟随模式」章节。
Windmove 包定义了在一个框架中 按方向切换相邻窗口 的命令。 M-x windmove-right 会选中当前选中窗口右侧紧邻的窗口, windmove-left 、 windmove-up 、 windmove-down 命令则分别对应左、上、下方向的窗口切换。执行 windmove-default-keybindings 可将这些命令绑定至 S-right Shift+右方向键等组合键;该绑定操作会禁用这些按键原本的移位选择功能(详见「移位选择」章节)。与为按方向选窗的命令绑定快捷键的方式相同,你可使用 windmove-display-default-keybindings ,为「指定下一条命令的缓冲区在哪个方向的窗口中显示」的相关命令绑定快捷键。此外, windmove-delete-default-keybindings 可用于为按方向删除窗口的命令绑定快捷键, windmove-swap-states-default-keybindings 则能为「将选中窗口与指定方向窗口的内容互换」的命令绑定快捷键。
执行 M-x compare-windows 命令,可对比不同窗口中显示的文本内容。详见「文件对比」章节。
全部滚动模式( M-x scroll-all-mode )是一款全局次要模式,启用后,滚动类命令和光标移动类命令会作用于所有窗口。
22.8. 窗口标签栏
global-tab-line-mode 命令用于切换是否在每个窗口的顶部显示 tab line标签行 。标签行会为该窗口中曾显示过的每个缓冲区显示专属按钮("tabs"),点击对应按钮即可切换至相应缓冲区。点击 + 图标可在该窗口的本地缓冲区标签行中新增一个缓冲区,点击某一标签的 x 图标则可将该标签移除。在标签行上滚动鼠标滚轮,可实现标签的水平滚动。
触摸屏输入(参见触摸屏输入与虚拟键盘)也可用于与 "tab line" 交互。长按(参见在触摸屏上使用 Emacs)某一标签,会弹出一个上下文菜单,其中包含对该被按标签的操作选项;轻点标签本身,即可切换至该标签对应的缓冲区;轻点标签行上的按钮,效果等同于使用 mouse-1 鼠标左键点击该按钮。
选中窗口本地的上一个标签,等同于按下 C-x LEFT (previous-buffer) ;选中下一个标签,等同于按下 C-x RIGHT (next-buffer) 。这两个命令均支持将数字前缀参数作为重复执行的次数。
你可自定义变量 tab-line-tabs-function ,来定义标签行的首选显示内容。默认情况下,该标签行会显示前文所述的、该窗口中曾访问过的所有缓冲区。但你也可将其设置为显示与当前缓冲区主模式相同的所有缓冲区列表,或按主模式对缓冲区进行分组显示 —— 此时点击首个标签中的模式名称,会弹出所有主模式的列表,你可从中选择另一组缓冲区进行查看。
请注意, Tab Line标签行与 Tab Bar标签栏并非同一功能 (参见标签栏)。标签栏位于每个框架的顶部,其标签用于在包含多个缓冲区窗口的窗口配置之间进行切换;而标签行位于每个窗口的顶部,其标签仅用于在当前窗口内的不同缓冲区之间切换。
另请注意,标签行与窗口工具栏会占用 同一显示区域 ,因此任一时刻只能显示二者中的一个;除非你在 Lisp 代码中自定义 tab-line-format 的值,向其中添加 (:eval (tab-line-format)) 来调整布局(详见《Emacs Lisp 参考手册》中的模式行格式章节)。
22.9. 窗口工具栏
global-window-tool-bar-mode 命令用于切换是否在每个窗口的顶部显示工具栏。启用该功能后,多个窗口可同时显示各自的专属工具栏。为节省显示空间,若某一窗口的工具栏无任何按钮可展示(即 tool-bar-map 变量值为 nil ),该窗口的工具栏会自动隐藏。
若你希望仅为部分缓冲区切换窗口工具栏的显示状态,可在这些缓冲区中执行 window-tool-bar-mode 命令。该用法在模式钩子中尤为实用。例如,若你希望仅为 非文件类缓冲区 且配有自定义工具栏的缓冲区显示窗口工具栏,可在初始化文件中添加以下代码(参见《Emacs 初始化文件》章节):
(add-hook 'special-mode-hook 'window-tool-bar-mode)
Emacs 也支持在框架顶部显示一个 全局统一的工具栏 (参见《工具栏》章节)。
请注意,窗口工具栏与标签行会占用 同一显示区域 ,因此任一时刻只能显示二者中的一个;除非你自定义 tab-line-format 变量的值,向其中添加 (:eval (window-tool-bar-string)) 来调整布局(详见《Emacs Lisp 参考手册》中的《模式行格式》章节)。
23. 框架与图形界面
当 Emacs 在图形化显示环境中启动时(如 X 窗口系统),它会占用一块系统级的图形化显示区域。在本手册中,该区域被称为 frame框架 ,而 "window窗口" 一词专指框架中用于显示缓冲区的区域。一个框架初始时仅包含一个窗口,也可将其拆分为多个窗口(参见多窗口章节)。框架通常还包含菜单栏、工具栏和回显区。
你也可以创建额外的框架(参见创建框架章节)。在同一个 Emacs 会话中创建的所有框架,均可访问相同的底层缓冲区及其他数据。例如,若某个缓冲区同时在多个框架中显示,在其中一个框架中对该缓冲区做出的任何修改,都会立即同步显示在其他所有框架中。
按下 C-x C-c 会关闭当前显示器上的所有框架;若 Emacs 在其他所有显示器上均无打开的框架,该操作会直接结束 Emacs 会话(参见退出 Emacs章节)。若仅需关闭当前选中的框架,按下 C-x 5 0 即可(此处为数字 0,非字母 o)。
本章介绍 Emacs 专用于图形化显示的功能(尤其是鼠标命令),以及管理多框架的相关功能。在文本终端中,这些功能有许多无法使用。不过,仍可在文本终端中创建多个框架,这类框架会逐个显示,并占满整个终端屏幕(参见文本终端章节)。部分文本终端也支持鼠标操作(在 GNU 和 Unix 系统上的使用方法参见文本终端中的鼠标操作章节;在 MS-DOS 系统上的使用方法参见 MS-DOS 中的鼠标使用章节)。所有文本终端均支持菜单功能。
23.1. 编辑相关的鼠标命令
mouse-1- 将光标移动至点击位置 (
mouse-set-point) 。 Drag-mouse-1- 拖动鼠标左键。拖动选中的文本激活选区,并将该文本放入主选择区 (
mouse-set-region) 。 mouse-2- 鼠标中键。将光标移动至点击位置,并在该位置插入主选择区的内容 (
mouse-yank-primary) 。 mouse-3- 鼠标右键。若选区已激活,将选区较近的一端移动至点击位置;若选区未激活,将标记位设为当前光标位置,再将光标移至点击位置。将最终的选区内容存入删除环;再次点击则删除该选区内容 (
mouse-save-then-kill) 。 C-M-mouse-1- 为拖动选中的文本激活矩形选区,详见「矩形操作」章节。
最基础的鼠标命令是 mouse-set-point ,在窗口的文本区域点击鼠标左键,即可调用该命令,它会将光标移动到点击的位置。若点击的窗口并非选中窗口,该窗口会成为新的选中窗口。你也可通过双击 mouse-1 鼠标左键激活选区,详见「单词与行的鼠标命令」章节。
默认情况下,若点击的框架并非选中框架,除了选中对应窗口并设置光标位置外,该框架会被设为选中框架。在 X 窗口系统中,可将变量 x-mouse-click-focus-ignore-position 设为 t 来更改此行为,此时点击未选中的框架,首次点击仅会选中该框架,不执行其他操作;再次点击才会选中窗口并设置光标位置。
按住 mouse-1 鼠标左键并在一段文本上拖动,会为该文本激活选区 (mouse-set-region) ,标记位会落在按住鼠标键的起始位置,光标则在松开鼠标键的结束位置,详见「标记与选区」章节。同时,选区内的文本会成为 主选择区 的内容,详见「与其他窗口程序的剪切粘贴」章节。
若将变量 mouse-drag-copy-region 设为非nil值,拖动鼠标选中文本时,该文本也会被添加至 删除环 ,该变量默认值为 nil 。
若该变量设为 non-empty ,则仅当选区非空时,才会将内容复制到删除环。例如,若鼠标拖动的区域不足半个字符,原本会向删除环中存入空字符串,而设为该值后,这种短距离拖动不会对删除环产生任何影响。
拖动鼠标时,若将鼠标移出窗口的顶部或底部,窗口会以稳定的速率自动滚动,直至将鼠标移回窗口内。通过这种方式,你可以选中无法完整显示在屏幕上的文本区域。每一步的滚动行数,取决于鼠标离窗口边缘的距离;变量 mouse-scroll-min-lines 规定了滚动的最小步长。
若启用选项 mouse-drag-mode-line-buffer ,且窗口系统支持文件拖动,那么在模式行的缓冲区名称区域拖动鼠标,可将该缓冲区对应的文件拖至其他程序或 Emacs 框架中。
点击 mouse-2 鼠标中键,会将光标移至点击位置,并在该位置插入主选择区的内容 (mouse-yank-primary) ,详见「与其他窗口程序的剪切粘贴」章节,该行为与其他 X 应用程序保持一致。你也可将 mouse-2 鼠标中键重新绑定至 mouse-yank-at-click 命令,该命令会在点击位置直接粘贴内容。
若将变量 mouse-yank-at-point 设为非nil值,点击 mouse-2 鼠标中键时不会移动光标,无论点击框架中的哪个位置、哪个窗口,都会在 当前光标位置 插入内容。该变量会同时作用于 mouse-yank-primary 和 mouse-yank-at-click 两个命令。
点击 mouse-3 鼠标右键会执行 mouse-save-then-kill 命令,该命令的行为会根据点击位置和选区的状态发生变化,具体规则如下:
- 若选区未激活,点击鼠标右键会激活选区,标记位为原光标位置,光标移至点击位置;
- 若选区已激活,点击鼠标右键会调整选区较近的一端,将其移至点击位置,调整后的选区内容会被复制到删除环;若原选区的内容已在删除环中,则会替换原有内容;
- 若最初通过双击或三击鼠标左键选中选区(即选区为整词或整行,详见「单词与行的鼠标命令」章节),那么通过鼠标右键调整选区时,也会按整词或整行的规则进行;
- 在同一位置连续第二次点击鼠标右键,会删除已选中的选区内容。
因此,使用鼠标删除文本的最简方式为:在文本一端点击鼠标左键,在另一端连续双击鼠标右键。若只想将文本复制到删除环、而不从缓冲区中删除,只需单击一次鼠标右键—— 或直接用鼠标左键拖动选中文本即可,后续可通过粘贴操作将其复制到其他位置。
mouse-save-then-kill 命令同样遵循变量 mouse-drag-copy-region 的设置(前文已述)。若该变量值为非nil,则每当该命令创建或调整激活的选区时,选区内的文本都会被添加至删除环;若删除环的最新条目是通过相同方式添加的,则会替换该条目,而非新建条目。
无论通过上述哪种鼠标命令设置选区,除了常规的选区取消方式外,后续执行 无移位修饰的光标移动命令 ,都会自动取消标记的激活状态,详见「移位选择」章节。
部分鼠标配有滚轮,可用于滚动页面。Emacs 在大多数图形化显示环境中,默认支持通过鼠标滚轮滚动窗口,可使用 M-x mouse-wheel-mode 切换该功能的开启与关闭。变量 mouse-wheel-follow-mouse 和 mouse-wheel-scroll-amount 决定了滚动的目标窗口和滚动步长;变量 mouse-wheel-progressive-speed 决定了滚动速度是否与滚轮的转动速度相关。
该模式还支持调整字体大小,默认将 Ctrl 键配合滚轮绑定为字体缩放的快捷键。启用该模式后,鼠标滚轮会触发 wheel-up (滚轮上滚)和 wheel-down (滚轮下滚)等特殊事件(部分旧系统会将其识别为 mouse-4 和 mouse-5 )。若鼠标配有水平滚轮,还会触发 wheel-left (滚轮左滚)和 wheel-right (滚轮右滚)事件。
Emacs 还支持 Shift 键配合滚轮实现水平滚动。在开始水平滚动前输入数字前缀参数(如 M-5 ),可修改由用户选项 mouse-wheel-scroll-amount-horizontal 定义的水平滚动步长。
若你的鼠标滚轮支持侧倾,或触控板支持该操作,可将变量 mouse-wheel-tilt-scrolxl 设为非nil值,启用滚轮侧倾的水平滚动功能。默认情况下,侧倾鼠标滚轮会让窗口视图向侧倾方向水平滚动:例如,向右倾滚轮会让窗口向右滚动,窗口中显示的文本则会向左水平移动。若想反转水平滚动的方向,可将变量 mouse-wheel-flip-direction 设为非nil值。
在图像模式下,当鼠标指针置于图片上方时(详见「查看图像文件」章节),Ctrl 键配合滚轮会缩放鼠标指针下方的图片,Shift 键配合滚轮则会让图片水平滚动。
23.2. 针对单词与行的鼠标命令
mouse-1 鼠标左键的这些操作变体可一次选中整词或整行文本。Emacs 会为选中的文本激活选区,同时将文本复制至删除环。
Double-mouse-1双击鼠标左键。选中点击位置所在的整词或字符周边的文本。
若在符号语法的字符(如 C 模式中的下划线)上双击,会选中该字符所在的整个符号;若在左 / 右括号语法的字符上双击,会选中该字符所起始或终止的括号匹配内容;若在字符串分隔符语法的字符(如 C 模式中的单引号、双引号)上双击,会选中整个字符串常量(Emacs 会通过启发式规则判断该字符为字符串的起始还是终止符)。
若在括号匹配内容的起始处或字符串分隔符的起始符上双击,光标会移至选区末尾,必要时会向前滚动缓冲区内容以显示光标的新位置;若在括号匹配内容的终止处或字符串分隔符的终止符上双击,默认光标会停留在选区末尾,若选区起始位置超出窗口上边界则会无法显示;将用户选项
mouse-select-region-move-to-beginning设为非nil值,可改为将光标移至选区起始位置,必要时向后滚动显示内容。Double-Drag-mouse-1- 双击并拖动鼠标左键。以整词为单位,选中拖动范围内的所有文本。
Triple-mouse-1- 三击鼠标左键。选中点击位置所在的整行文本。
Triple-Drag-mouse-1- 三击并拖动鼠标左键。以整行为单位,选中拖动范围内的所有文本。
23.3. 用鼠标跟随引用链接
部分 Emacs 缓冲区中会包含 buttons按钮 或 hyperlins超链接 :这类文本片段在被激活(如点击)时会执行特定操作(例如跳转到对应引用位置)。通常,按钮文本会有视觉高亮效果:或以下划线标注,或在文本外围绘制边框。将鼠标移至按钮上方时,鼠标光标的形状会发生变化,且按钮会亮起。若将变量 mouse-highlight 设为 nil ,Emacs 会关闭该高亮功能。
激活按钮的方式有两种:将光标移至按钮处并按下回车键( RET ),或在按钮上点击鼠标左键( mouse-1 )/ 鼠标中键( mouse-2 )。例如,在 Dired 缓冲区中,每个文件名都是一个按钮,激活该按钮会让 Emacs 打开对应文件(参见《Dired:目录编辑器》章节);在 *Compilation* 编译缓冲区中,每条错误提示信息都是一个按钮,激活后会跳转到该错误对应的源代码位置(参见《在 Emacs 中运行编译操作》章节)。
尽管在按钮上单击鼠标左键通常会激活按钮,但如果按住鼠标左键一段时间后再松开(具体为超过 450 毫秒),Emacs 只会将光标移至点击位置,而不会激活按钮。通过这种方式,可在不激活按钮的前提下,用鼠标将光标移至按钮上方。在按钮上或向按钮区域拖动鼠标时,会执行常规的选区设置操作,不会激活按钮。
可通过自定义变量 mouse-1-click-follows-link ,修改鼠标左键对按钮的作用方式:
- 若该值为正整数,该数值即为取消按钮激活所需按住鼠标左键的时长(单位:毫秒),默认值为前文所述的 450;
- 若该值设为
nil,鼠标左键仅会将光标移至点击位置,不会激活按钮; - 若该值设为
double,双击鼠标左键会激活按钮,单击仅会移动光标。
默认情况下,即便按钮处于未选中的窗口中,在其上点击 mouse-1 鼠标左键仍会激活该按钮。若将变量 mouse-1-click-in-non-selected-windows 设为 nil ,在未选中窗口的按钮上点击 mouse-1 鼠标左键,只会将光标移至点击位置并选中该窗口,而不会激活按钮
23.4. 菜单相关的鼠标点击操作
结合 Ctrl 和 Shift 修饰键的多款鼠标点击操作可调出对应菜单。
C-mouse-1该菜单用于选择缓冲区。
MSB(即 “mouse select buffer鼠标选择缓冲区”)全局次要模式可让此菜单的功能更智能、且支持更多自定义设置,详见《自定义缓冲区菜单》章节。
C-mouse-2- 该菜单包含用于查看和设置外观属性及其他文本属性的菜单项,其中文本属性设置功能主要在编辑富文本时使用(详见《富文本》章节)。
C-mouse-3- 该菜单为模式专属菜单:
- 若开启菜单栏模式,对于大多数主模式,此菜单会整合该模式下菜单栏中的所有专属菜单项;部分主模式可为该操作自定义不同的菜单内容。
- 若关闭菜单栏模式,此菜单会包含菜单栏中的 所有菜单项 (并非仅模式专属项),无需显示菜单栏即可调用全部菜单功能。
S-mouse-1- 该菜单用于修改当前窗口缓冲区的默认面属性,详见《文本缩放》章节。
多数图形界面应用会将鼠标右键( mouse-3 )设为调出上下文菜单的快捷键,此类菜单会根据鼠标点击的位置和上下文,提供相关的设置项与操作选项。Emacs 中鼠标右键的默认功能为绑定 mouse-save-then-kill 命令(详见《编辑相关的鼠标命令》章节),若你更习惯将其用作上下文菜单,可启用 context-menu-mode (上下文菜单模式):启用后,点击 mouse-3 鼠标右键即可调出上下文菜单,菜单的具体内容会根据当前主模式、以及鼠标点击位置附近的缓冲区内容动态变化。
你可通过变量 context-menu-functions 自定义上下文菜单的内容(详见《Emacs Lisp 参考手册》中的《主模式约定》章节),也可通过按下 S-F10 快捷键调出上下文菜单。
23.5. 模式行鼠标命令
可通过点击窗口的模式行,实现窗口的选择与各类操作。
模式行的部分区域(如缓冲区名称、主模式与次要模式名称处)配有专属的鼠标绑定命令。将鼠标悬停在这些区域时,区域会高亮显示,同时相关绑定命令的说明信息也会弹出(参见工具提示相关内容)。本节介绍的命令不适用于这些特殊区域。
mouse-1- 在模式行上点击
mouse-1鼠标左键,会选中该模式行所属的窗口。在模式行上按住mouse-1鼠标左键并拖动,可移动模式行的位置,进而调整其上下方窗口的高度。通过这种方式用鼠标调整窗口高度时,绝不会删除任何窗口,仅会限制窗口高度,使其不小于最小高度值。 mouse-2- 在模式行上点击
mouse-2鼠标中键,会将该模式行所属的窗口最大化,占满其所在的整个框架。 mouse-3- 在模式行上点击
mouse-3鼠标右键,会关闭该模式行所属的窗口。若该框架中仅有一个窗口,此操作将无任何效果。 C-mouse-2- 在模式行上按住 Ctrl 并点击鼠标中键,会拆分该模式行所属的窗口,生成两个左右并排的窗口,窗口的分隔线会落在鼠标点击的位置(参见窗口拆分相关内容)。
此外,在两个左右并排窗口的模式行分隔处,按住 mouse-1 鼠标左键并拖动,可左右移动窗口的垂直分隔线,调整两侧窗口的宽度。
请注意,窗口的调整操作会受 window-resize-pixelwise 变量的取值影响,相关说明参见窗口拆分章节。
23.6. 创建框架
前缀键 C-x 5 与 C-x 4 的功能逻辑相似: C-x 4 系列命令会在选中框架的新窗口中弹出指定缓冲区(参见《在另一窗口中显示内容》章节),而 C-x 5 系列命令则会在新的框架中完成该操作。若目标缓冲区已显示在某个可见或最小化的框架中(“最小化” 亦作图标化,参见《Emacs Lisp 参考手册》中《框架的可见性》章节),该框架会被前置并还原为正常显示状态(取消最小化);若未找到对应框架,则会在当前显示终端中新建一个框架。
C-x 5 下的各类命令,核心区别在于 查找或创建待选中缓冲区的方式 ,具体命令如下:
C-x 5 2- 使用默认框架参数创建一个新框架 (
make-frame-command) 。 C-x 5 c- 沿用当前框架的窗口配置与框架参数,克隆一个新框架 (
clone-frame) 。 C-x 5 b bufname RET- 在另一个框架中选中指定名称的缓冲区,对应命令
switch-to-buffer-other-frame。 C-x 5 f filename RET- 打开指定文件,并在另一个框架中选中该文件对应的缓冲区,对应命令
find-file-other-frame(参见《打开文件》章节)。 C-x 5 d directory RET- 在另一个框架中为指定目录打开 Dired 缓冲区,对应命令
dired-other-frame(参见《Dired:目录编辑器》章节)。 C-x 5 m- 在另一个框架中开始撰写邮件,对应命令
compose-mail-other-frame,是C-x m命令的跨框架版本(参见《发送邮件》章节)。 C-x 5 .- 在另一个框架中查找标识符的定义,对应命令
xref-find-definitions-other-frame,是M-.命令的多框架版本(参见《查找标识符引用》章节)。 C-x 5 r filename RET- 以只读方式打开指定文件,并在另一个框架中选中该缓冲区,对应命令find-file-read-only-other-frame(参见《打开文件》章节)。
C-x 5 5- 一个更通用的前缀命令 (
other-frame-prefix) ,作用于紧随其后执行的命令:该前缀会让后续命令所显示的缓冲区,在另一个框架中展示。
你可以通过 指定框架参数 ,控制新建框架的外观与行为,相关说明参见《框架参数》章节。
23.7. 框架命令
下述命令用于框架的删除与各类操作:
C-x 5 0- 删除当前选中的框架 (
delete-frame) 。若当前仅存在一个框架,执行此命令会触发错误提示。 C-x 5 u- 当启用
undelete-frame-mode(框架恢复模式)时,可恢复最近删除的 16 个框架中的一个。无前缀参数时,恢复 最近刚删除 的框架;若传入 1 到 16 之间的数字前缀参数(数字 1 对应最近删除的框架),则恢复对应序号的已删除框架。 C-z- 将当前选中的 Emacs 框架最小化(图标化) (
suspend-frame) ,详见《退出 Emacs》章节。 C-x 5 o- 选中并前置另一个框架。重复执行此命令,会在当前终端的所有框架间循环切换。
C-x 5 1- 删除当前终端上除选中框架外的所有其他框架。
M-F10- 切换当前框架的最大化状态,框架最大化时会占满整个屏幕。
F11- 切换当前框架的全屏模式。(全屏与最大化的区别通常在于:全屏模式会隐藏窗口管理器的装饰栏,为 Emacs 本身让出更多的屏幕空间。)
请注意,在部分窗口管理器环境下,若要让框架实现真正的最大化或全屏,需将变量 frame-resize-pixelwise 自定义设为非nil值。当该变量为非nil时,框架整体支持 像素级精度 调整大小,而非仅以行和列为单位的整数倍调整。
C-x 5 0 (delete-frame) 命令用于删除选中的框架,但为防止用户失去与 Emacs 会话的交互能力,该命令会拒绝删除 Emacs 会话中的最后一个框架。需注意,当 Emacs 以守护进程模式运行时(详见《将 Emacs 用作服务器》章节),即便所有常规的交互式框架都被删除,仍会保留一个虚拟框架;此种情况下, C-x 5 0 可删除最后一个交互式框架,用户可通过 emacsclient 重新连接至该 Emacs 会话。
C-x 5 1 (delete-other-frames) 命令仅删除 当前终端 上的其他所有框架(此处的终端指图形化显示器或文本终端,详见《文本终端》章节);若 Emacs 会话在其他图形化显示器或文本终端上还打开了框架,这些框架不会被删除。
C-x 5 o (other-frame) 命令用于选中当前终端的下一个框架。若在 X 窗口系统中使用 Emacs,且所用的窗口管理器会自动选中(或赋予焦点)鼠标光标悬停的任意框架,需将变量 focus-follows-mouse 设为 t ,此命令才能正常工作。设置后,执行 C-x 5 o 还会将鼠标光标 移动至 选中的框架处。
23.8. 字体设置
默认情况下,Emacs 在图形化显示界面中使用 10 号等宽字体 显示文本,且可通过交互方式调整字体大小(参见《文本缩放》章节)。
指定自定义字体的方式有以下几种:
- 在 'Options选项' 菜单中点击 'Set Default Font设置默认字体' ,所选字体会成为所有现有图形化框架的默认字体;若要将该设置保存至后续会话,可在 'Options选项' 菜单中点击 'Save Options保存选项' 。
在初始化文件中添加一行代码,修改
default-frame-alist变量以指定字体参数(参见《框架参数》章节),示例如下:(add-to-list 'default-frame-alist '(font . "DejaVu Sans Mono-10"))重启 Emacs 后,所有新建的图形化框架都会使用该字体作为默认字体。
在 X 资源文件中添加 'emacs.font' 的 X 资源配置,示例如下:
emacs.font: DejaVu Sans Mono-12
需重启 X 窗口系统或执行
xrdb命令,才能让 X 资源文件的配置生效(参见《X 资源》章节)。注意:在 X 资源文件中指定字体名时无需加引号。- 若在 GNOME 桌面或 Haiku 系统中运行 Emacs,可将变量
font-use-system-font设为t(默认值为nil),让 Emacs 跟随系统默认字体的变更,自动调整框架的默认字体。该功能生效的前提是,Emacs 编译时启用了 Gsettings(或旧版 Gconf)支持。(具体使用的 Gsettings 配置项为 'org.gnome.desktop.interface monospace-font-name' 和 'org.gnome.desktop.interface font-name' 。) - 使用命令行选项 '
-fn' (或 '--font' )指定字体(参见《字体指定选项》章节)。
若要查看当前使用的字体,可使用 C-u C-x = 命令,该命令会显示光标处字符的详细信息,同时标注其渲染所用的字体。
字体名的四种表示方式
方式一:Fontconfig 模式
Fontconfig 模式的字体名格式如下:
fontname[-fontsize][:name1=values1][:name2=values2]...
格式中所有方括号内的元素均可省略。其中:
fontname为字体家族名,如Monospace(等宽体)、DejaVu Sans Mono;fontsize为字体的号数(1 印刷点约等于 1/72 英寸);- 'name=values' 项用于指定字体的倾斜、字重等属性,values可为单个值,也可为逗号分隔的多个值;
- 部分属性值仅对应一种属性名,此种情况下可省略 'name=' 部分。
常用字体属性:
- 'slant'
- (倾斜)。italic(斜体)、oblique(伪斜体)、roman(正体)三者之一;
- 'weight'
- (字重)。light(细体)、medium(常规)、demibold(半粗)、bold(粗体)、black(特粗)五者之一;
- 'style'
- (样式)。部分字体会定义融合了倾斜和字重的特殊样式,例如Dejavu Sans的book样式,该样式会覆盖倾斜和字重的单独设置;
- 'width'
- (字宽)。condensed(紧缩)、normal(常规)、expanded(加宽)三者之一;
- 'spacing'
- (字符间距)。monospace(等宽)、proportional(比例间距)、dual-width(双宽)、charcell(字符格)四者之一。
Fontconfig 模式示例:
Monospace Monospace-12 Monospace-12:bold DejaVu Sans Mono:bold:italic Monospace-12:weight=bold:slant=italic
关于 Fontconfig 模式的详细说明,可参考 Fontconfig 手册(随 Fontconfig 分发,在线地址:https://fontconfig.org/fontconfig-user.html)。
注意:在 Windows 系统中,所有字体仅支持 fontname[-fontsize] 的简化格式,完整的 Fontconfig 模式并非对所有字体生效。
方式二:GTK 字体模式
GTK 字体模式的语法如下:
fontname [properties] [fontsize]
其中fontname为字体家族名,properties为空格分隔的属性值列表,fontsize为字体号数。
GTK 支持的字体属性:
- 倾斜属性:Italic(斜体)、Oblique(伪斜体),省略时默认为正体;
- 字重属性:Bold(粗体)、Book(书体)、Light(细体)、Medium(常规)、Semi-bold(半粗)、Ultra-light(超轻),省略时默认为Medium;
- 字宽属性:Semi-Condensed(半紧缩)、Condensed(紧缩),省略时使用默认字宽。
GTK 字体模式示例:
Monospace 12 Monospace Bold Italic 12
注意:在 Windows 系统中,仅支持fontname的最简格式。
方式三:XLFD(X 逻辑字体描述)
这是 X 窗口系统下指定字体的传统方式,Windows 系统也支持该格式。每个 XLFD 由 14 个以连字符分隔的单词或数字组成,示例如下:
-misc-fixed-medium-r-semicondensed--13-*-*-*-c-60-iso8859-1
XLFD 中的通配符 '*' 可匹配任意字符序列(包括空序列), '?' 可匹配单个字符;但匹配规则由具体实现决定,当通配符匹配长名称中的连字符时,结果可能不准确。为保证匹配可靠,需保留全部 14 个连字符,且仅在单个字段内使用通配符。XLFD 的大小写不敏感,完整语法如下:
-maker-family-weight-slant-widthtype-style… …-pixels-height-horiz-vert-spacing-width-registry-encoding
各字段含义:
- maker
- 字体制造商名称;
- family
- 字体家族名(如courier);
- weight
- 字重,通常为bold(粗)、medium(常规)、light(细),部分字体支持其他值;
- slant
- 倾斜样式,通常为r(正体)、i(斜体)、o(伪斜体)、ri(反向斜体)、ot(其他),部分字体支持其他值;
- widthtype
- 字宽,通常为normal(常规)、condensed(紧缩)、semicondensed(半紧缩)、extended(加宽),部分字体支持其他值;
- style
- 可选的附加样式名,通常为空(此时该位置会出现两个连续的连字符);也可指定 ISO-639 双字母语言代码(如ja日语、ko韩语),部分支持中日韩文字的字体会在此字段标注相关信息;
- pixels
- 字体高度(单位:像素);
- height
- 屏幕上的字体高度(单位:0.1 印刷点),即字体号数乘以 10;在固定垂直分辨率下,该值与pixels成正比,因此通常只需指定其中一个,另一个用*替代;
- horiz
- 字体适配的屏幕水平分辨率(单位:像素 / 英寸);
- vert
- 字体适配的屏幕垂直分辨率(单位:像素 / 英寸);系统字体的分辨率通常与当前屏幕匹配,因此这两个字段一般均设为*;
- spacing
- 字符间距类型,m(等宽)、p(比例间距)、c(字符格)三者之一;
- width
- 平均字符宽度(单位:0.1 像素);
- registry
- encoding
- 字体对应的 X 字体字符集(与 Emacs 字符集不同,但相似),可通过xfontsel程序查看可选值,通常注册表设为 'iso8859' 、编码设为 '1' 。
方式四:字体别名
部分字体会有简短的别名,可替代完整的字体规范表示,例如6x13等价于:
-misc-fixed-medium-r-semicondensed--13-*-*-*-c-60-iso8859-1
注意:该方式在 Windows 系统中不被支持。
X 窗口系统下的 Emacs 字体类型
在 X 系统中,Emacs 支持两种字体:
- 客户端字体:由 Xft 和 Fontconfig 库提供,支持抗锯齿、亚像素微调等高级字体特性;
- 服务端字体:由 X 服务器自身提供,不支持上述高级特性。
注意:Fontconfig 模式和 GTK 模式仅能匹配客户端字体。
等宽字体的查询与预览
Emacs 的默认字体建议使用等宽字体(所有字符宽度相同),不同类型字体的查询方式如下:
Xft/Fontconfig 客户端等宽字体:使用fc-list命令查询
fc-list :spacing=mono fc-list :spacing=charcell
X 服务端等宽字体:使用xlsfonts程序查询
xlsfonts -fn '*x*' | grep -E '^[0-9]+x[0-9]+' xlsfonts -fn '*-*-*-*-*-*-*-*-*-*-*-m*' xlsfonts -fn '*-*-*-*-*-*-*-*-*-*-*-c*'
XLFD 格式中, 间距字段为 'm' 或 'c' 的字体均为等宽字体。可使用xfd命令预览指定字体的样式,示例如下:
xfd -fn 6x13
该命令会显示 '6x13' 字体的所有字符。
补充说明
在 Emacs 运行过程中,还可为 特定类型的文本 单独设置字体(参见《文本面属性》章节),或为 单个框架 自定义字体(参见《框架参数》章节)。
23.9. 速览栏框架
speedbar速览栏 是一个特殊框架,用于便捷地在另一框架中进行导航或执行操作。速览栏一旦创建,始终与某个特定框架相关联,该框架被称为其 attached frame关联框架 ;所有速览栏操作均作用于这个关联框架。
键入 M-x speedbar 可创建速览栏,并将其与当前框架相关联。要关闭速览栏,可再次键入 M-x speedbar ,或选中速览栏后键入 q (也可像删除其他 Emacs 框架一样直接删除速览栏框架)。若要将速览栏关联至其他框架,需先关闭现有速览栏,再在目标框架中执行 M-x speedbar 命令。
速览栏支持多种工作模式, various modes文件显示模式 为其默认模式:该模式下,速览栏会按行显示关联框架选中窗口当前目录下的所有文件。点击非目录文件,会在关联框架的选中窗口中打开该文件(参见《用鼠标跟随引用链接》章节);点击目录,则会在速览栏中展示该目录的内容。每一行内容旁都有一个 '[+]' 或 '<+>' 的方框,点击该方框可 展开 对应项目的内容:展开目录会将该目录下的内容添加至速览栏中对应目录行的下方;展开普通文件则会在速览栏中列出该文件内的所有标签,点击标签名可跳转到关联框架选中窗口中该标签的对应位置。当文件或目录被展开后,旁侧的 '[+]' 会变为 '[-]' ,点击该方框可 折叠 项目,隐藏其展开的内容。
也可通过 键盘 操作速览栏进行导航:光标停在速览栏某一行时键入回车键( RET ),效果等同于点击该行的项目;按下空格键( SPC )可展开或折叠对应项目;按下 U 会显示当前目录的上级目录。要复制、删除或重命名光标所在行的文件,可分别键入 C 、 D 、 R ;按下 M 可创建新目录。
速览栏的另一通用模式为 Buffer Display mode缓冲区显示模式 ,该模式下速览栏会列出所有 Emacs 缓冲区。在速览栏中键入 b 可切换至该模式,键入 f 则可恢复为文件显示模式。也可在速览栏窗口的任意位置点击鼠标右键( mouse-3 )(或在模式行点击鼠标左键 mouse-1 ),在弹出的菜单中选择 显示方式 来切换显示模式。
部分主模式(包括 Rmail 邮件模式、Info 信息模式和 GUD 调试模式)为速览栏提供了 专属适配功能 ,会将该模式下的常用项目载入速览栏供用户选择。例如,在 Rmail 模式下,速览栏会列出所有 Rmail 邮件文件,点击文件旁的 '<M>' 方框,可将当前邮件移动至该 Rmail 文件中。
关于速览栏的使用与编程开发细节,详见《速览栏手册》中的速览栏相关章节。
23.10. 多显示器支持
单个 Emacs 程序可连接至多个 X 显示器。Emacs 启动时默认仅使用一个显示器 —— 即通过 DISPLAY 环境变量或 '–display' 选项指定的显示器(参见《启动选项》章节)。若要连接至其他显示器,可使用 make-frame-on-display 命令:
M-x make-frame-on-display RET 显示器名 RET- 在指定显示器上创建一个新框架。
单个 X 服务器可管理多个屏幕。当在同一服务器的两个屏幕上打开 Emacs 框架时,Emacs 会识别出这些屏幕共享一个键盘,并将来自这些屏幕的所有命令视作单一的输入流进行处理。
若在 不同 X 服务器 的显示器上打开 Emacs 框架,Emacs 会为每个服务器创建独立的输入流,且每个服务器各自拥有一个选中框架。通过某一特定 X 服务器输入的命令,仅会作用于该服务器对应的选中框架。
在多显示器显示环境中,还可使用 make-frame-on-monitor 命令:
M-x make-frame-on-monitor RET 显示器名 RET- 在指定的显示器上创建新框架,该显示器的屏幕区域为当前显示设备的一部分。
23.11. 框架参数
可通过在变量 default-frame-alist 中指定 框架参数默认列表 ,控制所有框架的默认外观与行为。该变量的值为一个参数条目列表,每个条目均指定一个参数名及其对应取值,这些条目会在 Emacs 创建新框架(包括初始框架)时生效。
例如,可在初始化文件中添加以下代码(参见《Emacs 初始化文件》章节),将默认框架宽度设为 90 字符列、默认框架高度设为 40 字符行,并将默认字体设为等宽字体 10 号( 'Monospace-10' ):
(add-to-list 'default-frame-alist '(width . 90)) (add-to-list 'default-frame-alist '(height . 40)) (add-to-list 'default-frame-alist '(font . "Monospace-10"))
关于框架参数的完整列表及其作用,详见《Emacs Lisp 参考手册》中的《框架参数》章节。
也可通过自定义变量 initial-frame-alist ,指定仅对 初始框架 生效的框架参数列表。
若 Emacs 编译时启用了 X 工具包支持,用于指定颜色和字体的框架参数将 不会作用于菜单和菜单栏 ,因为这类界面元素由 X 工具包绘制,而非 Emacs 直接渲染。
框架的外观与行为也可通过X 资源进行自定义(参见《X 选项与资源》章节),且 X 资源的配置会覆盖初始化文件中为初始框架指定的参数。
请注意,若使用桌面库保存和恢复 Emacs 会话,待恢复的框架及其参数会一同记录在桌面文件中。恢复这些框架时,文件中记录的参数会 优先于 初始化文件里 default-frame-alist 和 initial-frame-alist 所指定的框架参数。如何避免该情况,详见《保存 Emacs 会话》章节。
23.12. 滚动条
在图形化显示界面中,Emacs 的每个窗口侧边都会显示一个 垂直滚动条 。点击滚动条的上下箭头按钮,窗口会每次滚动一行(部分工具包支持自定义滚动条,可隐藏此类箭头按钮);在滚动条滑块的上方或下方点击 mouse-1 鼠标左键,窗口会分别向上、向下滚动近乎一整屏的内容,效果等同于快捷键 M-v 和 C-v (参见《移动光标位置》章节)(该行为在部分工具包中也可自定义);拖动滑块则可实现窗口的连续滚动。
若 Emacs 在 X 窗口系统中编译时未启用 X 工具包支持,滚动条的操作行为会有所不同:在滚动条的任意位置点击 mouse-1 鼠标左键,窗口会像按下 C-v 一样向下滚动;点击 mouse-3 鼠标右键,窗口会像按下 M-v 一样向上滚动;点击 mouse-2 鼠标中键并拖动,可上下移动滚动条滑块。
键入 M-x scroll-bar-mode 可 切换垂直滚动条的启用状态 ,该命令对所有框架生效,包括尚未创建的框架;若仅需切换当前选中框架的垂直滚动条状态,可使用命令 M-x toggle-scroll-bar 。
若要在 Emacs 启动时就控制垂直滚动条的启用状态,可自定义变量 scroll-bar-mode (参见《自定义配置》章节)。该变量的取值有三种: right (将滚动条置于窗口右侧)、 left (将滚动条置于窗口左侧)、 nil (禁用垂直滚动条)。默认情况下,若 Emacs 在 X 窗口系统中编译时启用了 GTK+ 支持,或运行在 Windows、macOS 系统中,滚动条会默认显示在窗口右侧;若 Emacs 在 X 窗口系统中编译时未启用 GTK+ 支持,滚动条会默认显示在窗口左侧(遵循 X 应用程序的旧有惯例)。
也可通过 X 资源项 'verticalScrollBars' 启用或禁用滚动条(参见《X 资源》章节);若要调整滚动条的宽度,可修改框架参数 scroll-bar-width (参见《Emacs Lisp 参考手册》中的《框架参数》章节)。
若在 X 窗口系统中使用 Emacs(启用 GTK+ 或 Motif 支持),可自定义变量 scroll-bar-adjust-thumb-portion ,控制滚动条的 超滚动 行为(即即便缓冲区末尾已显示在窗口中,仍可向下拖动滑块)。当该变量取值为非nil时,即便缓冲区末尾可见,仍可向下拖动滚动条滑块;取值为 nil 时,若缓冲区末尾已显示,滑块会固定在滚动条最下方。当整个缓冲区内容均可在窗口中显示时,无法触发超滚动行为。
滚动条的 视觉样式 由 scroll-bar 滚动条外观属性控制(部分工具包如 GTK+、Windows 会忽略该面属性,其滚动条样式仅能通过系统全局设置自定义,GTK + 的相关配置可参见《GTK + 资源》章节)。
在图形化框架中,垂直滚动条还会在 视觉上分隔左右并排的窗口 。当垂直滚动条被禁用时,Emacs 会默认使用 1 像素宽的垂直边框分隔这类窗口。该边框会占据右侧窗口的第一列像素,可能会遮挡窗口中显示的字符最左侧的像素。若这些像素包含重要信息,可启用 窗口分隔线 使其显示(参见《窗口分隔线》章节);若要还原垂直边框的视觉效果,可将框架的 right-divider-width 参数设为 1,并让窗口分隔线的面属性继承垂直边框的面属性(详见《Emacs Lisp 参考手册》中的《窗口分隔线》章节)。
在启用了工具包支持的图形化显示界面中,Emacs 还可为每个窗口的底部添加 horizontal scroll bar水平滚动条 。点击水平滚动条的左右箭头按钮,窗口会每次水平滚动一列;(注意:部分工具包支持自定义滚动条,可隐藏此类箭头按钮);在水平滚动条滑块的左侧或右侧点击鼠标左键,窗口会分别向左、向右滚动四列;拖动滑块则可实现窗口的连续水平滚动。
需注意,水平滚动可能会导致 光标位置移出窗口的左右可视区域 。此时键入字符插入文本,或使用键盘命令移动光标,光标通常会重新回到可视区域内。
键入 M-x horizontal-scroll-bar-mode 可 切换水平滚动条的启用状态 ,该命令对所有框架生效,包括尚未创建的框架;若仅需切换当前选中框架的水平滚动条状态,可使用命令 M-x toggle-horizontal-scroll-bar 。
若要在 Emacs 启动时控制水平滚动条的启用状态,可自定义变量 horizontal-scroll-bar-mode 。
也可通过 X 资源项 'horizontalScrollBars' 启用或禁用水平滚动条(参见《X 资源》章节);若要调整水平滚动条的高度,可修改框架参数 scroll-bar-height (参见《Emacs Lisp 参考手册》中的《框架参数》章节)。
23.13. 窗口分隔线
在图形化显示界面中,可启用 window dividers 窗口分隔线实现窗口的视觉分隔。窗口分隔线为可通过鼠标拖动的条状区域,借助它能轻松调整相邻窗口的尺寸。
键入命令 M-x window-divider-mode ,可切换窗口分隔线的显示状态。
如需自定义窗口分隔线的显示位置,可配置选项 window-divider-default-places ,其取值有三种: bottom-only (仅在窗口底部显示分隔线)、 right-only (仅在窗口右侧显示分隔线)、 t (在窗口底部和右侧均显示分隔线)。
如需调整该模式下窗口分隔线的宽度,可分别配置选项 window-divider-default-bottom-width (底部分隔线宽度)和 window-divider-default-right-width (右侧分隔线宽度)。
当垂直滚动条被禁用时,窗口分隔线还能发挥实用作用 —— 让窗口的第一列像素保持可见。若不启用分隔线,这一列像素会被用于分隔左右并排窗口的垂直边框遮挡(参见《滚动条》章节)。
关于窗口分隔线的更多细节,详见《Emacs Lisp 参考手册》中的窗口分隔线相关章节
23.14. 拖放功能
在大多数图形化桌面环境中,Emacs 支持基础的拖放操作。例如,将文本拖放至 Emacs 框架中,文本会被插入到拖放的位置;将文件拖放至 Emacs 框架中,Emacs 会打开该文件。一个特殊场景为:若将文件拖放至 Dired 缓冲区,该文件会根据源应用的操作规则,被移动或复制到该缓冲区所显示的目录中。
将文件拖放至 Emacs 时,默认会在拖放目标窗口中打开该文件。若希望此类场景下在新窗口中打开文件,可自定义变量 dnd-open-file-other-window 。
Emacs 目前支持 XDND、Motif 拖放协议,以及旧版的 KDE 1.x 拖放协议。
在将文本拖向 Emacs 窗口的过程中,若要滚动窗口或确定拖放文本的插入位置,操作起来会较为不便。将选项 dnd-indicate-insertion-point 设为非nil值后,拖放过程中鼠标在窗口内移动时,光标会自动跳至文本即将被插入的位置;将 dnd-scroll-margin 设为整数值后,拖放时若鼠标移动至窗口顶部或底部的该数值行范围内,窗口会自动滚动。
Emacs 也可通过鼠标将选区拖放至当前缓冲区或其他缓冲区的任意位置,该功能需将变量 mouse-drag-and-drop-region 设为非nil值方可启用。默认规则为:若拖放的目标缓冲区与源缓冲区为同一个,文本会被移动(即剪切并粘贴);若拖放至其他缓冲区,则仅复制文本。若将该变量设为某一修饰键名称(如'shift'、'control'或'alt'),则拖放时按住该修饰键,即便拖放至源缓冲区,文本也会被复制而非剪切。
若希望即便源缓冲区与目标缓冲区不同,拖放时仍执行剪切操作,可将选项 mouse-drag-and-drop-region-cut-when-buffers-differ 设为非nil值。默认情况下,在图形化显示界面中,拖放过程中选中的文本会在工具提示中显示,且光标会随鼠标指针一同移动。若要关闭该行为,可将选项 mouse-drag-and-drop-region-show-tooltip 或 mouse-drag-and-drop-region-show-cursor 设为nil。
若要将文本从 Emacs 拖放至其他程序,需将选项 mouse-drag-and-drop-region-cross-program 设为非nil值。
在 X 窗口系统中,部分程序可将文件拖放至 Emacs,期望 Emacs 对其进行保存。默认情况下,Emacs 会先提示用户输入保存的文件名,完成保存后再打开该文件;可通过修改变量 x-dnd-direct-save-function 更改此行为。更多细节详见《Emacs Lisp 参考手册》中的拖放操作相关章节。
23.15. 菜单栏
可使用 M-x menu-bar-mode 命令切换菜单栏的启用状态。不带参数执行该命令时,会对 菜单栏模式 (一款全局次要模式)进行开关切换;带参数执行时,若参数为正数则开启菜单栏模式,非正数则关闭。若要在 Emacs 启动时控制菜单栏的启用状态,可自定义变量 menu-bar-mode 。
资深用户通常会关闭菜单栏,在文本终端中尤为如此 —— 关闭后能多腾出一行空间用于显示文本。若菜单栏已关闭,在支持弹出菜单的显示界面中,可通过 C-mouse-3 调出包含菜单栏全部内容的弹出菜单;也可启用上下文菜单模式,并自定义变量 context-menu-functions ,通过点击鼠标右键(mouse-3)调出上下文菜单,相关操作详见《菜单的鼠标点击操作》章节。
关于如何通过菜单栏调用命令的相关说明,参见《菜单栏》章节;关于如何自定义菜单栏及菜单项视觉样式的方法,参见《X 选项与资源》章节。
23.16. 工具栏
在图形化显示界面中,Emacs 会在每个框架的顶部、菜单栏正下方显示一个工具栏。工具栏是一排带有图标的按钮,点击这些按钮可调用各类对应命令。Emacs 也可根据需要,在每个窗口的顶部单独显示工具栏(参见《窗口工具栏》章节)。
全局(默认)工具栏包含各类通用命令,部分主模式也会定义专属工具栏:当当前缓冲区使用这类带专属工具栏的主模式时,该主模式的工具栏会替换全局工具栏。若要阻止这种替换行为,可自定义变量 tool-bar-always-show-default 。
键入 M-x tool-bar-mode 可切换工具栏的启用状态,该命令对所有框架生效,包括尚未创建的框架。若要在 Emacs 启动时控制工具栏的启用状态,可自定义变量 tool-bar-mode 。
当 Emacs 编译时启用了 GTK+ 支持,每个工具栏项可仅显示图片、仅显示文本标签,或同时显示两者。默认情况下,Emacs 会遵循 GNOME 桌面的工具栏样式设置;若未定义相关设置,则仅以图片形式显示工具栏项。若要强制使用特定的工具栏样式,可自定义变量 tool-bar-style 。
对于 GTK+ 工具栏,还可通过框架参数 tool-bar-position 控制其显示位置,详见《Emacs Lisp 参考手册》中的《框架参数》章节。
NS 版本的 Emacs 将工具栏视作 窗口装饰元素 ,因此当窗口取消装饰时,工具栏也会随之隐藏,相关说明详见《Emacs Lisp 参考手册》中的《框架参数》章节。在 macOS 系统中,当框架进入全屏模式时工具栏会被隐藏,将鼠标指针移至屏幕顶部即可重新显示工具栏。
部分键盘会缺少 Emacs 用户可能需要用到的修饰键(参见《修饰键》章节),导致用户无法或难以输入带这些修饰键的按键序列。例如,许多键盘无 Hyper 和 Super 修饰键,智能手机的虚拟键盘通常也没有 Ctrl 和 Alt 修饰键。针对此情况,Emacs 可选择性显示一个由修饰键按钮组成的额外工具栏,即 modifier bar修饰键栏 。点击修饰键栏中的按钮后,Emacs 会将该按钮对应的修饰键应用到接下来读取的一次键盘操作中。启用全局次要模式 modifier-bar-mode 即可显示修饰键栏,键入 M-x modifier-bar-mode 可完成该模式的开关切换。
23.17. 标签栏
在图形化显示界面和文本终端中,Emacs 可根据需要在每个框架的顶部显示 Tab Bar标签栏 ,其位置位于菜单栏下方(参见《菜单栏》)、工具栏上方或下方(参见《工具栏》),具体由变量 tab-bar-position 控制。标签栏是一排标签按钮,点击即可在不同的窗口配置间切换。
标签栏中的每个标签,代表其所属框架的一个 命名持久化窗口配置 ,即该框架被划分为多个窗口的布局方式,以及每个窗口中显示的对应缓冲区。标签名称由该窗口配置下各窗口所显示的缓冲区名称组合而成。点击标签会切换至该标签记录的窗口配置,该配置是此框架中该标签作为当前标签时曾使用过的窗口与缓冲区布局。
若你使用桌面库保存和恢复 Emacs 会话(参见《保存 Emacs 会话》),标签栏中的所有标签会与其关联的窗口配置一同记录在桌面文件中,恢复会话后这些标签仍可使用。
请注意, 标签栏 与 标签行 (参见《窗口标签行》)并非同一功能:窗口顶部标签行的标签,用于在当前窗口的不同缓冲区间切换;而框架顶部标签栏的标签,用于在包含多个窗口、显示一个或多个缓冲区的不同窗口配置间切换。
键入 M-x tab-bar-mode 可切换标签栏的启用状态,该命令对所有框架生效,包括尚未创建的框架。若要在 Emacs 启动时控制标签栏的启用状态,可自定义变量 tab-bar-mode 并保存该配置。
变量 tab-bar-show 用于控制标签栏模式是否自动开启:
- 若取值为
t,执行创建新标签的命令时会自动启用标签栏模式; - 若取值为
1,当标签栏仅有一个标签时会自动隐藏,创建更多标签后则重新显示; - 更通用的规则为,若取值为非负整数,仅当标签数量大于该数值时,标签栏才会显示;
- 若取值为
nil,标签栏会始终隐藏,此时仍可通过M-x tab-next、M-x tab-switcher等支持标签名补全的命令,在不显示标签栏的情况下切换命名窗口配置,也可通过M-x tab-new、M-x tab-close等命令完成标签的创建与关闭。
需注意,若 tab-bar-show 设为数值,标签栏可能会在部分框架中显示、另一部分框架中隐藏,具体取决于各框架中创建的标签数量。
若仅需切换当前选中框架的标签栏启用状态,可键入 M-x toggle-frame-tab-bar 。该命令可实现对不同框架的标签栏进行选择性启用,不受 tab-bar-mode 和 tab-bar-show 取值的影响。
前缀键 C-x t 的功能逻辑与 C-x 5 相似: C-x 5 系列命令会在不同框架中打开缓冲区(参见《创建框架》),而 C-x t 系列命令会在选中框架的不同标签中,以不同的窗口配置打开缓冲区。
C-x t 下的各类命令,核心区别在于查找或创建待选中缓冲区的方式,以下命令可在新标签中选中指定缓冲区:
C-x t 2- 新建一个标签 (
tab-new) 。可通过自定义变量tab-bar-new-tab-choice,控制新标签中默认显示的缓冲区;也可通过自定义变量tab-bar-tab-name-function,设置新标签的默认命名规则。 C-x t bbufname RET=- 在另一个标签中选中指定名称的缓冲区,对应命令
switch-to-buffer-other-tab。 C-x t ffilename RET=- 打开指定文件(参见《打开文件》),并在另一个标签中选中该文件对应的缓冲区,对应命令
find-file-other-tab。 C-x t ddirectory RET=- 在另一个标签中编辑指定目录(参见《Dired:目录编辑器》),对应命令
dired-other-tab。 C-x t t- 一个前缀命令 (
other-tab-prefix) ,作用于紧随其后执行的命令:该前缀会让后续命令所显示的缓冲区,在新的标签中展示。
默认情况下,新建标签会显示执行新建命令前的当前缓冲区。若要让新标签默认显示其他缓冲区,可自定义变量 tab-bar-new-tab-choice 。
变量 tab-bar-new-tab-to 用于控制新标签的位置,默认情况下,新标签会添加在当前标签的右侧。
标签的删除命令
C-x t 0- 关闭当前选中的标签 (
tab-close) 。若标签栏中仅有一个标签,该操作默认无效果,除非将变量tab-bar-close-last-tab-choice自定义为非默认值。 C-x t 1- 关闭当前选中框架中,除当前标签外的所有其他标签。
变量 tab-bar-close-tab-select 用于控制关闭当前标签后选中的目标标签,默认会选中最近使用过的标签。
命令 tab-undo 可恢复最后一个被关闭的标签。
标签的切换命令
C-x t oC-TAB- 切换至下一个标签 (
tab-next) 。重复执行该命令,会在当前选中框架的所有标签间循环切换。带正数值前缀参数n时,切换至第n个下一个标签;带负数值前缀参数 - n 时,切换至第 n 个上一个标签。 S-C-TAB- 切换至上一个标签 (
tab-previous) 。带正数值前缀参数n时,切换至第n个上一个标签;带负数值前缀参数-n时,切换至第n个下一个标签。 C-x t RET tabname RET- 根据标签名切换标签 (
tab-switch) ,支持所有标签名的补全功能。标签名的默认候选列表和 “future history历史未来项” 会按最近使用顺序排序,因此可使用M-n(next-history-element) 快速选择最后一个、倒数第二个曾访问的标签名。 modifier-tab-number修饰键 + 标签数字根据标签的序号切换标签 (tab-select) 。先自定义变量tab-bar-select-tab-modifiers,指定一个或多个修饰键后,即可通过 指定修饰键 + 标签数字 的组合键,按序号选中对应标签;数字 9 可用于选中最后一个标签。Emacs 支持的所有修饰键均可配置(参见《修饰键》)。若要在标签名称旁显示标签序号,可自定义变量tab-bar-tab-hints,便于你快速确定选中对应标签所需按下的数字键。modifier-9修饰键 + 9切换至最后一个标签 (tab-last) ,组合键为tab-bar-select-tab-modifiers定义的修饰键 + 数字 9。带数值前缀参数n时,切换至倒数第n个标签。modifier-0修饰键 + 0切换至最近使用的标签 (tab-recent) ,组合键为tab-bar-select-tab-modifiers定义的修饰键 + 数字 0。带数值前缀参数n时,切换至第n个最近使用的标签。
标签的操作命令
C-x t r tabname RET- 将当前标签重命名为指定名称 (
tab-rename) 。 C-x t m- 将当前标签向右移动一个位置 (
tab-move) 。带正数值前缀参数n时,向右移动n个位置;带负数值前缀参数-n时,向左移动n个位置。
标签的鼠标操作
点击鼠标中键( mouse-2 )可关闭对应标签;点击鼠标右键( mouse-3 )会弹出上下文菜单,包含对该标签的各类操作选项;按住鼠标左键( mouse-1 )拖动标签,可将其移至标签栏的其他位置;滚动鼠标滚轮,可在标签间切换至上一个或下一个;滚动滚轮时按住 Shift 键,可将当前标签向左或向右移动。
标签的触摸屏操作
也可通过触摸屏输入操作标签(参见《触摸屏输入与虚拟键盘》): 长按 (参见《在触摸屏上使用 Emacs》)某个标签,会弹出对该标签的操作上下文菜单;长按标签栏本身,会弹出可创建和删除标签的上下文菜单;轻点某个标签,即可选中该标签对应的窗口配置;轻点标签栏上的按钮,效果等同于用 mouse-1 鼠标左键点击该按钮。
可启用 tab-bar-history-mode 模式,让 Emacs 记录每个标签使用过的所有窗口配置,后续可恢复这些配置:
M-x tab-bar-history-back- 恢复当前标签曾使用过的上一个窗口配置,可在窗口配置的历史记录中向后回溯;
M-x tab-bar-history-forward- 撤销上一次的窗口配置恢复操作,可在窗口配置的历史记录中向前前进。
可通过用户选项 tab-bar-format ,自定义标签栏上显示的各类元素。
23.18. 使用对话框
dialog box对话框 是一种特殊的交互窗口,用于向用户询问 yes-or-no 是否 类问题或其他特定问题。若你通过鼠标调用触发该问题的 Emacs 命令,许多 Emacs 命令都会通过对话框提出是否类的询问。
若要禁用对话框,可将变量 use-dialog-box 设为 nil 。此时 Emacs 将始终通过回显区和键盘输入的方式,发起 yes-or-no 是否 类的提示询问。该变量同时也控制是否启用文件选择窗口(但并非所有平台都支持此功能)。
文件选择窗口是用于询问文件名的专用对话框。即便你希望保留其他类型的对话框,也可自定义变量 use-file-dialog 来禁用文件选择窗口。若你已通过变量 use-dialog-box 禁用了所有对话框,此变量将不再生效。
当 Emacs 编译时启用了 GTK+ 支持,其会调用 GTK+ 文件选择对话框。Emacs 为该对话框新增了一个切换按钮,可通过此按钮在对话框中显示或隐藏隐藏文件(以 . 句点开头的文件)。若希望该切换按钮默认处于启用状态,可将变量 x-gtk-show-hidden-files 设为 t 。此外,Emacs 还为 GTK+ 文件选择对话框添加了帮助文本;若要禁用该帮助文本,可将变量 x-gtk-file-dialog-help-text 设为 nil 。
23.19. 工具提示
Tooltips工具提示 是一类小型专用框架,会在当前鼠标位置显示文本信息。当鼠标在窗口中的重要文本区域、模式行,或是 Emacs 框架的其他区域(如工具栏按钮、菜单项)上停留不动时,工具提示便会激活。
可通过命令 M-x tooltip-mode 切换工具提示的启用状态。禁用工具提示模式后,帮助文本将转而在回显区显示。若要控制启动时工具提示的启用状态,可自定义变量 tooltip-mode 。
以下变量为工具提示的显示提供了自定义选项:
tooltip-delay- 该变量指定 Emacs 在显示第一个工具提示前的等待时长,取值单位为秒。
tooltip-short-delay- 该变量指定 Emacs 在已显示第一个工具提示后,为不同项目显示后续工具提示前的等待时长,取值单位为秒。
tooltip-hide-delay- 若鼠标保持不动,工具提示从显示到自动隐藏的间隔时长,取值单位为秒。
tooltip-x-offsettooltip-y-offset- 工具提示的左上角相对于鼠标指针位置的水平、垂直偏移量,取值单位为像素。注意,若
tooltip-frame-parameters被自定义为分别包含left和top参数,这两个偏移量变量将被忽略。选择偏移量数值时,应确保工具提示不会遮挡鼠标指针的热点区域,否则可能干扰鼠标的点击操作。 tooltip-frame-parameters- 用于显示工具提示的框架参数。详见《Emacs Lisp 参考手册》中的「框架参数」章节,以及该手册中的「工具提示」章节。
若需更多工具提示的显示自定义选项,可执行 M-x customize-group RET tooltip RET 进行配置。
当 Emacs 基于 GTK+ 工具包、Nextstep 窗口系统或 Haiku 窗口系统编译构建时,会通过对应工具包显示工具提示,并沿用工具包自身工具提示的默认外观 8。若要禁用此功能,可将变量 use-system-tooltips 设为 nil 。禁用后,或当 Emacs 编译时未加入相应的窗口系统支持时,工具提示文本的大部分显示属性将由 tooltip 面版,以及 X 资源进行指定(参见X 选项与资源)。
GUD 工具提示是一类特殊的工具提示,在使用 GUD 调试程序时,会显示变量的取值。详见调试器操作。
23.20. 鼠标避让功能
在图形化终端中,鼠标指针可能会遮挡 Emacs 框架内的文本内容。Emacs 提供了两种方法来解决这一问题。
第一种,当鼠标指针位于 Emacs 框架内时,你每输入一个自插入字符,Emacs 就会自动隐藏鼠标指针;移动鼠标指针则会使其重新显示。若要禁用该功能,将变量 make-pointer-invisible 设为 nil 即可,详见「显示的自定义」章节。
第二种,你可以启用鼠标避让模式(一款辅助模式),让鼠标指针远离光标位置。启用该模式需自定义变量 mouse-avoidance-mode ,可为其设置不同取值,以多种方式移动鼠标指针:
banish- (归位)按下任意按键时,将鼠标指针移至框架的角落。可通过自定义变量
mouse-avoidance-banish-position,指定指针归位的目标位置。 exil- (暂移)仅当光标过于靠近指针时才将其归位,待光标移开后,允许指针回到原位置。
jum- (跃移)若光标过分靠近指针,将指针向随机方向移动一段随机距离。
animat- (动移)功能与跃移一致,只是会通过分步移动的效果营造出指针的动态移动观感。
cat-and-mous- (猫鼠式)与动移模式功能完全相同。
proteu- (变形移)在动移模式的基础上,还会同时改变鼠标指针的形状。
你也可通过执行命令 M-x mouse-avoidance-mode 启用该模式。每当鼠标避让模式移动鼠标指针时,对应的 Emacs 框架也会被置于顶层显示。
23.21. 文本终端
在文本终端中,Emacs 同一时间仅能显示一个 Emacs 框架,但你仍可创建多个 Emacs 框架并在其中切换。此类终端上的框架切换,与不同窗口配置间的切换方式十分相似。
使用快捷键 C-x 5 2 创建新框架并切换至该框架;使用 C-x 5 o 循环切换所有已存在的框架;使用 C-x 5 0 删除当前框架。
每个框架都有专属编号用于区分。若你的终端同一时间仅能显示一个框架,当前选中框架的编号 n 会以 'Fn' 的形式显示在模式行的开头位置。
'Fn' 实际上是框架的初始名称。你可根据需要为框架设置更具意义的名称,也可通过名称选中对应框架。使用命令 M-x set-frame-name RET name RET ,可为当前选中的框架指定新名称;使用命令 M-x select-frame-by-name RET name RET ,可根据名称选中对应框架。当某一框架被选中时,你为其设置的名称会显示在模式行中。
23.22. 文本终端中的鼠标使用
部分文本终端支持在终端窗口内进行鼠标点击操作。
在兼容 xterm 的终端模拟器中,可使用 M-x xterm-mouse-mode 命令让 Emacs 接管鼠标的基础使用功能 —— 该模式下基本仅支持无修饰键的单次点击操作。新版本的 xterm 还支持鼠标追踪功能。若需使用 xterm 针对此类点击的原生鼠标功能,可在按下鼠标按键的同时按住 SHIFT 键。Xterm 鼠标模式为全局次要模式(参见「次要模式」相关内容),重复执行该命令即可关闭此模式。
在 GNU/Linux 的控制台中,可使用 M-x gpm-mouse-mode 命令启用鼠标支持功能。使用该功能前,你的系统中必须已安装并运行 gpm 服务端程序。请注意,启用此模式后,无法通过鼠标在 Emacs 与其他使用 GPM 的程序之间传输文本,这是由 GPM 和 Linux 内核的功能限制导致的。
有关 MS-DOS 系统下的鼠标支持相关信息,参见「MS-DOS 下的鼠标使用」章节。
24. 国际字符集支持
Emacs 支持多种国际字符集,包括拉丁语系的欧洲变体、越南变体,同时支持阿拉伯文字、婆罗米系文字(适用于孟加拉语、印地语、泰语等语言)、西里尔文字、埃塞俄比亚文字、格鲁吉亚文字、希腊文字、汉字(适用于中、日两国语言)、韩文、希伯来文字以及国际音标字符。Emacs 还支持这些字符的各类编码方式,这类编码也被文字处理软件、邮件客户端等其他国际化软件所采用。
Emacs 通过对所有相关操作提供支持,实现带国际字符文本的编辑功能,具体包括:
- 可打开含非 ASCII 字符的文件、保存非 ASCII 文本,也可在 Emacs 与其调用的程序(如编译器、拼写检查器、邮件客户端)之间传递非 ASCII 文本。设置语言环境(参见「语言环境」)可自动为特定语言或文化配置编码体系及其他相关选项;你也可单独为每个命令指定 Emacs 对文本的编码与解码方式(参见「为文件文本指定编码体系」)。
- 可显示各类文字编码的非 ASCII 字符。在图形化显示界面中,该功能通过调用适配字体实现(参见「定义字体集」);在文本显示界面中,通过向终端发送特殊编码实现(参见「终端输入输出的编码体系」)。若部分字符显示异常,可参考「无法显示的字符」章节,其中介绍了可能出现的问题及对应的解决方法。
- 对于文字自然排版方向为从右至左的文字体系,Emacs 会对其字符重新排序后再显示(参见「双向编辑」),这类文字包括阿拉伯文、希伯来文、叙利亚文、塔安那文等少数文字。
可插入或搜索非 ASCII 字符。你可选择适配自身使用语言的 Emacs 输入方法(参见「选择输入方法」),或使用选择语言环境时默认配置的输入方法;若你的键盘可输入非 ASCII 字符,可选择对应的键盘编码体系(参见「终端输入输出的编码体系」),Emacs 将直接识别这些字符。在图形化显示界面中,现代系统通常会提供原生输入方法,同时也可通过
C-x 8前缀输入 Latin-1 字符(参见「单字节编辑模式」)。在 X 窗口系统中,需将系统区域设置为对应值,以确保 Emacs 正确解析键盘输入(参见「区域设置」与「X 键盘输入的编码体系」)。
本章后续内容将对上述问题展开详细说明。
24.1. 国际字符集简介
国际字符集与文字体系的使用者已制定了诸多标准化程度不一的编码系统,用于文件存储。这类编码系统通常为 multibyte多字节编码 ,即使用两个或更多字节的序列来表示单个非 ASCII 字符。
Emacs 内部采用自研的多字节字符编码,该编码是 Unicode 标准的超集 。这种内部编码支持将几乎所有已知文字体系的字符混合在单个缓冲区或字符串中。Emacs 在读写文件、与子进程交换数据时,会在自身多字节字符编码与其他各类编码系统之间进行转换。
执行命令 C-h h (view-hello-file) 可打开 etc/HELLO 文件,该文件通过展示多种语言的 “hello” 表达,直观呈现了不同的文字体系。若你的终端无法显示部分字符,这些字符会以 '?' 或空心方块形式呈现(参见《无法显示的字符》)。
即便在使用这些字符集的国家,键盘通常也不会为所有字符配备独立按键。你可使用 C-x 8 RET (insert-char) 插入键盘不支持的字符(参见《插入文本》)。部分常用字符配有快捷输入方式:例如,输入 C-x 8 [ 可插入左单引号 ‘ ;若启用智能引号模式,通常直接按 ` 键即可输入。(参见《引号》)。Emacs 还支持多种输入法,通常一种文字体系 / 语言对应一种输入法,可简化对应字符的输入操作(参见《输入法》)。
前缀键 C-x RET 用于调用与多字节字符、编码系统和输入法相关的命令。
命令 C-x = (what-cursor-position) 可显示光标所在位置字符的相关信息。除了《光标位置信息》中介绍的字符位置外,该命令还会展示字符的编码方式。例如,对于字符 'c' ,该命令会在回显区显示以下内容:
Char: c (99, #o143, #x63) point=28062 of 36168 (78%) column=53
'Char:' 后的四个值用于描述光标后方的字符,先显示字符本身,再依次给出其十进制、八进制和十六进制的字符编码。对于非 ASCII 多字节字符,若当前缓冲区的编码系统能对该字符进行 单字节安全编码 ,则会在后续显示 'file' 及该字符在该编码系统中的十六进制表示(参见《编码系统》);若字符的编码长度超过一个字节,Emacs 会显示 'file …' 。
在极少数情况下,Emacs 会遇到 raw bytes原始字节 :即值在 128(八进制 0200)至 255(八进制 0377)范围内的单字节,Emacs 无法将其解析为某类已知非 ASCII 字符编码的一部分。这类原始字节会被归为特殊的 八位字符集 ,Emacs 会将其以转义八进制码形式显示(该方式可自定义,参见《显示的自定义》)。这种情况下, C-x = 会显示原始字节而非文件。此外,Emacs 会将原始字节的字符编码映射至 #x3FFF80~#x3FFFFF 区间并展示,以此与 #x0080~#x00FF 区间的 Unicode 字符区分开。
若为该命令添加前缀参数( C-u C-x = ),会额外调用 describe-char 命令,展示该字符的详细描述信息,包括:
- 字符集名称,以及该字符在对应字符集中的编码;ASCII 字符归属于 ascii 字符集。
- 字符所属的文字体系、语法类型和分类。
- 在当前输入法中输入该字符的按键组合(若当前输入法支持该字符)。
- 字符的编码方式,包括在缓冲区中的内部编码,以及将缓冲区保存为文件时的外部编码。
- 若在图形界面运行 Emacs,会显示该字符对应的字体名称和字形编码;若在文本终端运行 Emacs,会显示发送至终端的编码。
- 若该字符在显示时与后续字符组合形成一个或多个 grapheme cluster字素簇 ,会展示组合信息:图形界面下为对应字体字形,以及参与组合的所有字符。
- 字符的文本属性(参见《Emacs Lisp 参考手册》中的《文本属性》),包括用于显示该字符的所有非默认面,以及包含该字符的所有覆盖层(参见同一手册中的《覆盖层》)。
以下是详细描述的示例(部分行做折行处理以适配手册排版):
position: 1 of 1 (0%), column: 0 # 位置 character: ê (displayed as ê) (codepoint 234, #o352, #xea) # 字符。显示、编码点、八进制、十六进制 preferred charset: unicode (Unicode (ISO10646)) # 首选字符集 code point in charset: 0xEA # 字符集内编码点 script: latin # 文字体系 syntax: w which means: word # 语法类型。w 表示:单词字符 category: .:Base, L:Left-to-right (strong), c:Chinese, j:Japanese, l:Latin, v:Viet # 字符分类。基础字符,L:从左到右(强),c:中文 to input: type "C-x 8 RET ea" or "C-x 8 RET LATIN SMALL LETTER E WITH CIRCUMFLEX" # 输入方式。C-x 8 RET ea buffer code: #xC3 #xAA # 缓冲区编码 file code: #xC3 #xAA (encoded by coding system utf-8-unix) # 文件编码 display: by this font (glyph code) # 显示方式。使用以下字体(字形编码) xft:-PfEd-DejaVu Sans Mono-normal-normal- normal-*-15-*-*-*-m-0-iso10646-1 (#xAC) Character code properties: customize what to show # 字符编码属性:可自定义展示内容 name: LATIN SMALL LETTER E WITH CIRCUMFLEX # 名称 old-name: LATIN SMALL LETTER E CIRCUMFLEX # 旧名称 general-category: Ll (Letter, Lowercase) # 通用分类 decomposition: (101 770) ('e' '^') # 字符分解
24.2. 语言环境
只要启用了多字节字符功能,Emacs 缓冲区就支持所有受兼容的字符集,无需为显示某类字符专门选择对应的语言。但选择 language environment语言环境 对配置各类默认项至关重要,简单来说,语言环境选择的是 首选文字体系 ,而非具体的语言。
语言环境会控制 Emacs 读取文本时识别的编码体系(参见「识别编码体系」),该规则适用于文件、接收的邮件及所有读入 Emacs 的文本,也可指定新建文件时使用的默认编码体系。每种语言环境还会对应一个默认的输入方法。
选择语言环境
可通过自定义变量 current-language-environment ,或使用命令 M-x set-language-environment 选择语言环境。执行该命令时当前处于哪个缓冲区不产生影响,因为其效果会全局作用于整个 Emacs 会话。受支持的语言环境列表可查看变量 language-info-alist ;若需了解某一语言环境 lang-env 的详细信息,可使用命令 C-h L lang-env RET (describe-language-environment) 。
Emacs 支持的语言环境包括:
ASCII, Arabic, Belarusian, Bengali, Brazilian Portuguese, Bulgarian, Burmese, Cham, Chinese-BIG5, Chinese-CNS, Chinese-EUC-TW, Chinese-GB, Chinese-GB18030, Chinese-GBK, Croatian, Cyrillic-ALT, Cyrillic-ISO, Cyrillic-KOI8, Czech, Devanagari, Dutch, English, Esperanto, Ethiopic, French, Georgian, German, Greek, Gujarati, Hebrew, IPA, Italian, Japanese, Kannada, Khmer, Korean, Lao, Latin-1, Latin-2, Latin-3, Latin-4, Latin-5, Latin-6, Latin-7, Latin-8, Latin-9, Latvian, Lithuanian, Malayalam, Oriya, Persian, Polish, Punjabi, Romanian, Russian, Sinhala, Slovak, Slovenian, Spanish, Swedish, TaiViet, Tajik, Tamil, Telugu, Thai, Tibetan, Turkish, UTF-8, Ukrainian, Vietnamese, Welsh, and Windows-1255.
ASCII、阿拉伯语、白俄罗斯语、孟加拉语、巴西葡萄牙语、保加利亚语、缅甸语、占语、中文 - 大五码、中文 - 万国码、中文 - 欧盟扩展码繁体、中文 - 国标码、中文 - 国标 18030、中文 - 国标扩展码、克罗地亚语、西里尔文 - 替代码、西里尔文 - 国际标准码、西里尔文 - KOI8 码、捷克语、天城文、荷兰语、英语、世界语、埃塞俄比亚语、法语、格鲁吉亚语、德语、希腊语、古吉拉特语、希伯来语、国际音标、意大利语、日语、卡纳达语、高棉语、韩语、老挝语、拉丁语 - 1、拉丁语 - 2、拉丁语 - 3、拉丁语 - 4、拉丁语 - 5、拉丁语 - 6、拉丁语 - 7、拉丁语 - 8、拉丁语 - 9、拉脱维亚语、立陶宛语、马拉雅拉姆语、奥里亚语、波斯语、波兰语、旁遮普语、罗马尼亚语、俄语、僧伽罗语、斯洛伐克语、斯洛文尼亚语、西班牙语、瑞典语、泰越语、塔吉克语、泰米尔语、泰卢固语、泰语、藏语、土耳其语、通用多八位编码字符集、乌克兰语、越南语、威尔士语、视窗 1255 编码。
在图形化显示界面中,要显示所选语言环境对应的文字体系,需配备适配的字体,字体的配置细节参见「字体集」章节。
与系统区域设置的关联
部分操作系统可通过设置环境变量 LC_ALL 、 LC_CTYPE 或 LANG 指定使用的字符集区域设置(若多个变量均被设置,以首个非空变量的配置为准)。Emacs 启动时,会在系统区域设置别名表中查找当前字符集区域设置的名称,将其标准名称与变量 locale-charset-language-names 和 locale-language-names 的配置项匹配(前者优先级高于后者);若匹配成功,会自动选择对应的语言环境,同时还会根据该区域设置,按需调整显示表、终端编码体系、区域设置编码体系、首选编码体系, 以及键盘发送的非 ASCII 字符的解析方式 (这一点尤为重要)。
若在 Emacs 运行过程中修改了 LC_ALL 、 LC_CTYPE 或 LANG 环境变量(可通过 M-x setenv 操作),可执行 set-locale-environment 命令,根据新的区域设置重新调整语言环境。
set-locale-environment 函数通常会使用语言环境指定的首选编码体系解析系统消息;但如果当前区域设置与变量 locale-preferred-coding-systems 中的配置项匹配,Emacs 会改用对应的编码体系。例如,若区域设置 ja_JP.PCK 与 locale-preferred-coding-systems 中的 japanese-shift-jis 匹配,即便默认编码为 UTF-8,Emacs 也会使用该编码。
你可通过显式执行 set-language-environment 命令,或在初始化文件中自定义 current-language-environment ,覆盖 Emacs 启动时自动选择的语言环境。
查看语言环境信息
要查看某一语言环境 lang-env 的生效配置,使用命令 C-h L = lang-env= RET (describe-language-environment) 即可。该命令会说明该语言环境适用的语言,列出对应的字符集、编码体系和输入方法,还会展示示例文本以演示其支持的文字体系;若输入空值作为 lang-env ,则会描述当前已选中的语言环境。
自定义语言环境
可通过常规钩子 set-language-environment-hook 自定义任意语言环境, set-language-environment 命令在完成新语言环境的配置后,会执行该钩子。钩子函数可通过检查变量 current-language-environment 判断当前的具体语言环境,针对特定语言环境的非默认配置(如键盘输入和终端输出的编码体系、默认输入方法等),都应在该钩子中设置。
set-language-environment 命令在开始配置新语言环境前,会先执行钩子 exit-language-environment-hook ,该钩子可用于撤销通过 set-language-environment-hook 完成的自定义配置。例如,若你通过 set-language-environment-hook 为某一特定语言环境设置了特殊的按键绑定,就需要在 exit-language-environment-hook 中恢复该按键的默认绑定。
24.3. 输入方法
input method 输入方法 是专为交互式输入设计的一类字符转换方式。本节介绍 Emacs 自带的输入方法;若需了解底层操作系统提供的原生输入方法,参见「单字节编辑模式」章节。
在 Emacs 中,通常一种语言对应一种专属输入方法;部分使用相同字符的语言可共用一个输入方法,也有少数语言支持多种输入方法。
输入方法的核心实现方式
- 简单映射:将 ASCII 字母映射为另一套字母体系,替代 ASCII 字符的输入,希腊语、俄语输入方法均采用此方式。
- 字符合成:将多个字符的序列转换为单个字符,是更常用的高级方式。许多欧洲语言的输入方法通过该方式,将「字母 + 重音符号」(或反之)的序列转换为单个带重音的非 ASCII 字母(例如部分方法可将
o ^合成为单个带抑扬符的 o)。这类输入方法无专属命令,仅完成可打印字符序列的合成。 - 映射 + 合成:音节文字体系的输入方法通常采用此组合方式,泰语、韩语输入方法均是如此。先将按键映射为特定发音或声调符号,再将构成完整音节的符号序列映射为单个音节字符。
中日文专属输入方法
中文输入方法
中文输入方法需先输入汉字的拼音(如 chinese-py 拼音输入法),或字符的拆分部件(如 chinese-4corner 四角码、 chinese-sw 等)。一条输入序列通常对应多个候选汉字,需通过 C-f 、 C-b 、 C-n 、 C-p (或方向键)及数字键选择目标字符,这类按键在候选选择阶段会被赋予特殊含义。
候选汉字在逻辑上分为多行展示,每行最多显示 10 个候选。Emacs 通常在回显区一次仅显示一行,行首会标注 (i/j),代表当前为第 i 行,共 j 行:
- 按
C-n/C-p可上下切换候选行; - 按
C-f/C-b可在当前行中前后切换候选字符,选中的候选会以特殊颜色高亮,按C-SPC可选定该候选并插入到缓冲区; - 候选字符旁会标注数字序号,直接按对应数字键可快速选定当前行的该候选。
在中文输入方法中按 TAB 键,会弹出一个独立缓冲区展示所有候选字符,点击 mouse-2 鼠标中键 可选定对应候选;此时 C-f、C-b、C-n、C-p 及数字键仍可正常使用,只是高亮效果会在候选缓冲区中显示,而非回显区。
若需按拼音声调输入,可使用 chinese-sisheng 四声输入法,该方法基于字符合成实现,例如输入 pi1 可得到带一声调的「pī」。
日文输入方法
日文输入方法需先通过拼音输入完整的单词,待单词字符进入缓冲区后,Emacs 会调用大型词典将其转换为一个或多个日文汉字 / 假名。一个拼音拼写通常对应多个日文单词,按 C-n / C-p 可循环切换候选词完成选择。
终止字符合成的方法
有时需要终止输入方法的字符合成处理,避免已输入的字符与后续字符组合(例如在 latin-1-postfix 输入方法中, o ^ 会自动合成带重音的 'o' ,若需单独输入 'o' 和 '^' ,可通过以下方式实现):
- 重复输入符号:将重音符号输入两次,是输入独立字母和符号的专属技巧,例如输入
o ^ ^可得到两个独立字符o^; - 插入无关字符再删除:在字母后输入一个无法与其合成的字符,再立即删除,例如输入
o o DEL ^可得到独立的o和^; - 通用快捷键:在两个字符之间按
C-\ C-\,可强制终止合成,该方式通用性最强,只是操作稍繁琐;该操作是连续两次执行C-\(toggle-input-method)。详见《选择输入方法》章节。 - 增量搜索中使用:
C-\ C-\在增量搜索中尤为实用,可终止输入方法的等待合成状态,直接基于已输入的字符开始搜索。
输入方法的辅助功能
- 查询字符输入方式:按
C-u C-x =,可查看当前输入方法下,光标所在位置字符的具体输入方式(参见「光标位置信息」章节)。 - 输入过程可视化配置:两个变量可控制输入方法的提示方式:
input-method-highlight-flag:非空时,缓冲区中会高亮显示未完成的合成字符序列(多数输入方法支持,少数会禁用此功能);input-method-verbose-flag:非空时,回显区会显示下一个可输入的候选字符列表(迷你缓冲区中除外)。
- 自定义输入方法:可将自定义函数添加到钩子变量
quail-activate-hook,修改输入方法的工作方式(参见「钩子」章节)。例如通过quail-translation-keymap函数获取输入方法的键映射表,再使用define-key重新定义部分按键的绑定(参见「在初始化文件中重新绑定按键」章节)。 - 只读缓冲区的输入方法抑制:当缓冲区文本因某种原因设为只读时,输入方法会自动禁用。此举可确保在
read-only-mode只读模式、image-mode 图片模式等将缓冲区(或部分区域)设为只读的模式中,单字符按键绑定能正常生效,即便输入方法处于激活状态。
其他字符输入方式
- 按 Unicode 输入任意字符:若需输入键盘上无对应按键的字符,可使用
C-x 8 RET(insert-char) ,通过字符的 Unicode 名称或编码点插入单个字符(参见「插入文本」章节)。 - Emoji 专属输入命令:Emacs 为 Emoji 字符提供了专属输入快捷键,所有相关命令均在
C-x 8 e键映射表中:C-x 8 e e(emoji-insert) :可浏览不同分类的 Emoji,选择后插入;C-x 8 e l(emoji-list) :弹出新缓冲区列出所有 Emoji,点击或按回车可将选中的 Emoji 插入当前缓冲区;C-x 8 e s(emoji-search) :根据名称搜索 Emoji 并插入。😘
- Emoji 信息查询:
describe-char命令可显示光标所在位置字符 / 字形的详细信息(包括 Emoji);若仅需快速查询字符名称,可使用C-x 8 e d(emoji-describe) 命令,该命令主要用于区分外观相似的 Emoji 变体,也可查询非 Emoji 字符的名称。
24.4. 选择输入方法
C-\- 启用或关闭已选中的输入方法 (
toggle-input-method) 。 C-x RET C-\ 输入法名 RET- 为当前缓冲区选择新的输入方法 (
set-input-method) 。 C-x \ 输入法名 RET- 临时启用选定的瞬时输入方法;插入单个字符后,该输入法会自动关闭 (
activate-transient-input-method) 。 C-h I 输入法名 RETC-h C-\ 输入法名 RET- 描述指定的输入方法 (
describe-input-method) 。默认情况下,该命令会描述当前启用的输入方法(若存在),描述内容会详细说明该输入法的完整使用方法。 M-x list-input-methods- 列出所有受支持的输入方法。
为当前缓冲区选择输入方法可使用 C-x RET C-\ (set-input-method) ,该命令会从迷你缓冲区读取输入法名称,名称通常以其适用的语言环境开头。变量 current-input-method 会记录当前选中的输入方法。
输入方法会通过各类 ASCII 字符序列来表示非 ASCII 字符,有时需要临时关闭输入方法,按下 C-\ (toggle-input-method) 即可;再次按下该快捷键,可重新启用输入方法。
若 首次 按下 C-\ 时尚未选择任何输入方法,Emacs 会提示你指定一个,该操作与使用 C-x RET C-\ 指定输入法的效果一致。
带数字参数执行该命令时(如 C-u C-\ ), toggle-input-method 总会提示你选择输入方法,并将最近一次选中的输入法作为默认选项推荐。
选择语言环境时,会为各缓冲区指定一个默认输入方法。若存在默认输入方法,按下 C-\ 即可在当前缓冲区启用它。变量 default-input-method 用于指定默认输入方法(值为 nil 表示无默认输入法)。
部分语言环境支持多种输入方法,若你想使用与 set-language-environment 命令默认选择不同的输入法,可通过 set-language-environment-hook 钩子让 Emacs 为特定语言环境选择自定义的默认输入方法(参见set-language-environment-hook相关说明)。示例如下:
(defun my-chinese-setup () "Set up my private Chinese environment." (if (equal current-language-environment "Chinese-GB") (setq default-input-method "chinese-tonepy"))) (add-hook 'set-language-environment-hook 'my-chinese-setup)
上述代码的作用是:当你选择「Chinese-GB(中文 - 国标码)」语言环境时,将默认输入方法设为带声调的拼音输入法 chinese-tonepy 。
你也可让 Emacs 自动激活指定的输入方法,示例如下:
(add-hook 'text-mode-hook (lambda () (set-input-method "german-prefix")))
该代码会在文本模式(Text mode)下,自动激活德语前缀输入法german-prefix。
部分字母文字的输入方法,本质是通过重新映射键盘,模拟该文字体系常用的各类键盘布局。键盘的正确映射方式取决于你的实际键盘布局,可使用命令 M-x quail-set-keyboard-layout 指定当前的键盘布局。
使用 M-x quail-show-key 命令,可查看在选定的键盘布局下,输入光标后该字符所需按下的按键(或按键序列)。 C-u C-x = 命令除了显示该字符的其他相关信息外,也会展示这一输入方式。
M-x list-input-methods 会列出所有受支持的输入方法,该列表会展示每种输入法的相关信息,包括其在 mode line模式行 中对应的显示标识。
有时需要临时启用输入方法仅插入单个字符,这种场景下使用瞬时输入方法会更为便捷。按下 C-x \ (activate-transient-input-method) 可临时启用输入方法,按该输入法规则插入单个字符后,输入法会自动关闭。若尚未选定瞬时输入方法, C-x \ 会提示你指定一个;后续再次执行该命令,会直接启用已选定的瞬时输入方法。若要更换瞬时输入方法,可按下 C-u C-x \ ,你选定的瞬时输入方法可与通过 C-u C-\ 选择的常规输入方法不同。
24.5. 编码系统
不同语言的使用者已制定出多种标准化程度各异的编码系统,用于表示各自的语言字符。Emacs 内部并不直接使用这些编码系统,而是在 读取数据 时将各类编码系统转换为自身的内部编码,在 写入数据 时再将内部编码转换为其他编码系统。该转换功能可应用于文件的读写、终端的数据收发,以及与子进程间的数据交换场景。
Emacs 为每种编码系统分配了专属名称。多数编码系统仅适用于单一语言,其名称以对应语言名开头;部分编码系统可支持多种语言,这类编码系统的名称通常以 'iso' 开头。此外还有一些特殊编码系统,例如 no-conversion (无转换)、 raw-text (原始文本)和 emacs-internal (Emacs 内部编码)。
有一类特殊的编码系统被统称为 代码页 (codepages),专为兼容微软视窗(MS-Windows)和微软磁盘操作系统(MS-DOS)软件的文本编码而设计。这类编码系统的名称格式为 cpnnnn ,其中 nnnn 为 3 位或 4 位的代码页编号。你可像使用其他编码系统一样使用这类编码,例如,要打开以代码页 850 编码的文件,可键入快捷键: C-x RET c cp850 RET C-x C-f 文件名 RET 。
编码系统除了能对非 ASCII 字符的各类表示形式进行转换外,还可执行 行尾转换 。Emacs 支持处理文件中行分隔符的三种主流规范:换行符(Newline,类 Unix 系统)、回车符后接换行符(Carriage Return + Linefeed,DOS 系统),以及仅使用回车符(Carriage Return,传统 Mac 系统)。
相关操作命令
C-h C 编码系统名 RET- 描述指定编码系统的详细信息 (
describe-coding-system) 。 C-h C RET- 描述当前正在使用的所有编码系统 (
describe-coding-system) 。 M-x list-coding-systems- 显示 Emacs 支持的所有编码系统列表。
命令 C-h C (describe-coding-system) 可展示特定编码系统的相关信息,包括该编码系统指定的行尾转换规则。执行该命令时,你可传入编码系统名作为参数;若留空参数,该命令会描述当前缓冲区及系统默认中,为各类用途选定的编码系统,同时还会展示编码系统的识别优先级列表(参见《编码系统的识别》章节)。
键入 M-x list-coding-systems 可查看 Emacs 支持的全部编码系统列表,该列表会展示每种编码系统的相关信息,包括其在模式行中对应的标识字符(参见《模式行》章节)。
此列表中的所有编码系统( 无转换编码no-conversion除外 ,该编码表示不执行任何形式的转换),均会明确可打印字符的转换方式与是否转换,但行尾转换的具体规则会根据每个文件的内容自动判定。例如,若检测到文件使用回车符 + 换行符作为行分隔符,Emacs 会自动采用 DOS 系统的行尾转换规则。
列表中的每种编码系统都包含三种 变体 ,用于明确指定行尾转换的具体方式:
…-unix- 不执行任何行尾转换,假定文件使用换行符作为行分隔符(该规范为类 Unix 系统、GNU 系统及 macOS 系统的默认规范)。
…-dos- 假定文件使用回车符 + 换行符作为行分隔符,并执行对应的行尾转换(该规范为微软系统的默认规范 9)。
…-mac- 假定文件仅使用回车符作为行分隔符,并执行对应的行尾转换(该规范为经典 Mac OS 系统的默认规范,目前仅在部分遗留软件中使用)。
为简化显示, list-coding-systems 命令的输出结果中会省略上述变体编码系统,因其命名规则完全可推导。例如,编码系统 iso-latin-1 包含 iso-latin-1-unix 、 iso-latin-1-dos 和 iso-latin-1-mac 三种变体。
编码系统unix、dos和mac分别是 undecided-unix 、 undecided-dos 和 undecided-mac 的别名。这类编码系统 仅指定行尾转换规则 ,字符编码的转换方式则由文本内容自行推导。
原始文本编码raw-text 适用于以 ASCII 文本为主、但可能包含值大于 127 的字节(且这些字节并非用于编码非 ASCII 字符)的文件。使用该编码时,Emacs 会原样复制这些字节值,并将当前缓冲区的变量 enable-multibyte-characters 设为 nil ,以保证这些字节被正确解析。 raw-text 会根据检测到的数据,以常规方式处理行尾转换,同时也包含上述三种标准变体,用于指定行尾转换的具体类型。
与之相对,无转换编码 no-conversion 表示不执行任何字符编码转换 —— 既不转换非 ASCII 字节值,也不执行行尾转换。该编码适用于读写二进制文件、tar 归档文件及其他需要逐字原样解析的文件,同时它也会将变量 enable-multibyte-characters 设为 nil 。
以 无任何转换 的方式编辑文件的最简方法,是使用 M-x find-file-literally 命令。该命令会采用no-conversion编码,同时还会禁用 Emacs 中其他可能在你查看文件前修改其内容的功能(参见《打开文件》章节)。
Emacs 内部编码 emacs-internal (与其等效的 utf-8-emacs 同理),表示文件中的非 ASCII 字符以 Emacs 的内部编码格式存储。该编码系统会根据检测到的数据处理行尾转换,同时也包含上述三种标准变体,用于指定行尾转换的具体类型。
24.6. 编码系统识别
Emacs 在读取任意文本内容时,都会尝试识别其应使用的编码系统,该过程适用于读取文件、子进程输出、X 窗口系统选择的文本等各类场景。 只要你设定好偏好配置 ,Emacs 大多时候能自动选中正确的编码系统。
部分编码系统可通过数据中出现的字节序列来识别或区分,但也有一些编码系统,即便在理论上也无法相互区分。例如,拉丁1(Latin-1)和拉丁2(Latin-2)编码就无法区分 —— 二者使用相同的字节值,仅代表的字符含义不同。
Emacs 通过 编码系统优先级列表 来处理上述情况。当你未指定文件的使用编码时,Emacs 读取文件会依次将数据与优先级列表中的编码系统进行匹配,从列表首位开始逐一向下检测,直至找到与数据匹配的编码系统,随后便会假定文件内容以该编码系统存储并完成转换。
编码系统的优先级列表由 选定的语言环境 决定(参见《语言环境》章节)。例如,若你使用法语,大概率希望 Emacs 优先使用拉丁 1 而非拉丁 2;若使用捷克语,则大概率希望优先使用拉丁 2。这也是指定语言环境的原因之一。
你也可通过 M-x prefer-coding-system 命令,对编码系统优先级列表进行精细调整。该命令会从迷你缓冲区读取编码系统名称,并将其添加至优先级列表的头部,使其优先级高于所有其他编码。多次执行该命令时,每次都会在列表头部新增一个编码系统。
若你使用的编码系统指定了行尾转换类型(如 iso-8859-1-dos ),其含义为:Emacs 会优先尝试识别 iso-8859-1 编码,且在识别出该编码时,使用 DOS 格式的行尾转换规则。
有时 文件名 也可指示文件应使用的编码系统,变量 file-coding-system-alist 便定义了这种对应关系。Emacs 提供了专用函数 modify-coding-system-alist ,用于向该列表中添加配置项。例如,要将所有 '.txt' 文件的读写编码设为 chinese-iso-8bit ,可执行以下 Lisp 表达式:
(modify-coding-system-alist 'file "\\.txt\\'" 'chinese-iso-8bit)
该函数的第一个参数固定为 file ,第二个参数为正则表达式,用于匹配该配置适用的文件,第三个参数则为这些文件要使用的编码系统。
Emacs 会根据 文件内容 识别应使用的行尾转换类型:若检测到文件仅使用回车符,或仅使用回车符加换行符的组合作为行分隔符,便会相应选择对应的行尾转换规则。你可将变量 inhibit-eol-conversion 设为非nil值,禁用行尾转换的自动识别功能。禁用后,DOS 格式的文件在缓冲区中会显示可见的 '^M' 字符;相较于模式行左侧边缘较为隐晦的 '(DOS)' 行尾类型标识(参见《行尾助记符》章节),部分用户更偏好这种显示方式。
默认情况下,编码系统的自动检测会 对转义序列敏感 。若 Emacs 检测到以转义字符开头的字符序列,且该序列符合 ISO-2022 编码的规范,便会使用某一种 ISO-2022 编码对文件进行解码。
但在某些场景下,你可能希望 原样读取 文件中的转义序列,此时可将变量 inhibit-iso-escape-detection 设为非nil值。开启该设置后,编码检测会忽略所有转义序列,且绝不会使用 ISO-2022 编码,最终所有转义序列都会在缓冲区中以可见形式显示。
inhibit-iso-escape-detection 的默认值为nil。建议你 不要永久修改 该变量,仅在执行特定操作时临时调整即可。原因在于,Emacs 发行版中的部分 Emacs Lisp 源文件,其非 ASCII 字符采用 iso-2022-7bit 编码存储;若禁用转义序列检测,打开这些文件时将无法正确解码。
变量 auto-coding-alist 和 auto-coding-regexp-alist 是指定编码系统的最高优先级方式:前者针对特定文件名模式,后者针对包含特定内容模式的文件。这两个变量的配置 甚至会覆盖文件自身 的
-*-coding:-*-
标签(参见《指定文件的编码系统》章节)。例如,Emacs 会将 auto-coding-alist 应用于 tar 归档文件,避免因归档内某个文件包含的 '-*-coding:-*-' 标签,导致 Emacs 误判并将该编码应用到整个归档文件上。
另一种指定编码系统的方式是使用变量 auto-coding-functions 。例如,Emacs 内置的其中一个自动编码函数可检测 XML 文件的编码。与上述两个变量不同,该变量 不会覆盖 任何 -*-coding:-*- 标签。
24.7. 指定文件的编码系统
若 Emacs 对文件编码识别有误,你可使用快捷键 C-x RET r (revert-buffer-with-coding-system) ,选用正确的编码系统重新读取该文件。该命令会提示你输入要使用的编码系统。若要查看 Emacs 实际用于解码该文件的编码系统,可查看 mode line模式行 左侧的编码系统助记字符(参见《模式行》章节),或键入 C-h C (describe-coding-system) 查询。
你可直接在文件内部为特定文件指定编码系统,方式有两种:
- 一是在文件开头使用 '
-*-…-*-' 格式的标识, - 二是在文件末尾添加本地变量列表(参见《文件中的本地变量》章节)。
具体操作是为名为 coding 的「variable」定义取值,实际上 Emacs 并不存在真正的 coding 变量,该方式并非设置变量,而是为当前文件指定对应的编码系统。例如,标识 -*-mode: C; coding: latin-1; -*- 既指定了使用 Latin-1 编码系统,也将文件的主模式设为 C 模式。当你在文件中显式指定编码后,该设置会覆盖 file-coding-system-alist 变量中的对应配置。
24.8. 为输出选择编码系统
Emacs 为某个缓冲区选定编码系统后,会将该编码系统存储在变量 buffer-file-coding-system 中。该编码系统会成为从当前缓冲区向文件写入内容相关操作的默认编码,如 save-buffer (保存缓冲区)和 write-region (写入区域)命令。你可通过 set-buffer-file-coding-system 命令,为该缓冲区后续的文件输出操作指定另一编码系统(参见《为文件文本指定编码系统》章节)。
你可在任意 Emacs 缓冲区中插入 Emacs 支持的所有字符,但多数编码系统仅能处理其中的一部分字符。因此,你插入的字符有可能无法用保存该缓冲区时使用的编码系统进行编码。例如,你打开了一个以 iso-8859-2 编码的波兰语文本文件,并在其中添加了一些俄语词汇,保存该缓冲区时,Emacs 将无法使用 buffer-file-coding-system 的当前值进行编码,因为你添加的字符无法被该编码系统解析。
出现上述情况时,Emacs 会尝试使用 优先级最高的编码系统 (由 M-x prefer-coding-system 或 M-x set-language-environment 命令设置)。若该编码系统能对缓冲区中的所有字符完成安全编码,Emacs 会采用此编码,并将其值存入 buffer-file-coding-system ;若不能,Emacs 会展示所有适用于编码该缓冲区内容的编码系统列表,让你从中选择其一。
若你在邮件中插入了无法被当前编码适配的字符,Emacs 的处理方式会略有不同。它会额外检查该优先级最高的编码系统是否推荐用于 MIME 邮件;若不推荐,Emacs 会将这一情况告知你,并提示你选择另一编码系统。这样做是为了避免你无意间发送了采用收件人邮件软件难以解码的编码方式的邮件。(若你在提示时输入对应编码系统名称,仍可使用该不适配的编码。)
当你发送邮件时(参见《发送邮件》章节),Emacs 会通过四种不同方式确定用于编码邮件文本的编码系统,优先级依次为:首先,若 buffer-file-coding-system 的缓冲区自有值非nil,则使用该值;其次,若 sendmail-coding-system 的值非nil,则使用该值;第三,使用 default-sendmail-coding-system 的值。若上述三个值均为 nil ,Emacs 会使用新文件的默认编码系统(即 buffer-file-coding-system 的默认值)对发出的邮件进行编码,而该默认编码系统由你选择的语言环境决定。
24.9. 为文件文本指定编码系统
当 Emacs 未能为文件内容自动选择正确的编码系统时,你可以使用以下命令手动指定:
C-x RET f 编码系统 RET- 使用指定的编码系统保存或重新读取当前缓冲区中的文件 (
set-buffer-file-coding-system) 。 C-x RET c coding RET- 为紧随其后执行的命令指定编码系统 (
universal-coding-system-argument) 。 C-x RET r coding RET- 使用指定的编码系统重新读取当前文件 (
revert-buffer-with-coding-system) 。 M-x recode-region RET 正确编码 RET 错误编码 RET- 转换缓冲区中指定区域的编码 —— 该区域此前以错误编码完成了解码,重新用正确编码对其解码。
命令 C-x RET f (set-buffer-file-coding-system) 用于为当前缓冲区设置 文件编码系统 (即保存或重新读取文件时使用的编码系统),你需要在迷你缓冲区中输入指定的编码系统名称。你也可以通过在模式行的编码系统标识处点击鼠标右键( mouse-3 )来调用该命令(参见《模式行》章节)。
若你指定的编码系统无法处理缓冲区中的所有字符,当你尝试保存缓冲区时,Emacs 会就这些无法处理的字符发出警告,并让你重新选择其他编码系统(参见《为输出选择编码系统》章节)。
你也可通过该命令为当前缓冲区的编码指定 行尾转换规则 (参见行尾转换)。例如,执行 C-x RET f dos RET ,Emacs 会将当前缓冲区的文本以 DOS 格式保存,行尾使用回车符加换行符的组合。
为文件指定编码系统的另一种方式,是在 打开文件时 进行设置。先执行命令 C-x RET c (universal-coding-system-argument) ,该命令会在迷你缓冲区中读取你输入的编码系统名称;退出迷你缓冲区后,这个指定的编码系统就会应用于紧随其后执行的那条命令。
例如,若紧随其后的命令是 C-x C-f (打开文件),Emacs 会使用该编码系统读取文件(并记录该编码系统,供后续保存文件时使用);若紧随其后的命令是 C-x C-w (另存为),则会使用该编码系统写入文件。以这种方式指定保存用的编码系统,而非通过 C-x RET f 命令设置时,即便缓冲区包含该编码系统无法处理的字符,Emacs 也不会发出警告。
受指定编码系统影响的其他文件操作命令包括 C-x i=(插入文件)、 =C-x C-v (重新访问文件),以及 C-x C-f 的跨窗口变体命令。 C-x RET c 命令也会作用于启动子进程的各类命令,包括 M-x shell (参见《从 Emacs 中运行 Shell 命令》章节)。若紧随其后的命令并不使用编码系统,那么 C-x RET c 命令最终将不会产生任何效果。
以 无任何转换 的方式打开文件的简便方法,是使用 M-x find-file-literally 命令(参见《打开文件》章节)。
变量 buffer-file-coding-system 的默认值,指定了创建新文件时使用的编码系统。该值适用于新建文件的场景,也适用于先创建缓冲区再将其保存为文件的场景。选择语言环境时,Emacs 通常会将该变量设为适合该语言环境的默认编码系统。
若你使用错误的编码系统打开了文件,可通过 C-x RET r (revert-buffer-with-coding-system) 命令修正。该命令会让你指定一个编码系统,并用其重新读取当前文件。
若某段文本已通过错误的编码系统插入到缓冲区中,你可使用 M-x recode-region 命令重新解码。该命令会先提示你输入正确的编码系统,再提示你输入此前实际使用的错误编码系统,随后完成编码转换 —— 它会先使用错误编码将该区域的内容编码,再使用正确编码对其重新解码。
24.10. 进程间通信的编码系统
本节介绍如何为与其他进程的通信操作指定编码系统。
C-x RET x coding RET- 使用指定编码系统在 Emacs 与其他图形化应用之间传输选中的文本 (
set-selection-coding-system) 。 C-x RET X coding RET- 使用指定编码系统传输下一次选中的文本,实现与其他图形化应用间的单向或双向传输 (
set-next-selection-coding-system) 。 C-x RET p input-coding RET out-coding RET- 为当前缓冲区中与子进程的输入、输出操作分别指定输入编码和输出编码 (
set-buffer-process-coding-system) 。
命令 C-x RET x (set-selection-coding-system) 用于指定编码系统,该编码将应用于 Emacs 向其他窗口应用发送选中文本 ,以及 从其他应用接收选中的文本 这两种场景。该命令的设置会作用于后续所有的文本选中传输操作,直至再次执行该命令覆盖原有设置。命令 C-x RET X (set-next-selection-coding-system) 则仅为 Emacs 中接下来的一次选中文本操作 ,或 Emacs 读取的下一次外部选中文本操作 指定编码系统。
变量 x-select-request-type 用于指定从 X 窗口系统中接收其他应用选中文本时,请求获取的数据类型。若该变量值为 nil (默认值),Emacs 会按顺序尝试 UTF8_STRING 和 COMPOUND_TEXT 两种类型,并通过多种启发式规则从两个返回结果中选择更合适的一种;若这两种类型均尝试失败,Emacs 会回退使用 STRING 类型。若 x-select-request-type 的值为 COMPOUND_TEXT 、 UTF8_STRING 、 STRING 或 TEXT 中的任一符号,Emacs 将仅使用该指定的请求类型。若该变量值为上述部分符号组成的列表,Emacs 会按列表顺序依次尝试其中的请求类型,直至某一类型尝试成功,或遍历完整个列表为止。
命令 C-x RET p (set-buffer-process-coding-system) 为与子进程的输入、输出操作指定编码系统,该命令的设置仅作用于当 前缓冲区 。通常每个子进程都有其对应的专属缓冲区,因此可在对应子进程的缓冲区中执行该命令,为与该特定子进程的双向数据转换指定编码系统。
你也可在执行启动子进程的命令前,先执行 C-x RET c (universal-coding-system-argument) 命令,为与该子进程的通信操作指定编码系统,具体用法参见《为文件文本指定编码系统》章节。
与子进程间输入、输出数据转换使用的默认编码系统,由 当前的语言环境 决定。
变量 locale-coding-system 用于指定编码系统,该编码将应用于系统字符串的编码和解码操作,例如系统错误信息、 format-time-string 函数的格式串及时间戳的编解码。在 X 窗口系统中,该编码系统也可能被用于解码非 ASCII 的键盘输入;在批处理模式下,该编码还会用于对发送至标准输出流和标准错误流的文本进行编码。你应选择与 底层系统的文本表示方式 相兼容的编码系统,而系统的文本表示方式通常由环境变量 LC_ALL 、 LC_CTYPE 和 LANG 中的一个决定(按上述排列顺序,第一个值非空的环境变量将作为文本表示方式的判定依据)。
24.11. 文件名的编码系统
C-x RET F coding RET- 使用指定的编码系统对文件名进行编码和解码 (
set-file-name-coding-system) 。
命令 C-x RET F (set-file-name-coding-system) 用于指定专门对文件名进行编码的编码系统,该设置对文件内容的读写操作无任何影响。
实际上,该命令的作用仅为修改变量 file-name-coding-system 的值。若将该变量设为某一编码系统名称(可为 Lisp 符号或字符串格式),Emacs 会在所有文件操作中,使用该编码系统对文件名进行编码。这一设置让文件名中可以包含非 ASCII 字符 —— 至少支持该指定编码系统能编码的所有非 ASCII 字符。
若 file-name-coding-system 的值为 nil ,Emacs 会使用由选定语言环境决定的默认编码系统,该默认编码存储在变量 default-file-name-coding-system 中(默认值通常为 UTF-8 )。
当 Emacs 运行在基于 NT 内核的微软视窗系统版本中(包括 Windows 2000、XP 及所有后续版本), file-name-coding-system 的值基本会被忽略,因为 Emacs 默认会调用相关应用程序接口(API),直接传递 Unicode 格式的文件名。与之相反,在 Windows 9X 系统中,文件名会通过 file-name-coding-system 进行编码,该变量应被设为与当前系统区域设置对应的代码页(参见代码页相关内容)。变量 w32-unicode-filenames 用于控制 Emacs 调用接收文件名的系统函数时,是否使用 Unicode 应用程序接口:Emacs 的启动代码会在 Windows 9X 系统中将该变量设为 nil ,在更高版本的微软视窗系统中则设为 t 。
警告 :若在 Emacs 会话过程中修改 file-name-coding-system 的值(或更改语言环境),而你此前已打开过部分文件,这些文件的名称是通过旧编码系统编码的,且在新编码系统下无法编码(或编码方式不同),就可能引发问题。若你尝试以原文件名保存这类缓冲区的内容,可能会使用错误的文件名,或直接触发保存错误。若出现此类问题,可使用 C-x C-w 命令为该缓冲区指定新的文件名。
若对文件名进行编码时发生错误,可使用 M-x recode-file-name 命令修改文件名的编码系统。执行该命令时,Emacs 会依次提示你输入目标现有文件名、该文件名原有的编码系统,以及你希望转换到的目标编码系统。
24.12. X 键盘输入的编码系统
X 窗口系统下的输入法会指定专属的编码系统,这类编码系统是解码键盘输入所必需的。默认情况下,Emacs 在与输入法服务器建立连接后,会自动为每种输入法确定对应的解码编码系统,并使用该专属编码系统对键盘输入进行解码。但这种自动判定操作有时可能失败,出现该情况时,Emacs 会改用区域设置编码系统进行解码(参见《进程间通信的编码系统》章节)。
若输入法未正确声明其用于编码文本的编码系统,就需要手动指定 Emacs 对该输入法的输入文本进行解码时所用的编码系统。将变量 x-input-coding-system 的值设为某一编码系统符号后,Emacs 会无条件使用该编码系统,对所有来自输入法的键盘输入进行解码。
24.13. 终端 I/O 的编码系统
C-x RET t coding RET- 使用指定编码系统处理终端输出 (
set-terminal-coding-system) 。 C-x RET k coding RET- 使用指定编码系统处理键盘输入 (
set-keyboard-coding-system) 。
命令 C-x RET t (set-terminal-coding-system) 用于指定 终端输出 的编码系统。若为终端输出指定了字符编码,所有输出到终端的字符都会转换为该编码系统格式。
该功能适用于专为支持特定语言或字符集设计的纯字符终端 —— 例如,支持某一种 ISO 拉丁字符集的欧洲终端。在使用多字节文本时,你需要指定终端编码系统,让 Emacs 知晓该终端实际能处理哪些字符。
默认情况下,终端输出不会进行任何编码转换,除非 Emacs 能从你的终端类型或区域设置中推导出合适的编码系统(参见《语言环境》章节)。
命令 C-x RET k (set-keyboard-coding-system) 或变量 keyboard-coding-system ,用于指定 键盘输入 的编码系统。对于部分会发送非 ASCII 图形字符的终端,键盘输入的字符编码转换功能十分实用 —— 例如,部分为 ISO Latin-1 字符集或其子集设计的终端。
默认情况下,键盘输入会根据系统的区域设置进行编码转换。若你的终端实际并不支持区域设置所对应的编码(例如,按下 M-i 时终端插入了非 ASCII 字符),你需要将 keyboard-coding-system 设为 nil 来关闭编码转换。你可在初始化文件中添加以下代码实现该设置:
(set-keyboard-coding-system nil)
在微软视窗系统中,设置 keyboard-coding-system 无任何效果;仅在老旧的 Windows 9X 系统中例外,此时该编码必须与微软视窗控制台的当前代码页匹配,而控制台代码页可通过调用 w32-set-console-codepage 函数修改。
为键盘输入设置编码系统转换,与使用输入法之间存在一定相似性:二者都会将一系列键盘输入转换为单个字符。但二者设计初衷不同, 输入法 是为了方便用户交互式操作,待转换的输入序列通常为 ASCII 可打印字符;而 编码系统 的转换对象,通常为非图形字符序列。
24.14. 字体集
一种字体通常仅为某一种字母体系或文字脚本定义字形。因此,要显示 Emacs 所支持的全范围文字脚本,就需要组合使用多种字体。在 Emacs 中,这样的字体组合被称为 字体集 。字体集由一系列字体规格定义而成,其中每一种字体规格被分配处理一个字符编码范围;对于其指定字体未覆盖的字符,该字体集会回退调用另一个字体集来处理。
每个字体集都和单种字体一样拥有专属名称。但不同的是,字体由系统存储,可用的字体名称也由系统定义,而 字体集是在 Emacs 内部自行定义 的。一旦完成某一字体集的定义,你便可在 Emacs 中通过指定其名称来使用它,所有可使用单种字体的场景均适用。当然,Emacs 字体集仅能使用你的系统所支持的字体。若部分字符在屏幕上显示为空白方框或十六进制编码,说明用于显示这些字符的字体集中,没有对应适配的字体。出现这种情况,或是字符虽能显示但显示效果不符合预期时,你可能需要安装额外的字体,或是修改该字体集,使其调用你系统中已安装的特定字体(详见下文)。你的操作系统可能会提供可选安装的字体,你也可以安装 GNU 国际字体包(GNU Intlfonts),该字体包包含了 Emacs 所支持的绝大多数文字脚本对应的字体 10。
Emacs 会自动创建三种字体集:standard fontset标准字体集、 startup启动字体集和 default默认字体集。 默认字体集 最有可能包含适配各类非 ASCII 字符的字体,它是另外两种字体集的默认回退字体集;当你设置的是默认字体而非字体集时,该字体集也会作为默认回退选项。但默认字体集并未指定字体族名称,因此若直接使用,显示效果可能会存在一定的随机性。你可在启动 Emacs 时使用 '-fn' 选项指定特定的字体集,例如:
emacs -fn fontset-standard
你也可通过 X 资源中的 'Font' 项指定字体集(参见《X 选项与资源》章节)。
若未指定要使用的字体集,Emacs 会使用一款 ASCII 字体,对于该字体未覆盖的字符,则会以 'fontset-default' (默认字体集)作为回退。 标准字体集 尽管名称如此,却仅在被显式调用时才会生效。
要查看特定字体集的相关信息,可使用 M-x describe-fontset 命令。该命令会提示你输入字体集名称,默认值为当前框架正在使用的字体集;执行后会展示该字体集中的所有字符子范围,以及分配给各范围的对应字体。若要查看在未指定字体集的情况下(常规启动的默认情况),Emacs 在当前会话中使用的字体信息,可在命令提示时输入 fontset-default 并回车,或直接回车,即可查看当前框架所用字体集的详情。
一个字体集并非必须为每一个字符编码都指定对应字体。若某字体集未为某个字符指定字体,或是其指定的字体在你的系统中不存在,该字符就无法被正确显示,取而代之的会是该字符的十六进制编码、细空格或空白方框(详见《无字形字符的显示处理》章节)。此外,即便字体集为某一字符范围指定了字体,你也可能对其视觉显示效果不满意。出现上述这些情况时,你可以对字体集进行修改,具体方法参见《修改字体集》章节。
24.15. 定义字体集
在 X 窗口系统中运行时,Emacs 会根据 standard-fontset-spec 的取值自动创建一个标准字体集,该字体集的名称为:
-*-fixed-medium-r-normal-*-16-*-*-*-*-*-fontset-standard
可简称为 'fontset-standard' 。
在 GNUstep 和 macOS 系统中,标准字体集由 ns-standard-fontset-spec 的取值生成;在微软视窗系统(MS Windows)中,标准字体集则由 w32-standard-fontset-spec 的取值生成。
标准字体集的粗体、斜体、粗斜体变体也会被自动创建,其名称会将原名称中的 'medium' 替换为 'bold' ,或将 'r' 替换为 'i' ,也可同时替换两者。
若你通过 'Font' 资源、 '-fn' 命令行参数指定了默认的 ASCII 字体,或 Emacs 启动时自动识别到了默认字体,程序会基于该字体自动生成一个字体集,即 启动字体集 ,名称为 fontset-startup 。Emacs 生成该字体集的规则为:将字体名称中的 charset_registry (字符集注册名)字段替换为 'fontset' , charset_encoding (字符集编码名)字段替换为 'startup' ,再将生成的字符串作为字体集的指定标识。
例如,若你通过以下形式指定字体启动 Emacs:
emacs -fn "*courier-medium-r-normal--14-140-*-iso8859-1"
Emacs 会生成下述字体集,并将其应用于 X 窗口系统的初始框架:
-*-courier-medium-r-normal-*-14-140-*-*-*-*-fontset-startup
对于该字体所支持的所有字符,启动字体集会直接使用该指定字体(或注册表、编码不同的变体);对于其他字符,则会回退至 'fontset-default' (默认字体集)进行匹配。
通过 X 资源 'Emacs.Font' ,你可像指定实际字体名一样指定字体集名称。但注意 不要 在 'Emacs*Font' 这类通配符资源中指定字体集名称 —— 该通配符会匹配菜单等其他各类资源,而菜单组件无法识别并处理字体集。相关细节可参考《X 窗口系统的选项与资源》章节。
你可通过命名为 'Fontset-n' 的 X 资源指定额外的字体集(其中n为从 0 开始的整数),该资源的取值需遵循以下格式:
fontpattern, [charset:font]… 字体模式, [字符集:字体]…
其中, fontpattern字体模式 需符合标准 X 窗口系统的字体名格式(可参考前文启动字体集的示例),但最后两个字段除外,这两个字段需设为 'fontset-alias' 的形式。
每个字体集均有两个名称:长名称和短名称。长名称即上述的 字体模式 ,短名称为长名称的最后两个字段,即 'fontset-alias'(例如启动时自动创建的字体集,其短名称为 'fontset-startup' )。你可通过任意一个名称引用该字体集。
'charset:font' 格式用于指定(当前字体集中)某一特定字符集所使用的字体。其中, charset 为字符集名称, font 为该字符集对应的字体。在定义单个字体集时,可根据需要多次使用该格式。
对于其余未单独指定的字符集,Emacs 会依据字体模式( fontpattern )自动匹配字体:将模式中的 'fontset-alias' 替换为对应字符集的描述值。例如针对 ASCII 字符的字体, 'fontset-alias' 会被替换为 'ISO8859-1' 。
此外,当字体模式中出现多个连续的通配符时,Emacs 会将其合并为单个通配符,这一设计是为了避免使用 auto-scaled fonts自动缩放的字体。通过放大原有字体得到的缩放字体并不适用于文本编辑,而缩小字体也无实际意义 —— 直接使用小字体的原始尺寸效果会更好,Emacs 也会按此方式处理。
因此,若 fontpatter 字体模式为下述形式:
-*-fixed-medium-r-normal-*-24-*-*-*-*-*-fontset-24
则 ASCII 字符对应的字体指定规则为:
-*-fixed-medium-r-normal-*-24-*-ISO8859-1
而中文 GB2312 字符对应的字体指定规则为:
-*-fixed-medium-r-normal-*-24-*-gb2312*-*
你的系统中可能没有匹配上述字体指定规则的中文字体。大多数 X 窗口系统发行版所包含的中文字体,其字体族字段均为「宋体(song ti)」或「仿宋(fangsong ti)」。这种情况下,可按如下方式指定「Fontset-n」:
Emacs.Fontset-0: -*-fixed-medium-r-normal-*-24-*-*-*-*-*-fontset-24,\
chinese-gb2312:-*-*-medium-r-normal-*-24-*-gb2312*-*
配置后,除中文 GB2312 字符外,所有字符对应的字体指定规则中,字体族字段均为「fixed」;而中文 GB2312 字符的字体指定规则中,字体族字段为通配符 '*' ,可自动匹配系统中的中文字体。
Emacs 中负责解析字体集资源配置值并创建字体集的函数为 create-fontset-from-fontset-spec ,你也可以显式调用该函数手动创建字体集。
关于字体命名的更多相关信息,可参阅《字体》章节。
24.16. 修改字体集
字体集并非总需要从头创建。若仅需小幅修改,直接编辑现有字体集通常更简便,最常用的是 'fontset-default' (默认字体集)。修改 'fontset-default' 还会影响所有将其作为回退字体集的其他字体集,因此这是解决 Emacs 为特定文字体系选择字体时各类问题的有效方法。
可通过 set-fontset-font 函数修改字体集,该函数需指定 要修改字体的字符、字符集、文字体系或字符范围 ,以及 待使用的字体规格 。以下为具体示例:
;; 为汉字优先使用大五码(Big5)字体 (set-fontset-font "fontset-default" 'han (font-spec :registry "big5") nil 'prepend) ;; 为表情符号文字体系使用“Noto Color Emoji”字体(默认配置) (set-fontset-font "fontset-default" 'emoji '("Noto Color Emoji" . "iso10646-1") nil 'prepend) ;; 使用彩色字体显示心形字符 (set-fontset-font "fontset-default" #x2764 "Noto Color Emoji") ;; 为Unicode私有使用区使用自定义私有字体MyPrivateFont (set-fontset-font "fontset-default" '(#xe000 . #xf8ff) "MyPrivateFont") ;; 为拉丁-3字符集使用Liberation Mono字体 (set-fontset-font "fontset-default" 'iso-8859-3 "Liberation Mono") ;; 在启动字体集(fontset-startup)中,将DejaVu Sans Mono设为回退字体, ;; 优先于默认字体集(fontset-default)调用 (set-fontset-font "fontset-startup" nil "DejaVu Sans Mono" nil 'append)
修改 symbol script符号文字体系 的字体集时,变量 use-default-font-for-symbols 的取值会决定该 字体集 是否实际生效。
关于 set-fontset-font 函数的更多详细用法,可参考《GNU Emacs Lisp 参考手册》中的字体集章节。
若你不清楚某个字符的编码点或其所属的文字体系,可让 Emacs 直接查询:将光标移至该字符处,按下 C-u C-x = (what-cursor-position) ,相关信息及更多细节会在 Emacs 弹出的 *Help* 帮助缓冲区中显示,具体可参考光标位置信息章节。
例如,日文字符归属于kana(假名)文字体系,但日文文本中常会混合汉字,因此可通过为han(汉字)文字体系配置字体,让 Emacs 使用Kochi Gothic(高知哥特体)显示日文:
(set-fontset-font "fontset-default" 'han "Kochi Gothic")
(为方便使用,Emacs 中的 'han' 文字体系并非仅支持中文字符,而是覆盖了中日韩( CJK )所有统一字符。)
Emacs 支持的所有 script 文字体系 列表,可查看变量 script-representative-chars 的取值。
上述这类字体集配置 仅对默认字体不支持的字符生效 :例如若 'Kochi Gothic' 字体包含拉丁字符,Emacs 也不会用它显示拉丁文字体系 —— 因为 Emacs 默认字体通常已支持基础拉丁字符集。
你系统中安装的部分字体可能存在损坏,或显示对应字符时效果不佳,此时可让 Emacs 在搜索合适的显示字体时,完全忽略这些问题字体。具体方法为:将问题字体名称添加至列表型变量 face-ignored-fonts 的取值中,可在 '~/.emacs' 配置文件中添加如下示例代码:
(add-to-list 'face-ignored-fonts "Some Bad Font")
24.17. 无法显示的字符
你的终端可能无法显示部分非 ASCII 字符。大多数文本终端仅支持一种字符集(可通过变量 default-terminal-coding-system 告知 Emacs 当前终端使用的字符集,详见《终端输入输出的编码体系》章节); 无法用该编码体系编码的字符,默认会显示为问号 '?' 。
图形化显示界面能支持更广泛的字符显示,但如果你的系统未安装对应字符的字体,这些字符会以 空心方块 的形式呈现。
若你需要使用 Latin-1 字符,而终端不支持 Latin-1 字符的显示,可将其替换为助记 ASCII 序列来展示,例如用 ""o" 表示带分音符的字母 ö 。加载 iso-ascii 库即可实现该功能。
若你的终端支持 Latin-1 字符显示,还可通过 Latin-1 等效字符与ASCII 助记序列结合的方式,显示其他欧洲字符集的字符。自定义变量 latin1-display 并启用该功能即可,其中所用的 ASCII 助记序列,大多与前缀输入法的助记序列一致。
24.18. 单字节编辑模式
ISO 8859 系列拉丁字符集将八进制 0240 至 0377(十进制 160 至 255)的字符编码范围,用于表示欧洲各类语言(及部分非欧洲语言)所需的带重音字母和标点符号。需要注意的是,即便在单字节缓冲区中(即禁用多字节字符的情况下),Emacs 仍会将此编码范围内的字节视为 原始字节 ,而非字符;但 Emacs 仍可将这些字符编码临时视作某一单字节字符集的内容来处理。若要指定使用的字符集,可调用 M-x set-language-environment 命令,并选择合适的语言环境(如 'Latin-n' )。相关细节可参考《GNU Emacs Lisp 参考手册》中的「禁用多字节字符」章节。
只要当前使用的终端或字体支持,Emacs 也能将十进制 160 至 255 范围内的字节显示为可识别的字符,该功能会自动生效。在图形化显示界面中,Emacs 还可通过 字体集 显示单字节字符,其实际原理是根据当前语言环境,将单字节字符转换为等效的多字节字符后再展示。若要启用该功能,只需将变量 unibyte-display-via-language-environment 设置为非nil值即可。请注意,该设置 仅影响此类字节的显示方式 ,并不会改变 Emacs 将其视作原始字节而非字符的核心处理逻辑。
若你的终端不支持 Latin-1 字符集的显示,Emacs 可将这些字符转换为 ASCII 序列展示,至少能让你清晰识别字符本身。加载 iso-ascii 库即可实现该功能。理论上可为其他 ISO 8859 拉丁字符集实现类似的库,但目前暂未开发。
默认情况下,非 ISO 8859 字符(十进制 128 至 159 范围内的编码)会以 八进制转义序列 的形式显示。若需为非标准的 ISO 8859 字符集扩展版本修改此显示方式,可使用 disp-table 库中的 standard-display-8bit 函数。
输入单字节非 ASCII 字符有两种方法:
- 使用当前选定语言环境对应的输入法(详见「输入法」章节)。在单字节缓冲区中使用输入法时,通过输入法输入的非 ASCII 字符会被自动转换为单字节格式。
若你的键盘可生成表示非 ASCII 字符的、十进制 128 及以上的字符编码,可直接敲击对应按键输入该编码。
在图形化显示界面中,使用上述按键无需进行特殊设置,可直接生效;而在文本终端中,需调用
M-x set-keyboard-coding-system命令,或自定义变量keyboard-coding-system,以此指定键盘所使用的编码体系(详见「终端输入输出的编码体系」章节)。启用该功能后,你可能需要通过ESC键来输入元字符(Meta);但在控制台终端或xterm等终端模拟器中,你可将元字符映射为ESC键,同时仍能直接通过键盘、组合键(Compose)或右Alt键(AltGr)输入 8 位字符,相关细节可参考「用户输入的类型」章节。许多现代系统为各类无对应键盘按键的语言,提供了 原生输入法 支持。若 Emacs 在编译时启用了原生输入法支持,你即可激活此类输入法并输入其支持的字符。原生输入法的激活与使用方式因系统和输入法类型而异,本文不再赘述,可参考对应的系统文档。本节仅介绍 Emacs 中用于控制原生输入法使用的相关功能。
在基于 GTK 工具包编译的 Emacs 中,变量
x-gtk-use-native-input用于控制 Emacs 是否接收 GTK 输入法生成的字符。该变量默认值为nil,此时 Emacs 使用 X 输入法(XIM);若设为非nil值,则使用 GTK 输入法。X 资源中的useXIM用于控制是否启用 XIM,inputStyle则用于控制原生输入法在 X 界面中生成的预览文本的显示方式,相关细节可参考「Emacs 的 X 资源列表」。在微软视窗(MS-Windows)系统中,Emacs 支持由输入法管理器(IMM)提供的原生输入法,若有需要也可将其关闭,相关细节可参考「微软视窗系统中的键盘使用方法」。
你可将组合键
C-x 8用作 合成字符前缀 ,来输入非 ASCII 的 Latin-1字符及其他可打印字符。C-x 8可在迷你缓冲区、普通缓冲区中用于字符插入,也可在搜索过程中及所有允许输入按键序列的场景中使用。C-x 8的功能通过加载iso-transl库实现。该库加载后,若键盘配有Alt修饰键,该键将与C-x 8实现相同的功能:按住Alt键并敲击重音字符,即可为后续输入的字母添加对应重音。此外,iso-transl库加载后,若键盘带有 Latin-1 虚重音字符键,这些按键也会被定义为合成键,可与后续输入的字符组合生成带重音的字符。按下
C-x 8 C-h可列出所有可用的C-x 8字符合成映射关系。你可通过
M-x iso-transl-set-language命令,为特定语言扩展C-x 8支持的字符合成映射集,目前该功能支持的语言包括:法语(French)、德语(German)、葡萄牙语(Portuguese)、西班牙语(Spanish)和世界语(Esperanto)。相关细节可参考变量iso-transl-language-alist。
24.19. 字符集
在 Emacs 中, charset 是 字符集(character set)的缩写。Emacs 除了支持自身定义的若干字符集(如 emacs、unicode-bmp、eight-bit)外,还兼容绝大多数主流字符集(如 ascii、iso-8859-1、cp1250、big5、unicode)。所有受支持的字符,均归属于一个或多个字符集。
Emacs 通常会自动对字符集做最优处理,无需用户手动干预;但了解字符集的一些底层细节,有时能为使用带来帮助。
一个典型应用场景是字体选择(详见「字体」章节):每种语言环境(详见「语言环境」章节)都会为各类字符集定义一个 优先级列表 。Emacs 搜索字体时,会优先尝试找到能显示最高优先级字符集的字体。例如在日语语言环境中, 'japanese-jisx0208' 字符集拥有最高优先级,因此 Emacs 会尝试使用 注册表属性 为 'JISX0208.1983-0' 的字体。
有两个命令可用于查询字符集相关信息:
- 执行
M-x list-charset-chars,按提示输入字符集名称,即可显示该字符集中的所有字符; - 执行
M-x describe-character-set,按提示输入字符集名称,即可展示该字符集的详细信息,包括其在 Emacs 内部的表示方式。
执行 M-x list-character-sets 可显示 Emacs 支持的所有字符集列表,该列表会标注各字符集的名称及身份识别补充信息。如需了解更多背景,可参考由日本信息处理学会 / 日本信息技术标准委员会(IPSJ/ITSCJ)维护的《用于转义序列的 ISO 编码字符集国际注册表》(ISO-IR)。该列表中的字符集分为两类:常规字符集排在前列,后续为补充字符集。补充字符集指用于定义其他字符集(作为父集或子集),或为旧版 Emacs 提供向下兼容性的字符集。
若要查询缓冲区中某个字符所属的字符集,只需将光标移至该字符前,按下 C-u C-x = 即可(详见「国际字符集简介」章节)。
24.20. 双向编辑
Emacs 支持编辑阿拉伯语、波斯语、希伯来语等文字体系的文本,这类文字的横向自然显示顺序为 从右到左 ,但嵌入其中的数字和拉丁语文本仍按从左到右的方式显示。拉丁语文档中也常嵌入小段阿拉伯语或希伯来语文本(例如程序源文件中的注释和字符串),因此这类文字的文本实际为 双向文本 :同时包含从左到右和从右到左的字符段。
本节介绍 Emacs 为编辑双向文本提供的功能与配置项。
Emacs 以逻辑顺序(也叫阅读顺序)存储从右到左的文本和双向文本:即阅读时第一个字符在缓冲区或字符串中的位置,排在下一个字符之前。双向文本会在显示阶段重新排序为视觉顺序,这就导致字符在缓冲区中的位置,与其在屏幕上的显示位置不再保持单调递增的关系。Emacs 实现了《Unicode 标准附录 #9》中规定的Unicode 双向算法(UBA),用于双向文本的显示重排;仅在文本方向与段落基础方向相反时的折行显示上存在差异(例如从右到左的段落中出现长段英语文本)。
缓冲区局部变量 bidi-display-reordering 用于控制缓冲区中的文本是否在显示时重排。若其值为非nil,Emacs 会对显示的含从右到左方向属性的字符进行重排,该变量默认值为 t 。
双向文本的每个段落均可设置独立的 基础方向 ,可设为从右到左或从左到右。从左到右的段落,文本从窗口左边界开始显示,到达右边界时自动截断或折行;与之相反,从右到左的段落,文本从窗口右边界开始显示,到达左边界时截断或折行。默认情况下, 空行(即全部由空白字符组成的行) 为段落分隔符;若需修改,可自定义两个缓冲区局部变量 bidi-paragraph-start-re 和 bidi-paragraph-separate-re (详见「局部变量」章节),其值为正则表达式(字符串)—— 例如将两个变量均设为 "^" ,即可将单个换行符作为新段落的起始标识。
Emacs 会根据 段落开头的文本内容 ,动态判断每个段落的基础方向。但有时需要为缓冲区中的所有段落强制指定固定的基础方向:若变量 bidi-paragraph-direction 设为非nil,则会关闭基础方向的动态判断,转而强制缓冲区中所有段落使用该变量的缓冲区局部值指定的方向,其有效值为 right-to-left (从右到左)和 left-to-right (从左到右),其他值均视为 nil 。
此外,也可通过在段落开头 插入特殊格式字符 来控制段落的基础方向: 从右到左标记(RLM) 会强制后续段落为从右到左方向, 从左到右标记(LRM) 则强制为从左到右方向(可通过 C-x 8 RET 插入这类字符)。在图形界面会话中,LRM 和 RLM 字符会显示为极窄的空白字符;在文本终端中则显示为普通空白字符。
由于字符在显示时会被重排,那些按 逻辑顺序 或 缓冲区位置段 执行的 Emacs 命令,可能会产生特殊效果。例如 C-f (前进字符)和 C-b (后退字符)按逻辑顺序移动光标,因此当光标遍历经过重排的双向文本时,有时会出现跳跃;同理,若高亮区域覆盖的连续缓冲区字符段跨过重排文本,视觉上该区域可能显得不连续。这属于正常现象,与其他支持双向文本的程序表现一致。
绑定在方向键上的光标移动命令(如 LEFT 、 C-RIGHT ),会 适配当前段落的基础方向 。在从左到右的段落中,带或不带修饰键的右箭头命令,会沿缓冲区文本向前移动;而在从右到左的段落中,该操作会变为向后移动。这一设计契合从右到左段落的特点:屏幕上向左移动时,字符在缓冲区中的位置通常呈递增趋势。
当光标移出某一段落时,若前一段落或后一段落的基础方向与原段落不同,方向键的功能可能会发生变化,此时需要根据新的基础方向调整按下的方向键。
默认情况下, LEFT 、 RIGHT 方向键按 逻辑顺序 移动光标;若将变量 visual-order-cursor-movement 设为非nil,则这些命令会移动到当前屏幕位置 视觉上 左侧或右侧的字符,并在需要时跳转到下一行或上一行屏幕文本。请注意,受周边双向文本上下文影响,该操作可能会使光标在缓冲区中移动较长的距离。
双向文本有时会使用 特殊格式字符 来影响文本的显示重排,前文提到的 LRM 和 RLM 就是其中两种,这类字符还有其他类型。默认情况下,它们在图形界面帧中显示为窄空白符号,在文本模式帧中显示为普通空格。若希望能直观看到这些特殊控制字符,避免其对显示的影响超出预期,可开启 glyphless-display-mode (无字形显示模式,详见「文本的显示方式」章节)。开启该次要模式后,这些格式字符会显示为 小方框内的缩写形式 ,在屏幕上突出显示,便于理解其作用。
25. 主模式与次模式
Emacs 内置多种编辑模式,可通过实用的方式改变其基础操作行为,这些模式分为 major modes 主模式和 minor modes 次模式两类。
主模式为处理特定类型文件(如 C 语言源文件,参见「编辑程序」章节)或特定类型的非文件缓冲区(如 Shell 缓冲区,参见「在 Emacs 中执行 Shell 命令」章节)提供专属功能支持。主模式之间互斥,任意时刻每个缓冲区都有且仅有一个主模式。
次模式是可自由开启或关闭的可选功能,并非必须绑定于特定类型的文件或缓冲区。例如 Auto Fill mode 自动换行模式便是一种副模式,开启后输入空格时,会在单词之间自动换行(参见「自动换行模式」章节)。各副模式之间相互独立,且与当前选中的主模式也彼此独立。
25.1. 主模式
每个缓冲区都拥有一个主模式,该模式决定了此缓冲区为当前缓冲区时 Emacs 的编辑行为。 mode line模式行 通常会在 圆括号内显示当前主模式 的名称(参见「模式行」章节)。
功能最基础的主模式为 Fundamental mode 基本模式 。该模式无专属的模式重定义或变量设置,因此 Emacs 的每个命令都会以最通用的方式执行,所有用户选项变量也均处于默认状态。
编辑 Emacs 可识别的特定类型文本(如 Lisp 代码、英文文本)时,通常会使用更专用的主模式,例如 Lisp mode、Text mode。绝大多数主模式可分为三大类:
- 第一类是适用于普通文本的模式,包含纯文本和带标记的文本,涵盖 Text mode、HTML mode、SGML mode、TeX mode和 Outline mode;
- 第二类是针对特定编程语言的模式,包括 Lisp mode(含多个变体)、C mode、Fortran mode等;
- 第三类是与文件无直接关联的主模式,这类模式用于 Emacs 为特定用途创建的缓冲区,例如 Dired 功能创建的缓冲区所使用的 Dired mode (参见「目录编辑器 Dired」章节)、快捷键
C-x m在缓冲区所使用的Message mode (参见「发送邮件」章节)、用于与子 Shell 进程交互的缓冲区所使用的 Shell mode (参见「交互式子 Shell」章节)。
通常,当你首次打开文件或创建缓冲区时,Emacs 会自动设置主模式(参见「选择文件模式」章节)。你也可以通过 M-x 命令手动选择新的主模式:将模式名后加上 -mode ,即可得到对应模式的选择命令(例如,执行 M-x lisp-mode 即可进入 Lisp 模式)。由于每个缓冲区有且仅有一个主模式,因此不存在「关闭」主模式的操作,若需切换,只需更换为其他主模式即可。
缓冲区局部变量 major-mode 的取值为一个符号,该符号与对应主模式的命令名完全一致(例如 lisp-mode )。此变量由 Emacs 自动设置, 请勿手动修改 。
major-mode 的默认值决定了两类场景下使用的主模式:一是未指定主模式的文件,二是通过 C-x b 创建的新缓冲区。该变量的默认值通常为符号 fundamental-mode ,即对应基本模式。你可通过自定义界面修改此默认值(参见「简易自定义界面」章节),也可在初始化文件中添加如下语句实现修改(参见「Emacs 初始化文件」章节):
(setq-default major-mode 'text-mode)
若 major-mode 的默认值为 nil ,则新缓冲区会沿用前一个当前缓冲区的主模式。
专用主模式通常会重新定义部分按键的功能,使其更适配该模式的使用场景。例如,编程语言相关模式会将 TAB 键绑定为 按对应语言的语法规则缩进当前行的功能 (参见「缩进」章节)。常被重新定义的按键包括 TAB 、 DEL 和 C-j 。许多主模式还会自定义专属命令,这类命令通常绑定到以 C-c 为前缀的按键序列(参见「按键」章节)。主模式也可修改用户选项和变量,例如,编程语言模式通常会为变量 comment-start 设置缓冲区局部值,该变量用于定义源代码注释的分隔符规则(参见「处理注释」章节)。
若要查看当前主模式的说明文档(含其按键绑定列表),可按下 C-h m (describe-mode) ,相关内容亦可参见「其他帮助命令」章节。
除 Fundamental mode基本模式外,所有主模式都定义了 mode hook 模式钩子 —— 这是一个可自定义的 Lisp 函数列表,每当该主模式在某个缓冲区中启用时,列表内的函数都会依次执行。关于钩子的更多信息,参见「钩子」章节。各模式钩子均以对应主模式命名,例如 Fortran mode的钩子为 fortran-mode-hook 。此外,所有基于文本的主模式在执行自身模式钩子前,都会先执行 text-mode-hook ;多数编程语言模式11(包括 Emacs 自带的所有编程语言模式),则会先执行 prog-mode-hook ,再执行自身模式钩子。钩子函数可通过读取变量 major-mode 的值,判断当前实际进入的是哪一个主模式。
模式钩子常被用于启用次模式(参见「次模式」章节)。例如,你可在初始化文件中添加以下语句,实现「在所有基于文本的主模式中启用 Flyspell mode拼写检查次模式」(参见「检查并修正拼写」章节),以及「在 Emacs Lisp 模式中启用 EIDoc 文档实时提示次模式」(参见「编程语言文档查阅」章节):
(add-hook 'text-mode-hook 'flyspell-mode) (add-hook 'emacs-lisp-mode-hook 'eldoc-mode)
25.2. 次模式
minor mode 次模式是一类可选的编辑模式,可按照明确定义的方式改变 Emacs 的操作行为。与主模式不同,任意时刻均可启用 任意数量 的次模式。部分次模式为 buffer-local 缓冲区局部 模式,可在特定缓冲区中开启(启用)、在其他缓冲区中关闭(禁用);另一部分则为 global 全局 模式,一旦启用,会作用于 Emacs 会话中所有操作及全部缓冲区。多数次模式默认处于禁用状态,仅有少数次模式默认启用。
多数缓冲区局部次模式启用后,会在 mode line模式行的主模式标识后方显示自身状态。例如,模式行中的 'Fill' 表示 Auto Fill mode自动换行模式已启用,相关说明参见「模式行」章节。
与主模式相同,每个次模式都对应一个 mode command 模式命令 ,命令名为「模式名-mode」。例如,自动换行模式对应的命令为 auto-fill-mode 。但主模式命令仅用于启用对应模式,次模式命令则可实现启用与禁用的双向操作,规则如下:
- 无前缀参数直接调用次模式命令时(可通过
M-x执行,或为命令绑定按键后敲击对应按键,参见「自定义按键绑定」章节),会 切换 该次模式状态:若原本禁用则启用,若原本启用则禁用。 - 带前缀参数调用次模式命令时,若参数为 0 或负数,会 无条件禁用 该次模式;若参数为正数,则 无条件启用 。
- 在 Lisp 代码中调用次模式命令时,若省略参数或参数为nil,会 无条件启用 该次模式(此设计便于在主模式的模式钩子中启用次模式,参见「主模式」章节);若参数为非nil值,则按上述交互式前缀参数的规则处理。
多数次模式还配有与模式命令同名的 mode variable 模式变量 :变量值为非nil表示次模式已启用,为 nil 则表示禁用。 注意 :请勿在 Lisp 代码中通过直接修改模式变量的值来启用 / 禁用次模式,应调用对应的模式命令;而通过自定义界面(参见「简易自定义界面」章节)设置模式变量时,会自动触发对应模式命令,确保次模式被正确启用 / 禁用。
以下为常用的 buffer-local 缓冲区局部次模式列表:
- 缩写模式(Abbrev mode):根据预定义的缩写规则自动展开文本,参见「缩写」章节。
- 自动换行模式(Auto Fill mode):输入时自动插入换行符,防止行内容过长,参见「文本换行」章节。
- 自动保存模式(Auto Save mode):定期保存缓冲区内容,减少程序崩溃时的工作丢失,参见「自动保存:应对意外故障」章节。
- 智能引号模式(Electric Quote mode):自动转换引号样式,例如将输入的
`like this'自动转换为‘like this’;可自定义其生效的文本类型,也可在单个缓冲区中完全禁用,参见「引号」章节。 - 富文本模式(Enriched mode):支持编辑和保存带格式的文本,参见「富文本」章节。
- 拼写检查模式(Flyspell mode):自动高亮拼写错误的单词,参见「检查并修正拼写」章节。
- 语法高亮模式(Font-Lock mode):自动高亮程序中的各类文本单元,该模式默认全局启用,也可在单个缓冲区中禁用,参见「文本外观」章节。
- 行号显示模式(Display Line Numbers mode):是
display-line-numbers功能的便捷封装,根据display-line-numbers-type的值设置行号显示规则,参见「显示自定义」章节。 - 大纲次模式(Outline minor mode):提供与大纲主模式(Outline mode)相似的功能,参见「大纲模式」章节。
- 覆盖模式(Overwrite mode):输入普通打印字符时会替换原有文本,而非将原有文本后移。例如,光标位于 'FOOBAR' 中字母 'B' 前方时,开启该模式后输入 'G' 会得到 'FOOGAR',而非默认的 'FOOGBAR' 。该模式下,命令
C-q会插入后续任意字符(包括数字),可实现「插入字符而非替换原有字符」的操作。该模式的命令overwrite-mode绑定于Insert键。 - 二进制覆盖模式(Binary Overwrite mode):覆盖模式的变体,适用于编辑二进制文件;将换行符、制表符视作普通字符,可被其他字符替换,也可替换其他字符。该模式下,
C-q后的数字仍按常规表示八进制字符编码。 - 视觉行模式(Visual Line mode):按单词边界进行自动换行,使长行在单词之间折行显示,参见「视觉行模式」章节。
以下为实用的全局次模式列表:
- 列号显示模式(Column Number mode):在模式行中显示当前光标所在列号,参见「模式行」章节。
- 选中删除模式(Delete Selection mode):若选区处于激活状态,输入文本时会先删除选区内容,参见「选区操作」章节。
- 补全提示模式(Icomplete mode):在迷你缓冲区中进行补全操作时,实时显示可用的补全选项,参见「迷你缓冲区快速选择」章节。
- 行号模式(Line Number mode):在模式行中显示当前光标所在行号,默认启用,参见「模式行」章节。
- 菜单栏模式(Menu Bar mode):为每个框架添加菜单栏,默认启用,参见「菜单栏」章节。
- 滚动条模式(Scroll Bar mode):为每个窗口添加滚动条,默认启用,仅在图形化终端中显示滚动条,参见「滚动条」章节。
- 工具栏模式(Tool Bar mode):为每个框架添加工具栏,默认启用,仅在图形化终端中显示工具栏,参见「工具栏」章节。
- 窗口工具栏模式(Window Tool Bar mode):为每个窗口添加工具栏,参见「窗口工具栏」章节。
- 标签栏模式(Tab Bar mode):为每个框架添加标签栏,参见「标签栏」章节。
- 标签行模式(Tab Line mode):为每个窗口添加标签行,参见「窗口标签行」章节。
- 临时标记模式(Transient Mark mode):高亮显示选区,且当标记处于激活状态时,让 Emacs 的多数命令作用于选区,默认启用,参见「标记与选区」章节
25.3. 选择文件模式
访问文件时,Emacs 会自动为其选择一种 主要模式 。默认情况下,该选择基于文件名 —— 例如,后缀为 '.c' 的文件会默认使用 C mode 编辑;部分场景下,也会根据文件内的特殊文本选择主要模式,这类特殊文本也可用于启用 buffer-local 缓冲区本地的次要模式 。
Emacs 选择文件模式的具体流程如下:
第一步:检查文件本地模式变量
Emacs 会先检查文件中是否包含 file-local mode文件本地模式变量 (参见《文件中的本地变量》章节)。若存在指定了主要模式的文件本地变量,Emacs 会直接使用该模式,忽略其他所有判断条件。通过文件本地变量指定主要模式的方法有多种, 最简方式 是在文件的 第一个非空行 中,将模式名包裹在 '-*-' 之间,该行也可包含其他文本。例如:
; -*-Lisp-*-
上述代码会告知 Emacs 使用 Lisp 模式。注意此处的分号是为了让 Lisp 将该行识别为注释,也可等价写为:
; -*- mode: Lisp;-*-
也可通过 eval 规范 ,利用文件本地变量指定缓冲区本地的次要模式。例如,以下第一个非空行会将缓冲区设为 Lisp mode,并启用自动换行模式:
; -*- mode: Lisp; eval: (auto-fill-mode 1); -*-
注意:通常不建议以这种方式启用次要模式,因为多数次要模式代表用户的个性化偏好。若你希望为特定文件类型启用某一次要模式,更推荐通过 主要模式钩子 实现(参见《主要模式》章节)。
第二步:检查目录本地的自动模式关联表
Emacs 会检查文件后缀是否匹配任意目录本地的 auto-mode-alist 中的条目,该表通过 .dir-locals.el 工具实现(参见《按目录划分的本地变量》章节)。
第三步:检查文件首行的 #! 标记
若仍未确定主要模式,Emacs 会检查文件内容是否以 #! 开头。该标记表示此文件是可执行的 Shell 命令,系统会通过文件首行指定的解释器运行该文件(文件其余内容作为解释器的输入)。因此,Emacs 会尝试通过解释器名称选择模式。例如,首行为 '#!/usr/bin/perl' 的文件会以 Perl mode 打开。解释器程序名与主要模式的对应关系,由变量 interpreter-mode-alist 定义。
若文件首行以 #! 开头,通常无法在首行使用 '-*-' 标记(否则系统运行解释器时会出现解析错误)。
- 因此,这类文件中,Emacs 会同时在第一行和第二行查找 '-*-' 标记。
- 手册页(man page)也存在类似情况:其首行通常以魔术字符串
'\"开头,用于指定 troff 预处理器列表,这类文件同样会在第二行查找 '-*-' 标记。
第四步:通过 magic-mode-alist 匹配缓冲区首文本
Emacs 会基于 magic-mode-alist 变量,通过检查 缓冲区开头的文本内容 来判定主要模式。该变量的默认值为 nil (空列表),因此 Emacs 会跳过此步骤;你可在初始化文件中对其进行自定义配置(参见《Emacs 初始化文件》章节)。该变量的值需为若干指定格式的元素组成的列表。元素格式有两种:
正则表达式格式:
(regexp . mode-function)其中 regexp 为正则表达式(参见《正则表达式的语法》), mode-function 为主要模式命令。若文件开头的文本匹配该正则表达式,Emacs 会使用 mode-function 指定的主要模式。
函数匹配格式:
(match-function . mode-function)其中 match-function 为 Lisp 函数,Emacs 会在缓冲区开头调用该函数;若函数返回非 nil 的值,则使用 mode-function 设置主要模式。
第五步:根据文件名匹配自动模式关联表
若仍未找到合适的主要模式,Emacs 会最终通过 文件名 判断,文件名与主要模式的对应关系由变量 auto-mode-alist 控制。该变量的值为列表,每个元素有两种格式:
- 基础格式:
(regexp . mode-function) - 扩展格式:
(regexp mode-function flag)
例如,该列表中默认包含条目 ("\\.c\\'" . c-mode) ,用于为后缀为 .c 的文件选择 C mode 。(注意:Lisp 语法中,需用 '\\' 表示字符串中的 '\',而正则表达式中需用 '\' 取消 '.' 的特殊含义。)
若元素为扩展格式 (regexp mode-function flag) 且 flag 为非 nil,则 Emacs 调用 mode-function (若其非 nil)后,会 舍弃匹配正则表达式的文件后缀 ,并重新遍历列表查找新的匹配项。这种「递归剥离后缀」的机制,适用于多后缀文件—— 此类文件的「外层后缀」会掩盖实际指定模式的「内层后缀」,例如备份文件、后缀为 .gpg 的 GPG 加密文件均使用该特性。
在 GNU/Linux 等区分文件名大小写的系统中,Emacs 会先对 auto-mode-alist 进行区分大小写的查找;若查找失败,会再次进行不区分大小写的查找。若要关闭第二次查找,可将变量 auto-mode-case-fold 设为 nil。
在微软 Windows 等不区分文件名大小写的系统中,Emacs 仅对 auto-mode-alist 进行一次不区分大小写的查找。
第六步:通过 magic-fallback-mode-alist 表匹配
若以上所有步骤均未找到主要模式,Emacs 会将缓冲区开头的文本与变量 magic-fallback-mode-alist 进行匹配。
该变量的工作方式与 magic-mode-alist 一致,唯一区别是仅在 auto-mode-alist 匹配失败后才会被调用。其默认值包含用于识别图片文件、HTML/XML/SGML 文件、PostScript 文件和Unix 风格配置文件的规则。
主要模式的重映射
当 Emacs 找到某一主要模式后,会做最后一次检查:该模式是否被 major-mode-remap-alist 重映射。若存在重映射,则使用重映射后的模式。该机制适用于 同一种文件类型可对应多种主要模式 的场景,方便用户指定偏好的模式。注意:该重映射会影响上述所有方法找到的主要模式 —— 例如,文件首行指定的模式,未必是最终在访问该文件的缓冲区中启用的模式(该重映射也会影响 revert-buffer 命令,参见《恢复缓冲区》章节)。
若某一文件类型有多种可选模式,可通过自定义 major-mode-remap-alist 告知 Emacs 你的偏好。例如,在 ~/.emacs 初始化文件中添加以下代码(参见《Emacs 初始化文件》章节):
(add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
可强制 Emacs 在 auto-mode-alist 或文件本地变量指定 c-mode 时,调用 c-ts-mode 。反之,添加:
(add-to-list 'major-mode-remap-alist '(c-mode))
可强制 Emacs 永远不将 c-mode 重映射为其他模式。
major-mode-remap-alist 的默认值为 nil ,即无重映射。但加载部分 Lisp 包或功能时,可能会自动引入模式重映射(Emacs 会默认认为,加载这些包代表用户偏好使用替代模式)。因此,为了让 Emacs 行为可预测,建议始终自定义 major-mode-remap-alist 明确你的偏好—— 该变量会覆盖 Emacs 内部的所有重映射规则。
恢复默认主要模式: normal-mode 命令
若你手动修改了缓冲区的主要模式,可键入 M-x normal-mode ,让 Emacs 恢复为其自动选择的主要模式。 find-file 命令选择主要模式时,调用的正是该函数。
- 若缓冲区正在访问某一文件,该命令还会处理文件的 '-*-' 行和文件本地变量列表(若有);参考 文件本地变量
- 若缓冲区未访问任何文件,该命令仅处理 '-*-' 行和文件本地变量列表中的主要模式规范(若有)。
normal-mode 会考虑模式重映射 —— 若在 Emacs 选择缓冲区的主要模式后,你自定义了 Major-mode-remap-alist ,该命令可能会启用与 Emacs 初始选择不同的模式。
文件名变更时的模式自动切换
C-x C-w 和 set-visited-file-name 命令若修改了文件名,且新文件名对应某一主要模式,Emacs 会自动切换至该模式(参见《保存文件》章节);若缓冲区原本未访问任何文件, C-x C-s 命令也会触发此行为。例外情况:若缓冲区内容已通过特殊文本指定了主要模式,或当前为部分特殊主要模式(不允许模式变更),则不会触发自动切换。若要关闭该特性,可将变量 change-major-mode-with-file-name 设为 nil 。
26. 缩进
Indentation 缩进 指在文本行开头插入或调整 whitespace characters 空白字符 (空格和 / 或制表符)。本章介绍 Text mode及相关模式与编程语言模式通用的缩进命令和配置项。关于编程模式下的缩进相关额外说明,参见《程序缩进》章节。
实现缩进最简便的方式是按下 TAB 键。在大多数主要模式中,按下该键会执行 indent-for-tab-command 命令(在 C 语言及相关模式中, TAB 键执行 c-indent-line-or-region 命令,其行为与之类似,参见《C 语言缩进命令》章节)。
TAB- 以适配当前模式的方式插入空白字符,或为当前行执行缩进 (
indent-for-tab-command) 。若区域处于激活状态,则为区域内所有行执行缩进。
TAB 键的具体行为由当前主要模式决定:在文本模式及相关主要模式中, TAB 键通常会插入若干空格和制表符的组合,将光标移动至下一个制表位(参见《制表位》章节)。在此模式下,上一行首个非空白字符的位置会被视作一个额外的制表位,因此你可通过 TAB 键让光标与上一行对齐。若区域处于激活状态(参见《区域操作》章节), TAB 键会执行特殊行为:为区域内每一行缩进,使各行首个非空白字符与上一行对齐。
在编程模式中, TAB 键会根据前序代码的结构,为当前代码行执行符合语法逻辑的缩进。若区域处于激活状态,则为区域内所有行执行该缩进操作。若光标初始位置处于当前行的缩进空白段内,执行该命令后光标会被重新定位至该行首个非空白字符处。
若你仅需在缓冲区中插入一个制表符,可键入 C-q TAB (参见《插入文本》章节)。
26.1. 缩进命令
除 TAB 制表键 (indent-for-tab-command) 外,Emacs 还提供多种命令,以其他方式实现缩进操作。
C-M-o- 在光标位置拆分当前行 (
split-line) 。光标后的行内文本将成为新行,且缩进至光标所在的列位置。该命令会先将光标向前移动,跳过所有空格和制表符;拆分完成后,光标将停在插入的换行符之前。 M-m- 将光标移至当前行第一个非空白字符处 (
back-to-indentation) 。若当前行无任何非空白字符,则将光标移至行尾。 M-i- 在光标位置插入空白字符,直至下一个制表位 (
tab-to-tab-stop) ,详见制表位章节。 M-x indent-relative- 在光标位置插入空白字符,直至光标与上一行(实际为最后一个非空行)的第一个非空白字符对齐。若光标原本已在该位置右侧,则执行
tab-to-tab-stop命令;若带数字参数调用此命令,则不执行任何操作。 M-^合并上一行与当前行 (
delete-indentation) 。该命令会将当前行开头的所有缩进字符及行分隔符替换为单个空格,实现两行的整洁合并。特殊情况(适用于 Lisp 代码):若待合并的字符为连续的左右括号,或合并位置紧跟另一个换行符,则省略上述的单个空格。
若当前设置了填充前缀,当被删除的换行符后紧跟填充前缀时,
M-^会同时删除该填充前缀,详见填充前缀章节。带前缀参数调用此命令时,将合并当前行与下一行;若区域处于激活状态且未带前缀参数,则合并该区域内的所有行。
C-M-\缩进区域内的所有行,效果等同于在每行行首按下
TAB制表键 (indent-region) 。若带数字参数调用,将把区域内所有行统一缩进至该数字指定的列数。
C-x TAB缩进所有起始于该区域的行,受影响的行将作为一个整体进行刚性移动 (
indent-rigidly) 。无参数调用此命令时,将激活一个临时模式,可交互式调整受影响行的缩进:临时模式激活期间,按左方向键/右方向键可分别向左 / 向右缩进 1 个空格;也可按
S-LEFT/S-RIGTH,向左 / 向右缩进至下一个制表位(详见制表位章节)。按下其他任意按键,将退出该临时模式,且该按键会按常规功能执行。带前缀参数
n调用此命令时,将把目标行向前缩进n个空格(不激活临时模式);n为负值时则向后缩进,因此可使用一个绝对值较大的负值,移除区域内所有行的缩进,示例操作:C-u -999 C-x TAB
26.2. 制表位
Emacs 会定义特定的列号作为 tab stop 制表位 。在文本模式及相关模式下插入空白符时,制表键( TAB )会将光标停在这些位置(参见缩进相关说明), M-i 这类缩进命令也会遵循该规则(参见缩进命令相关说明)。制表位的位置由变量 tab-stop-list 控制,其默认值为 nil ,代表每 8 列设置一个制表位。该变量也可设为一个 从零开始计数 的列号列表(按升序排列),列表中的列号即为制表位的位置。Emacs 会取列表中最后一个元素与倒数第二个元素的差值,以此为间隔无限延伸该制表位列表。
无需直接自定义 tab-stop-list 变量,Emacs 提供了更便捷的制表位查看与设置方式:执行命令 M-x edit-tab-stops 。该命令会打开一个专用缓冲区,用于展示当前制表位的设置情况,缓冲区内容格式如下:
: : : : : : 0 1 2 3 4 0123456789012345678901234567890123456789012345678 To install changes, type C-c C-c
第一行的冒号(:)对应每个制表位的位置,下方两行的数字仅用于标示冒号所在的列数。若 tab-stop-list 为默认值 nil,该缓冲区初始状态下将不显示任何冒号。
你可在该缓冲区中编辑制表位:在需要设置制表位的列位置输入冒号即可,此缓冲区默认启用 Overwrite mode改写模式(参见次要模式)。需注意,Emacs 会以你手动设置的最后两个显式制表位的差值为步长,无限延伸后续的制表位。编辑完成后,按下 C-c C-c 即可使新的制表位设置生效。默认情况下,新的制表位设置会应用于所有缓冲区;但如果你已将 tab-stop-list 设为调用 M-x edit-tab-stops 时所在缓冲区的局部变量(参见局部变量),则新设置仅对该缓冲区生效。若要将制表位设置保存至后续的 Emacs 会话,可通过自定义界面(Customize)保存 tab-stop-list 的值(参见简易自定义界面)。
注意:本节所讲的制表位,与缓冲区中制表符(tab 字符)的显示方式无任何关联。制表符在显示时,始终会以空白字符的形式填充至 下一个显示制表位 ,具体规则参见文本的显示方式相关内容。
26.3. 制表符与空格的选择
默认情况下,缩进命令会插入(或删除) 最短的制表符与空格组合 ,使光标对齐至目标列。制表符在显示时会以一段空白的形式呈现,直至下一个显示制表位。默认配置下,每 tab-width 列会设置一个显示制表位(该变量默认值为 8),详见《文本的显示方式》。
若需要,可将所有缩进统一设置为仅使用空格实现:将 buffer-local 缓冲区局部 变量 indent-tabs-mode 设为 nil 即可。关于缓冲区局部变量的设置方法,详见《局部变量》章节。需注意,无论 indent-tabs-mode 的取值如何,按下 C-q TAB 始终会插入一个制表符。
将 indent-tabs-mode 设为 nil 的一个重要原因是:不同编辑器对制表符的显示规则不一致,即便是 Emacs 用户,也可能为 tab-width 配置不同的自定义值。仅使用空格进行缩进,可确保文件在任意编辑器中显示的缩进格式完全一致。如果仅关注文件在 Emacs 中的显示效果,也可通过 file-local variable文件局部变量 设置 tab-width 来解决该问题(详见《文件中的局部变量》)。
Emacs 也提供了制表符与空格的互转命令,且转换过程中 始终保留所有非空白文本的列位置不变 :
M-x tabify:扫描指定区域内的空格序列,若转换后不会改变缩进效果,会将连续至少两个空格的序列转换为制表符;M-x untabify:将指定区域内的所有制表符,转换为对应数量的空格。
26.4. 缩进的便捷功能
变量 tab-always-indent 可调整制表键 (indent-for-tab-command) 的行为。其默认值为 t ,此时制表键将遵循「缩进」章节中描述的默认缩进行为。若将该值改为符号 complete ,制表键会先尝试缩进当前行;若当前行已完成缩进,则会尝试补全光标处的文本(参见《符号名的补全》)。若该值设为 nil ,则仅当光标位于左边界或当前行的缩进区域内时,制表键才会缩进当前行;其余情况下,制表键将直接插入一个制表符。
当 tab-always-indent 设为 complete 时,制表键优先执行补全还是缩进,可通过变量 tab-first-completion 进一步自定义。例如,若将该变量设为 eol ,则仅当光标位于行尾时,制表键才会执行文本补全。更多细节可参见《Emacs Lisp 参考手册》中的「模式专属缩进」章节。
Electric Indent mode 是一个全局次要模式,开启后按下回车键( RET )会自动缩进新行,该模式默认启用。按下 M-x electric-indent-mode 可切换该全局模式的开关;若仅需在单个缓冲区中切换,可使用命令 M-x electric-indent-local-mode 。
26.5. 代码对齐
Alignment 对齐 是指调整区域内多行文本的空白符,使所有行中特定内容均从同一列开始的操作。该操作通常用于提升文本或代码的可读性,典型示例为对类 C 编程语言中的一系列赋值语句进行对齐: 原始代码:
int a = 1; short foo = 2; double blah = 4;
对齐后通常为:
int a = 1; short foo = 2; double blah = 4;
可使用命令 M-x align 对当前区域内的行进行对齐,该命令适配多种标记语言和编程语言的通用对齐模式,并将这些模式编码为一套 alignment rules 对齐规则 ,定义了不同上下文下各类文本的对齐方式。
用户选项 align-rules-list 指定了 M-x align 需参考的对齐规则,其值为一个描述对齐规则的元素列表。每个元素均为一个点对 (title . attributes) :其中 title 为符号类型的对齐规则名称, attributes 为规则属性列表,用于定义规则的生效条件,以及对行的拆分和对齐方式。每个规则属性也是一个点对 (attribute . value) ,唯一的必选 attribute 为 regexp , value 为一个正则表达式,通过子表达式匹配每行中需要 M-x align 增减空白符的位置(参见《正则表达式中的反斜杠》)。关于对齐规则属性的完整说明,可查看 align-rules-list 的文档字符串 (C-h v align-rules-list RET) 。该选项默认配置了一长串适配 Emacs 所支持的多种语言的对齐规则,且默认规则通过 modes 规则属性指定了 M-x align 的生效主模式。主模式也可通过将缓冲区局部变量 align-mode-rules-list 设为非空的对齐规则列表,来覆盖 align-rules-list 的配置;当 align-mode-rules-list 为非空值时, M-x align 将优先参考该变量,而非 align-rules-list 。
除对齐规则外, M-x align 还会使用另一类 exclusion rules 排除规则 ,用于指定区域内无需对齐、需保持原样的内容。用户选项 align-exclude-rules-list 定义了这些排除规则,其值同样为描述排除规则的点对列表,与 align-rules-list 格式一致。该选项默认包含了对 Lisp、C 等语言中 字符串常量 和 注释 的对齐排除规则。除 align-exclude-rules-list 中的默认排除规则外,主模式还可通过将 align-mode-exclude-rules-list 设为非空的规则列表,定义自定义排除规则;该变量对 align-exclude-rules-list 的覆盖方式,与 align-mode-rules-list 对 align-rules-list 的覆盖方式一致。
M-x align 会将目标区域拆分为多个 sections 分段 (通常为连续的非空行),并通过增减空白符,按照所有匹配的对齐规则对每个分段分别对齐。该命令会保证单个分段内的所有行对齐方式一致,但同一区域内的不同分段可能采用不同的对齐方式。用户选项 align-region-separate 指定了 M-x align 拆分区域为分段的方式,其值可为符号 entire 、 group ,或一个正则表达式:
- 若值为
entire,Emacs 会将整个区域作为一个分段进行对齐; - 若值为
group,Emacs 会将区域内每组连续的非空行分别作为独立分段; - 若值为正则表达式,
M-x align会扫描区域中匹配该表达式的内容,将其作为分段分隔符。
该选项默认设为一个正则表达式,可匹配 空行 ,以及仅包含空白符和单个大括号('{' 或 '}')的行。若正则表达式无法满足精准拆分的特殊场景,也可将 align-region-separate 设为一个函数,由该函数定义区域到对齐分段的拆分规则,更多细节可查看其文档字符串。特定的对齐规则还可通过指定 separate 规则属性,覆盖 align-region-separate 的取值,定义专属的分段分隔符。
若带前缀参数调用 M-x align (快捷键 C-u M-x align ),该命令会启用更多对齐规则 —— 这些规则通常实用,但有时可能会产生过度对齐的效果。例如,在 Lisp 缓冲区中有如下代码:
(set-face-attribute 'mode-line-inactive nil
:box nil
:background nil
:underline "black")
执行 C-u M-x align 后将得到:
(set-face-attribute 'mode-line-inactive nil
:box nil
:background nil
:underline "black")
多数情况下,应先直接调用 M-x align (不带前缀参数);若结果不符合预期,可通过 C-/ 撤销操作,再尝试带前缀参数的 C-u M-x align 。
可使用命令 M-x align-highlight-rule ,在当前区域中可视化特定对齐规则或排除规则的作用效果。该命令会提示你输入规则标题,并高亮显示区域内受该规则影响的内容:对对齐规则,会高亮 M-x align 将增减的空白符;对排除规则,会高亮 M-x align 将跳过对齐的内容。若要清除该命令的高亮效果,执行 M-x align-unhighlight-rule 即可。
命令 M-x align-current 与 M-x align 功能类似,区别在于:无论当前是否选中区域,该命令仅对 包含光标 的对齐分段生效,其会根据 align-region-separate 定义的分段分隔符,确定当前分段的边界。 M-x align-entire 是 M-x align 的另一个变体,该命令会忽略 align-region-separate 的配置,将整个区域作为单个对齐分段进行统一对齐。若将 align-region-separate 设为 entire , M-x align 的默认行为将与 M-x align-entire 一致。
以下示例可说明将整个区域作为单个分段对齐的效果,原始代码:
one = 1; foobarbaz = 2; spam = 3; emacs = 4;
若选中所有行并执行 M-x align ,结果为:
one = 1; foobarbaz = 2; spam = 3; emacs = 4;
而执行 M-x align-entire 时,所有行被作为单个分段对齐,所有等号 '=' 将出现在同一列:
one = 1; foobarbaz = 2; spam = 3; emacs = 4;
命令 M-x align-regexp 允许你通过 自定义临时对齐规则 对当前区域进行对齐,而非使用 align-rules-list 中的预定义规则。该命令会提示你输入一个正则表达式,并将该表达式作为临时对齐规则的 regexp 属性,用于区域对齐。默认情况下,该命令会调整匹配你所指定正则表达式 第一个子表达式 的空白符;若带前缀参数调用 M-x align-regexp ,其还会提示你指定待使用的子表达式、设置对齐的空白符填充量,以及是否对每行中所有匹配该正则表达式的内容重复应用该规则。关于正则表达式及其子表达式的更多信息,参见《正则表达式中的反斜杠》。
若用户选项 align-indent-before-aligning 为非空值,Emacs 会在执行 M-x align 对齐区域前,先对该区域进行缩进处理(参见《缩进》章节),该选项默认值为 nil 。
用户选项 align-to-tab-stop 用于指定对齐后的内容是否从制表位开始(参见《制表位》章节):
- 若值为
nil,M-x align仅使用满足对齐需求的最少空白符,忽略制表位; - 若值为非空符号,
M-x align会检查该符号的取值,若其值为非空,则按制表位进行对齐。
该选项默认设为 indent-tabs-mode ,因此在使用制表符进行缩进的缓冲区中,对齐操作会遵循制表位的配置(参见《制表符与空格》章节)。
用户选项 align-default-spacing 指定了 M-x align 及其相关命令在对齐时,为每行不同内容之间填充的默认空白符数量:
- 当
align-to-tab-stop为nil时,该值为填充的空格数; - 当
align-to-tab-stop为非空值时,该值为填充的制表位数量。
各对齐规则可通过 spacing 规则属性,覆盖 align-default-spacing 设置的默认值。
27. 自然语言相关命令
本章介绍 Emacs 中针对 自然语言文本 的编辑命令(此处的文本指自然语言的字符序列,而非计算机编程语言代码)。这类命令的执行逻辑会遵循自然语言的句法与格式规范,涵盖单词、句子、段落、大写字母相关的使用规则。同时本章也会讲解 文本填充 相关命令,即重新调整段落的行宽,使各行列数大致均等。这些命令虽主要为自然语言文本编辑设计,在程序代码编辑中也同样常用。
Emacs 提供了多种适用于自然语言文本编辑的主模式:若编辑普通纯文本文件,可使用 文本模式 ,该模式会针对自然语言的句法规范,对 Emacs 做轻量定制; 大纲模式 则为编辑大纲结构的文本提供了专属操作命令,详见《大纲模式》章节。
Org 模式 是大纲模式的拓展,可将 Emacs 变为功能完善的事务管理工具:你可通过该模式管理待办清单、记录笔记,并将笔记导出为多种格式。相关用法详见 Emacs 自带的《Org 信息手册》。
针对包含嵌入式命令的特殊文本,Emacs 也提供了对应的专用主模式,包括 TeX 与 LaTeX 模式(详见《TeX 模式》)、HTML 与 SGML 模式(详见《SGML 和 HTML 模式》)、XML 模式(详见 Emacs 自带的《nXML 模式信息手册》),以及 Groff 与 Nroff 模式(详见《Nroff 模式》)。
若需编辑由文本字符构成的 ASCII 绘图,可使用 图片模式 —— 这是为编辑此类绘图专门设计的主模式,详见《编辑字符绘图》章节。
27.1. 单词操作
27.2. 句子操作
27.3. 段落操作
27.4. 页面操作
27.5. 引号处理
27.6. 文本填充
27.6.1. 自动填充模式
27.6.2. 显式填充命令
27.6.3. 填充前缀
27.6.4. 自适应填充
27.7. 大小写转换命令
Emacs 提供了专门命令,可将单个单词或任意范围的文本转换为大写或小写形式。
M-l- 将后续单词转换为小写 (
downcase-word) 。 M-- M-l- 将前一个单词转换为小写。注:
M--即 Meta-减号。 M-u- 将后续单词转换为大写 (
upcase-word) 。 M-- M-u- 将前一个单词转换为全大写形式。
M-c- 将后续单词首字母大写 (
capitalize-word) 。 M-- M-c- 将前一个单词转换为首字母大写、其余字母小写的形式。
C-x C-l- 将选中区域的文本转换为小写 (
downcase-region) 。 C-x C-u- 将选中区域的文本转换为大写 (
upcase-region) 。
M-l (downcase-word) 会将光标后方的单词转换为小写,并将光标移至该单词末尾。因此,重复按下 M-l 可依次转换后续的多个单词。 M-u (upcase-word) 则将单词转换为全大写,而 M-c (capitalize-word) 仅将单词首字母转为大写,其余字母均转为小写。若为这些命令指定参数,可一次性转换多个单词。这些命令在将大量全大写文本转换为大小写混合格式时尤为实用:你可在文本中移动光标,根据需要对每个单词分别使用 M-l 、 M-u 或 M-c ,也可偶尔使用 M-f 跳过无需转换的单词。
若为单词大小写转换命令指定负参数(如 C-u - 5 M-c ),该命令会对光标 前方 指定数量的单词进行转换,且 不会移动光标 。当你刚输入完一个大小写错误的单词时,此用法会非常便捷:直接使用 M-- M-u 这类转换命令即可修正,无需中断输入。
若在单词 中间位置 执行单词大小写转换命令,该命令仅对光标 后方 的单词部分生效(这一行为与 M-d ( kill-word ,删除单词) 类似);若指定负参数,则仅对光标 前方 的单词部分进行大小写转换。
另外两个大小写转换命令为 C-x C-u (upcase-region) 和 C-x C-l (downcase-region) ,二者会将光标与标记之间的 整个区域 内的所有文本转换为指定大小写,执行后光标与标记的位置均保持不变。
区域大小写转换命令 upcase-region 和 downcase-region 默认处于 禁用状态 ,这意味着你尝试使用这类命令时,Emacs 会要求你确认操作。当你确认后,可选择启用该命令,后续使用时将不再弹出确认提示。详见「命令的禁用」相关内容。
27.8. 文本模式
27.9. 大纲模式
27.9.1. 大纲次模式
27.9.2. 大纲格式
27.9.3. 大纲移动命令
27.9.4. 大纲可见性命令
27.9.5. 多视图查看单个大纲
27.9.6. 折叠编辑
27.10. 组织模式(Org Mode)
27.10.1. 作为事务管理器的 Org 模式
27.10.2. 作为创作系统的 Org 模式
27.11. TeX 模式
27.11.1. TeX 编辑命令
27.11.2. LaTeX 编辑命令
27.11.3. TeX 打印命令
27.11.4. TeX 模式杂项功能
27.12. SGML 与 HTML 模式
27.13. Nroff 模式
27.14. 富文本
27.14.1. 富文本模式
27.14.2. 硬换行与软换行
27.14.3. 格式信息编辑
27.14.4. 富文本中的外观样式
27.14.5. 富文本中的缩进
27.14.6. 富文本中的对齐方式
27.14.7. 设置其他文本属性
27.15. 文本表格编辑
27.15.1. 什么是文本表格?
27.15.2. 创建表格
27.15.3. 表格识别
27.15.4. 表格单元格操作命令
27.15.5. 单元格对齐方式
27.15.6. 表格行与列操作
27.15.7. 纯文本与表格的相互转换
27.15.8. 表格杂项功能
27.16. 双列编辑
28. 程序编辑
28.1. 编程语言相关主模式
28.2. 顶层定义(或函数定义)
28.2.1. 左边距约定
28.2.2. 按函数定义移动
28.2.3. 按句子移动
28.2.5. 函数名称显示模式
28.3. 程序缩进
28.3.1. 基本程序缩进命令
28.3.2. 多行缩进
28.3.3. 定制 Lisp 缩进
28.3.4. C 语言缩进命令
28.3.5. 定制 C 语言缩进
28.4. 括号编辑相关命令
28.4.1. 平衡括号表达式
28.4.2. 在括号结构中移动
28.4.3. 括号匹配
28.5. 注释处理
注释是编程中至关重要的组成部分,因此 Emacs 提供了专门用于编辑和插入注释的命令。它还可通过 Flyspell Prog 模式对注释进行拼写检查(详见 “拼写检查与修正” 章节)。
部分主模式针对不同类型注释的缩进制定了特殊规则。例如,在 Lisp 代码中,以两个分号(;;)开头的注释会按代码行的方式缩进,而以三个分号(;;;)开头的注释则应左对齐到页边距,且常用于代码分段说明。Emacs 能够识别这些约定:例如,在注释行按 Tab 键时,会将注释缩进至合适位置。
;; 此函数仅为示例 ;;; 此处使用两个或三个分号均可 (defun foo (x) ;;; 接下来是函数的第一部分: ;; 下一行实现加一操作 (1+ x)) ; 此行实现加一操作
28.5.1. 注释命令
28.5.2. 多行注释
28.5.3. 控制注释的相关选项
28.6. 文档查阅
28.6.1. Info 文档查阅
28.6.2. 手册页查阅
28.6.3. 编程语言文档查阅
28.7. 代码折叠次模式
28.8. 符号名称补全
28.9. 混合大小写单词处理
28.10. 语义分析(Semantic)
28.11. 其他程序编辑实用功能
28.12. C 语言及相关模式
28.12.1. C 模式移动命令
28.12.2. C 语言自动缩进字符
28.12.3. C 模式中的贪婪删除功能
28.12.4. C 模式的其他命令
28.13. 汇编语言模式
28.14. Fortran 模式
28.14.1. 移动命令
28.14.2. Fortran 缩进
28.14.2.1. Fortran 缩进与填充命令
28.14.2.2. 续行
28.14.2.3. 行号显示
28.14.2.4. 语法约定
28.14.2.5. Fortran 缩进相关变量
28.14.3. Fortran 注释
28.14.4. Fortran 模式下的自动填充
28.14.5. Fortran 列检查
28.14.6. Fortran 关键字缩写
29. 程序编译与测试
29.1. 在 Emacs 中运行编译
29.2. 编译模式
29.3. 编译用子 shell
29.4. 在 Emacs 中使用 Grep 搜索
29.5. 实时语法错误检测
29.6. 在 Emacs 中运行调试器
29.6.1. 启动 GUD 调试器
29.6.2. 调试器操作
29.6.3. GUD 调试器命令
29.6.4. GUD 调试器定制
29.6.5. GDB 图形界面
29.6.5.1. GDB 图形界面布局
29.6.5.2. 源代码缓冲区
29.6.5.3. 断点缓冲区
29.6.5.4. 线程缓冲区
29.6.5.5. 堆栈缓冲区
29.6.5.6. 其他 GDB 缓冲区
29.6.5.7. 监视表达式
29.6.5.8. 多线程调试
29.7. 执行 Lisp 表达式
29.8. Emacs Lisp 代码库
29.9. 求值 Emacs Lisp 表达式
29.10. Lisp 交互缓冲区
29.11. 运行外部 Lisp 解释器
30. 大型程序维护
30.1. 版本控制
30.1.1. 版本控制简介
30.1.1.1. 理解版本控制解决的问题
30.1.1.2. 支持的版本控制系统
30.1.1.3. 版本控制的核心概念
30.1.1.4. 基于合并与基于锁定的版本控制
30.1.1.5. 基于变更集与基于文件的版本控制
30.1.1.6. 分布式与集中式代码仓库
30.1.1.7. 日志文件类型
30.1.2. 版本控制与模式行
30.1.3. 版本控制下的基本编辑
30.1.3.1. 基于合并的基本版本控制
30.1.3.2. 基于锁定的基本版本控制
30.1.3.3. C-x v v 中的高级控制
30.1.4. 日志条目缓冲区的功能
30.1.5. 为文件注册版本控制
30.1.6. 查看与比较旧版本
30.1.7. 版本控制变更日志
30.1.8. 撤销版本控制操作
30.1.9. 忽略版本控制文件
30.1.10. 版本控制目录模式
30.1.10.1. 版本控制目录缓冲区
30.1.10.2. 版本控制目录命令
30.1.11. 版本控制分支
30.1.11.1. 分支切换
30.1.11.2. 分支间的变更拉取 / 推送
30.1.11.3. 分支合并
30.1.11.4. 新建分支
30.1.12. 版本控制的杂项命令与功能
30.1.12.1. 变更日志与版本控制
30.1.12.2. 删除与重命名版本控制文件
30.1.12.3. 版本标签
30.1.12.4. 插入版本控制头信息
30.1.12.5. 编辑版本控制命令
30.1.12.6. 准备补丁文件
30.1.13. 定制版本控制
30.1.13.1. 通用选项
30.1.13.2. RCS 与 SCCS 相关选项
30.1.13.3. CVS 专用选项
30.2. 项目管理
30.2.1. 作用于文件的项目命令
30.2.2. 作用于缓冲区的项目命令
30.2.3. 项目切换
30.2.4. 项目列表文件管理
30.3. 变更日志
30.3.1. 变更日志命令
30.3.2. 变更日志格式
30.4. 查找标识符引用
30.4.1. 查找标识符
30.4.1.1. 标识符查阅
30.4.1.2. xref 缓冲区中的可用命令
30.4.1.3. 基于标识符的搜索与替换
30.4.1.4. 标识符查询
30.4.2. 标签表
30.4.2.1. 源文件标签语法
30.4.2.2. 创建标签表
30.4.3. 选择标签表
30.5. Emacs 开发环境
30.6. 使用 Emerge 合并文件
30.6.1. Emerge 概述
30.6.2. Emerge 的子模式
30.6.3. 差异状态
30.6.4. 合并命令
30.6.5. 退出 Emerge
30.6.6. 合并两个版本的内容
30.6.7. Emerge 的细节要点
30.7. 漏洞引用
31. 缩写
31.1. 缩写概念
31.2. 定义缩写
31.3. 控制缩写展开
31.4. 缩写建议
31.5. 查看与编辑缩写
31.6. 保存缩写
31.7. 动态缩写展开
31.8. 定制动态缩写
32. 目录编辑器(Dired)
32.1. 进入目录编辑器
32.3. 用目录编辑器删除文件
32.4. 批量标记多个文件
32.5. 在目录编辑器中打开文件
32.6. 目录编辑器中的标记与标记符
32.7. 对文件执行操作
32.8. 目录编辑器中的 Shell 命令
32.9. Shell 命令猜测
32.10. 目录编辑器中的文件名转换
32.11. 目录编辑器中的文件比较
32.12. 目录编辑器中的子目录
32.13. 目录编辑器中的子目录开关
32.14. 在子目录间移动
32.15. 隐藏子目录
32.16. 更新目录编辑器缓冲区
32.17. 目录编辑器与 find 命令
32.18. 编辑目录编辑器缓冲区
32.19. 在目录编辑器中查看图片缩略图
32.20. 目录编辑器的其他功能
33. 日历与日记
33.1. 日历中的移动
33.1.1. 按标准时间长度移动
33.1.2. 星期、月份或年份的起始与结束
33.1.3. 指定日期跳转
33.2. 日历滚动
33.3. 天数计算
33.4. 日历杂项命令
33.5. 编写日历文件
33.6. 节假日显示
33.7. 日出日落时间
33.8. 月相显示
33.9. 与其他日历系统的转换
33.9.1. 支持的日历系统
33.9.2. 转换到其他日历系统
33.9.3. 从其他日历系统转换
33.10. 日记
33.10.1. 日记文件
33.10.2. 显示日记
33.10.3. 日期格式
33.10.4. 添加日记条目的命令
33.10.5. 特殊日记条目
33.10.6. 约会提醒
33.10.7. 日记条目的导入与导出
33.11. 夏令时
33.12. 时间间隔求和
33.13. 日历与日记的高级功能
33.13.1. 定制日历
33.13.2. 定制节假日
33.13.3. 玛雅日历转换
33.13.4. 日期显示格式
33.13.5. 时间显示格式
33.13.6. 定制日记
33.13.7. 使用非公历的日记条目
33.13.8. 日记显示
33.13.9. 高级日记显示
33.13.10. Sexp 条目与高级日记显示
34. 发送邮件
34.1. 邮件缓冲区格式
34.2. 邮件头字段
34.3. 邮件别名
34.4. 邮件命令
34.4.1. 邮件发送
34.4.2. 邮件头编辑
34.4.3. 邮件引用
34.4.4. 邮件杂项功能
34.5. 邮件签名
34.6. 邮件娱乐功能
34.7. 邮件撰写方式
35. 使用 Rmail 阅读邮件
35.1. Rmail 基本概念
35.2. 邮件内滚动
35.3. 邮件间移动
35.4. 删除邮件
35.5. Rmail 文件与收件箱
35.6. 多个 Rmail 文件
35.7. 将邮件复制到外部文件
35.8. 标签
35.9. Rmail 属性
35.10. 发送回复
35.11. 摘要
35.11.1. 生成摘要
35.11.2. 在摘要中编辑
35.12. Rmail 文件排序
35.13. 邮件显示
35.14. Rmail 与编码系统
35.15. 邮件内编辑
35.16. 邮件摘要
35.17. 阅读 Rot13 加密邮件
35.18. movemail 程序
35.19. 从远程邮箱获取邮件
35.20. 从多种格式的本地邮箱获取邮件
36. 使用 Gnus 处理电子邮件与新闻组
36.1. Gnus 缓冲区
36.2. Gnus 启动流程
36.3. 使用 Gnus 组缓冲区
36.4. 使用 Gnus 摘要缓冲区
37. 主机安全
38. 网络安全
39. 文档查看
39.2. 文档查看器搜索
39.3. 文档查看器切片功能
39.4. 文档查看器格式转换
40. 从 Emacs 运行 Shell 命令
40.1. 单个 Shell 命令
40.2. 交互式子 shell
40.3. Shell 模式
40.4. Shell 提示符
40.5. Shell 命令历史
40.5.1. Shell 历史环
40.5.2. Shell 历史复制
40.5.3. Shell 历史引用
40.6. 目录跟踪
40.7. Shell 模式选项
40.8. Emacs 终端模拟器
40.9. 终端模式
40.10. 远程主机 Shell
40.11. 串行终端
41. 将 Emacs 用作服务器
41.1. TCP Emacs 服务器
41.2. 调用 emacsclient
41.3. emacsclient 选项
42. 打印硬拷贝
42.1. PostScript 硬拷贝
42.2. PostScript 硬拷贝相关变量
42.3. 打印软件包
43. 文本排序
44. 图片编辑
44.1. 图片模式基本编辑
44.2. 插入后移动控制
44.3. 图片模式制表符
44.4. 图片模式矩形命令
45. 二进制文件编辑
46. 保存 Emacs 会话
47. 递归编辑层级
48. 超链接与网页导航功能
48.1. 使用 EWW 网页浏览
48.2. 嵌入式 WebKit 组件
48.3. 跟随 URL 链接
48.4. 激活 URL 链接
48.5. 查找光标位置的文件与 URL
49. 游戏与其他娱乐功能
50. Emacs Lisp 软件包
50.1. 软件包菜单缓冲区
50.2. 软件包状态
50.3. 软件包安装
50.4. 软件包文件与目录结构
50.5. 获取软件包源
50.5.1. 指定软件包源
51. 定制
51.1. 简易定制界面
51.1.1. 定制组
51.1.2. 浏览与搜索设置
51.1.3. 修改变量
51.1.4. 保存定制
51.1.5. 定制外观样式
51.1.6. 定制特定项目
51.1.7. 定制主题
51.1.8. 创建定制主题
51.2. 变量
51.2.1. 查看与设置变量
51.2.2. 钩子
51.2.3. 局部变量
51.2.4. 文件中的局部变量
51.2.4.1. 指定文件变量
51.2.4.2. 文件变量的安全性
51.2.5. 目录级局部变量
51.2.5.1. 通过 EditorConfig 设置目录级变量
51.2.6. 连接级局部变量
51.3. 定制键绑定
51.3.1. 键映射
51.3.2. 前缀键映射
51.3.3. 局部键映射
51.3.4. 迷你缓冲区键映射
51.3.5. 交互式修改键绑定
51.3.6. 在初始化文件中重新绑定键
51.3.7. 修饰键
51.3.8. 重新绑定功能键
51.3.9. 命名 ASCII 控制字符
51.3.10. 重新绑定鼠标按钮
51.3.11. 禁用命令
51.4. Emacs 初始化文件
51.4.1. 初始化文件语法
51.4.2. 初始化文件示例
51.4.3. 终端专用初始化
51.4.4. Emacs 查找初始化文件的方式
51.4.5. 初始化文件中的非 ASCII 字符
51.4.6. 早期初始化文件
51.5. 保存持久化认证信息
52. 退出与中止
53. 处理 Emacs 故障
53.1. 递归编辑层级
53.2. 屏幕乱码
53.3. 文本乱码
53.4. 内存不足
53.5. Emacs 崩溃时
53.6. 崩溃后的恢复
53.7. 紧急退出
53.8. 退格键无法删除时
54. 报告漏洞
54.1. 查看现有漏洞报告与已知问题
54.2. 漏洞的判定标准
54.3. 理解漏洞报告
54.4. 漏洞报告检查清单
54.5. 提交 GNU Emacs 补丁
55. 为 Emacs 开发做贡献
55.1. 编码标准
55.2. 版权转让
56. 如何获取 GNU Emacs 相关帮助
附录 A GNU 通用公共许可证
附录 B GNU 自由文档许可证
附录 C Emacs 启动命令行参数
C.1 操作参数
C.2 初始选项
C.3 命令参数示例
C.4 环境变量
C.4.1 通用变量
C.4.2 杂项变量
C.4.3 MS-Windows 系统注册表
C.5 指定显示名称
C.6 字体指定选项
C.7 窗口颜色选项
C.8 窗口大小与位置选项
C.9 内部边框与外部边框
C.10 框架标题
C.11 图标
C.12 其他显示选项
附录 D X 窗口系统选项与资源
D.1 X 资源
D.2 Emacs 的 X 资源表
D.3 Lucid 菜单与对话框 X 资源
D.4 Motif 菜单 X 资源
D.5 GTK+ 资源
D.5.1 GTK+ 资源基础
D.5.2 GTK+ 组件名称
D.5.3 Emacs 中的 GTK+ 组件名称
D.5.4 GTK+ 样式
附录 E Emacs 29 版本反向更新说明
附录 F Emacs 与 macOS / GNUstep
F.1 macOS 与 GNUstep 下的 Emacs 基本使用
F.1.1 获取环境变量
F.2 Mac / GNUstep 定制
F.2.1 修饰键
F.2.2 框架变量
F.2.3 macOS 触控板 / 鼠标滚轮变量
F.3 macOS / GNUstep 下的窗口系统事件
F.4 GNUstep 支持
附录 G Emacs 与 Haiku 系统
G.1 Haiku 系统下的安装与启动
G.2 Haiku 系统下的字体后端与选择
附录 H Emacs 与 Android 系统
H.1 Android 版本历史
H.2 在 Android 上启动 Emacs
H.3 Emacs 在 Android 上可访问的文件
H.4 在 Android 上从其他程序访问文件
H.5 在 Android 下运行 Emacs
H.6 Android 窗口系统
H.7 Android 下的字体后端与选择
H.8 Android 启动问题排查
H.9 在 Android 上安装额外软件
附录 I Emacs 与 Microsoft Windows/MS-DOS
I.1 在 MS-Windows 上启动 Emacs 的方法
I.2 文本文件与二进制文件
I.3 MS-Windows 上的文件名
I.4 MS-Windows 上的 ls 命令模拟
I.5 MS-Windows 上的 HOME 目录与启动目录
I.6 MS-Windows 上的键盘使用
I.7 MS-Windows 上的鼠标使用
I.8 Windows 9X/ME 与 Windows NT/2K/XP/Vista/7/8/10 上的子进程
I.9 MS-Windows 上的打印功能
I.10 MS-Windows 上的字体指定
I.11 其他 Windows 专用功能
I.12 Emacs 与 MS-DOS
I.12.1 MS-DOS 上的键盘使用
I.12.2 MS-DOS 上的鼠标使用
I.12.3 MS-DOS 上的显示
I.12.4 MS-DOS 上的文件名
I.12.5 MS-DOS 上的打印功能
I.12.6 MS-DOS 上的国际语言支持
I.12.7 MS-DOS 上的子进程
GNU 宣言
什么是 GNU?GNU 不是 Unix!
我为何必须编写 GNU
为何 GNU 要与 Unix 兼容
GNU 的获取方式
为何众多程序员愿意提供帮助
你如何能做出贡献
为何所有计算机用户都将受益
对 GNU 目标的一些易反驳的反对意见
术语表
致谢
按键(字符)索引
命令行选项索引
命令与函数索引
变量索引
概念索引
脚注
Footnotes:
本手册本身受《GNU 自由文档许可证》保护。该许可证的理念与《通用公共许可证》相近,但更适用于文档类作品。参见《GNU 自由文档许可证》章节。
“point(光标位置)” 这一术语源于字符 . ,该字符曾是 TECO 语言(初代 Emacs 的开发语言)中用于定位编辑位置的命令。
出于历史原因,我们将 Alt 键称为 Meta 键。
在 site-start.el 文件中设置 inhibit-startup-screen 是无效的,因为启动界面的初始化流程,早于 site-start.el 文件的读取时间。关于 site-start.el 的更多信息,参见《Emacs 初始化文件》章节。
ASCII 编码中并无 C-SPC 字符;在文本终端中,按下 C-SPC 通常会输入 C-@ 字符。该按键同样绑定了 set-mark-command 命令,因此除非你的文本终端行为特殊,否则可直接将 C-@ 视作 C-SPC 使用。
除 C-/ 外,撤销命令还绑定至 C-x u ,因该快捷键对初学者而言更易记忆:字母 u 对应英文 “undo(撤销)”;同时也绑定至 C-_ ,原因是在部分文本终端中,按下 C-/ 实际输入的是 C-_ 。
若你的文件系统不支持符号链接,Emacs 会改用普通文件实现文件锁定。
在 Nextstep 系统中,由工具包创建的工具提示,其前景色和背景色也可通过设置 tooltip-frame-parameters 中包含的前景、背景框架参数进行自定义。
该行尾规范也被多用途互联网邮件扩展(MIME)的 'text/*' 类型正文及其他网络传输场景采用,与标准通用标记语言(SGML)参考语法中的记录开始 / 记录结束格式不同,Emacs 不直接支持后者。
若你在 X 窗口系统中运行 Emacs,可能需要通过以下命令告知 X 服务器新安装字体的存放路径:
xset fp+ /usr/local/share/emacs/fonts xset fp rehash
更具体地说,是所有从prog-mode派生的模式(参见《Emacs Lisp 参考手册》中的「派生模式」章节)。